From 1a2bac7cc3e500276d48281b9349f95fb4d7ee3f Mon Sep 17 00:00:00 2001 From: Mario Basic Date: Sat, 13 Jun 2015 15:53:17 +0200 Subject: [PATCH] Added devtools detection. --- assets/js/WakaTime.js | 26 ++++--- assets/js/devtools.js | 9 +++ assets/js/events.js | 48 +++++++++++-- assets/js/helpers/in_array.js | 12 ++++ bower.json | 3 +- devtools.html | 2 + gulpfile.js | 2 +- manifest.json | 1 + public/js/bundle.js | 90 +++++++++++------------- public/js/devtools.js | 14 ++++ public/js/events.js | 128 ++++++++++++++++++++-------------- 11 files changed, 215 insertions(+), 120 deletions(-) create mode 100644 assets/js/devtools.js create mode 100644 assets/js/helpers/in_array.js create mode 100644 devtools.html create mode 100644 public/js/devtools.js diff --git a/assets/js/WakaTime.js b/assets/js/WakaTime.js index 91e2889..80245dc 100644 --- a/assets/js/WakaTime.js +++ b/assets/js/WakaTime.js @@ -2,10 +2,12 @@ import UrlHelper from './UrlHelper.js'; import $ from 'jquery'; import currentTimestamp from './helpers/currentTimestamp.js'; import changeExtensionIcon from './helpers/changeExtensionIcon.js'; -import devtools from './libs/devtools-detect.js'; +var in_array = require('./helpers/in_array'); class WakaTime { + tabsWithDevtoolsOpen = []; + constructor(props) { this.detectionIntervalInSeconds = 60; //default @@ -14,6 +16,12 @@ class WakaTime { this.heartbeatApiUrl = 'https://wakatime.com/api/v1/users/current/heartbeats'; this.currentUserApiUrl = 'https://wakatime.com/api/v1/users/current'; + + this.tabsWithDevtoolsOpen = []; + } + + setTabsWithDevtoolsOpen(tabs) { + this.tabsWithDevtoolsOpen = tabs; } /** @@ -63,7 +71,11 @@ class WakaTime { if (newState === 'active') { // Get current tab URL. chrome.tabs.query({active: true}, (tabs) => { - this.sendHeartbeat(tabs[0].url); + var debug = false; + // If the current active tab has devtools open + if(in_array(tabs[0].id, this.tabsWithDevtoolsOpen)) debug = true; + + this.sendHeartbeat(tabs[0].url, debug); }); } }); @@ -124,14 +136,12 @@ class WakaTime { * sends an ajax post request to the API. * * @param entity + * @param debug */ - sendHeartbeat(entity) { + sendHeartbeat(entity, debug) { var payload = null; - // TODO: Detect if devTools are open - console.log(devtools.open); - this._getLoggingType().done((loggingType) => { // Get only the domain from the entity. @@ -140,7 +150,7 @@ class WakaTime { var domain = UrlHelper.getDomainFromUrl(entity); - payload = this._preparePayload(domain, 'domain'); + payload = this._preparePayload(domain, 'domain', debug); console.log(payload); @@ -149,7 +159,7 @@ class WakaTime { } // Send entity in heartbeat else if (loggingType == 'url') { - payload = this._preparePayload(entity, 'url'); + payload = this._preparePayload(entity, 'url', debug); console.log(payload); diff --git a/assets/js/devtools.js b/assets/js/devtools.js new file mode 100644 index 0000000..8f6fd9c --- /dev/null +++ b/assets/js/devtools.js @@ -0,0 +1,9 @@ +// Create a connection to the background page +var backgroundPageConnection = chrome.runtime.connect({ + name: "devtools-page" +}); + +backgroundPageConnection.postMessage({ + name: 'init', + tabId: chrome.devtools.inspectedWindow.tabId +}); diff --git a/assets/js/events.js b/assets/js/events.js index 900d87b..ff4fdaf 100644 --- a/assets/js/events.js +++ b/assets/js/events.js @@ -1,5 +1,11 @@ import WakaTime from "./WakaTime.js"; +var wakatime = new WakaTime; + +// Holds currently open connections (ports) with devtools +// Uses tabId as index key. +var connections = {}; + /** * Whenever an alarms sets off, this function * gets called to detect the alarm name and @@ -14,8 +20,6 @@ function resolveAlarm(alarm) { console.log('recording a heartbeat - alarm triggered'); - var wakatime = new WakaTime; - wakatime.recordHeartbeat(); } } @@ -35,8 +39,6 @@ chrome.tabs.onActivated.addListener(function (activeInfo) { console.log('recording a heartbeat - active tab changed'); - var wakatime = new WakaTime; - wakatime.recordHeartbeat(); }); @@ -55,11 +57,45 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { if (tabId == tabs[0].id) { console.log('recording a heartbeat - tab updated'); - var wakatime = new WakaTime; - wakatime.recordHeartbeat(); } }); } }); + + +chrome.runtime.onConnect.addListener(function (port) { + + if (port.name == "devtools-page") { + + // Listen to messages sent from the DevTools page + port.onMessage.addListener(function (message, sender, sendResponse) { + if (message.name == "init") { + + connections[message.tabId] = port; + + wakatime.setTabsWithDevtoolsOpen(Object.keys(connections)); + + wakatime.recordHeartbeat(); + } + }); + + port.onDisconnect.addListener(function (port) { + + var tabs = Object.keys(connections); + + for (var i = 0, len = tabs.length; i < len; i ++) { + if (connections[tabs[i]] == port) { + delete connections[tabs[i]]; + break; + } + } + + wakatime.setTabsWithDevtoolsOpen(Object.keys(connections)); + + wakatime.recordHeartbeat(); + }); + + } +}); \ No newline at end of file diff --git a/assets/js/helpers/in_array.js b/assets/js/helpers/in_array.js new file mode 100644 index 0000000..53d5ac6 --- /dev/null +++ b/assets/js/helpers/in_array.js @@ -0,0 +1,12 @@ +function in_array(needle, haystack) { + for (var i = 0; i < haystack.length; i ++) { + if (needle == haystack[i]) { + return true; + break; + } + } + + return false; +} + +export default in_array; \ No newline at end of file diff --git a/bower.json b/bower.json index 6bf6dd5..38db952 100644 --- a/bower.json +++ b/bower.json @@ -9,7 +9,6 @@ ], "dependencies": { "font-awesome": "~4.3.0", - "bootstrap": "~3.3.4", - "devtools-detect": "~1.0.0" + "bootstrap": "~3.3.4" } } diff --git a/devtools.html b/devtools.html new file mode 100644 index 0000000..0eaf379 --- /dev/null +++ b/devtools.html @@ -0,0 +1,2 @@ + + diff --git a/gulpfile.js b/gulpfile.js index 739f61d..34f9d67 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -18,9 +18,9 @@ elixir(function (mix) { mix.copy('vendor/bower_components/bootstrap/fonts', 'public/fonts'); mix.copy('vendor/bower_components/font-awesome/less', 'assets/less/font-awesome'); mix.copy('vendor/bower_components/font-awesome/fonts', 'public/fonts'); - mix.copy('vendor/bower_components/devtools-detect/devtools-detect.js', 'assets/js/libs/devtools-detect.js'); mix.less('app.less'); mix.browserify('app.js', null, 'assets/js'); mix.browserify('events.js', 'public/js/events.js', 'assets/js'); mix.browserify('options.js', 'public/js/options.js', 'assets/js'); + mix.browserify('devtools.js', 'public/js/devtools.js', 'assets/js'); }); diff --git a/manifest.json b/manifest.json index 06455aa..87aedab 100644 --- a/manifest.json +++ b/manifest.json @@ -3,6 +3,7 @@ "name": "WakaTime", "version": "1.0.0", "description": "Get stats about your website debugging, research, documentation, etc.", + "devtools_page": "devtools.html", "icons": { "16": "graphics/wakatime-logo-16.png", "48": "graphics/wakatime-logo-48.png", diff --git a/public/js/bundle.js b/public/js/bundle.js index c9c1e14..194e2dc 100644 --- a/public/js/bundle.js +++ b/public/js/bundle.js @@ -79,14 +79,14 @@ var _helpersChangeExtensionIconJs = require('./helpers/changeExtensionIcon.js'); var _helpersChangeExtensionIconJs2 = _interopRequireDefault(_helpersChangeExtensionIconJs); -var _libsDevtoolsDetectJs = require('./libs/devtools-detect.js'); - -var _libsDevtoolsDetectJs2 = _interopRequireDefault(_libsDevtoolsDetectJs); +var in_array = require('./helpers/in_array'); var WakaTime = (function () { function WakaTime(props) { _classCallCheck(this, WakaTime); + this.tabsWithDevtoolsOpen = []; + this.detectionIntervalInSeconds = 60; //default this.loggingType = 'domain'; //default @@ -94,9 +94,16 @@ var WakaTime = (function () { this.heartbeatApiUrl = 'https://wakatime.com/api/v1/users/current/heartbeats'; this.currentUserApiUrl = 'https://wakatime.com/api/v1/users/current'; + + this.tabsWithDevtoolsOpen = []; } _createClass(WakaTime, [{ + key: 'setTabsWithDevtoolsOpen', + value: function setTabsWithDevtoolsOpen(tabs) { + this.tabsWithDevtoolsOpen = tabs; + } + }, { key: 'checkAuth', /** @@ -151,7 +158,11 @@ var WakaTime = (function () { if (newState === 'active') { // Get current tab URL. chrome.tabs.query({ active: true }, function (tabs) { - _this2.sendHeartbeat(tabs[0].url); + var debug = false; + // If the current active tab has devtools open + if (in_array(tabs[0].id, _this2.tabsWithDevtoolsOpen)) debug = true; + + _this2.sendHeartbeat(tabs[0].url, debug); }); } }); @@ -217,15 +228,13 @@ var WakaTime = (function () { * sends an ajax post request to the API. * * @param entity + * @param debug */ - value: function sendHeartbeat(entity) { + value: function sendHeartbeat(entity, debug) { var _this3 = this; var payload = null; - // TODO: Detect if devTools are open - console.log(_libsDevtoolsDetectJs2['default'].open); - this._getLoggingType().done(function (loggingType) { // Get only the domain from the entity. @@ -234,7 +243,7 @@ var WakaTime = (function () { var domain = _UrlHelperJs2['default'].getDomainFromUrl(entity); - payload = _this3._preparePayload(domain, 'domain'); + payload = _this3._preparePayload(domain, 'domain', debug); console.log(payload); @@ -242,7 +251,7 @@ var WakaTime = (function () { } // Send entity in heartbeat else if (loggingType == 'url') { - payload = _this3._preparePayload(entity, 'url'); + payload = _this3._preparePayload(entity, 'url', debug); console.log(payload); @@ -295,7 +304,9 @@ var WakaTime = (function () { exports['default'] = WakaTime; module.exports = exports['default']; -},{"./UrlHelper.js":2,"./helpers/changeExtensionIcon.js":7,"./helpers/currentTimestamp.js":8,"./libs/devtools-detect.js":9,"jquery":23}],4:[function(require,module,exports){ +},{"./UrlHelper.js":2,"./helpers/changeExtensionIcon.js":7,"./helpers/currentTimestamp.js":8,"./helpers/in_array":9,"jquery":23}],4:[function(require,module,exports){ +//jshint esnext:true + 'use strict'; Object.defineProperty(exports, '__esModule', { @@ -488,6 +499,8 @@ exports['default'] = MainList; module.exports = exports['default']; },{"react":179}],5:[function(require,module,exports){ +//jshint esnext:true + "use strict"; Object.defineProperty(exports, "__esModule", { @@ -601,6 +614,8 @@ exports["default"] = Navbar; module.exports = exports["default"]; },{"react":179}],6:[function(require,module,exports){ +//jshint esnext:true + 'use strict'; Object.defineProperty(exports, '__esModule', { @@ -868,47 +883,24 @@ exports["default"] = function () { module.exports = exports["default"]; },{}],9:[function(require,module,exports){ -/*! - devtools-detect - Detect if DevTools is open - https://github.com/sindresorhus/devtools-detect - by Sindre Sorhus - MIT License -*/ -'use strict'; +"use strict"; -(function () { - 'use strict'; - var devtools = { open: false }; - var threshold = 160; - var emitEvent = function emitEvent(state) { - window.dispatchEvent(new CustomEvent('devtoolschange', { - detail: { - open: state - } - })); - }; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function in_array(needle, haystack) { + for (var i = 0; i < haystack.length; i++) { + if (needle == haystack[i]) { + return true; + break; + } + } - setInterval(function () { - if (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized || window.outerWidth - window.innerWidth > threshold || window.outerHeight - window.innerHeight > threshold) { - if (!devtools.open) { - emitEvent(true); - } - devtools.open = true; - } else { - if (devtools.open) { - emitEvent(false); - } - devtools.open = false; - } - }, 500); + return false; +} - if (typeof module !== 'undefined' && module.exports) { - module.exports = devtools; - } else { - window.devtools = devtools; - } -})(); +exports["default"] = in_array; +module.exports = exports["default"]; },{}],10:[function(require,module,exports){ // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. diff --git a/public/js/devtools.js b/public/js/devtools.js new file mode 100644 index 0000000..81917a8 --- /dev/null +++ b/public/js/devtools.js @@ -0,0 +1,14 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o threshold || window.outerHeight - window.innerHeight > threshold) { - if (!devtools.open) { - emitEvent(true); - } - devtools.open = true; - } else { - if (devtools.open) { - emitEvent(false); - } - devtools.open = false; - } - }, 500); + return false; +} - if (typeof module !== 'undefined' && module.exports) { - module.exports = devtools; - } else { - window.devtools = devtools; - } -})(); +exports["default"] = in_array; +module.exports = exports["default"]; },{}],7:[function(require,module,exports){ /*!