diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..170a0fe --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +.bowerrc text eol=lf +.jshintignore text eol=lf +AUTHORS text eol=lf +LICENSE text eol=lf +.csslintrc text eol=lf +*.less text eol=lf +*.html text eol=lf +*.js text eol=lf +*.json text eol=lf +*.css text eol=lf +*.jsx text eol=lf +.gitignore text eol=lf +.gitattributes text eol=lf +.gitmodules text eol=lf +.jshintrc text eol=lf +*.md text eol=lf +*.rst text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index d3060e7..be16b69 100644 --- a/.gitignore +++ b/.gitignore @@ -26,9 +26,11 @@ node_modules .DS_Store -vendor/ +vendor/bower_components .idea # Generated chrome extension public/ +web-ext-artifacts/ +.web-extension-id diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/assets/js/components/MainList.jsx b/assets/js/components/MainList.jsx index 537c122..c01b3c5 100644 --- a/assets/js/components/MainList.jsx +++ b/assets/js/components/MainList.jsx @@ -1,16 +1,16 @@ -/* global chrome */ +/* global browser */ var React = require('react'); var MainList = React.createClass({ _openOptionsPage: function() { - if (chrome.runtime.openOptionsPage) { + if (browser.runtime.openOptionsPage) { // New way to open options pages, if supported (Chrome 42+). - chrome.runtime.openOptionsPage(); + browser.runtime.openOptionsPage(); } else { // Reasonable fallback. - window.open(chrome.runtime.getURL('options.html')); + window.open(browser.runtime.getURL('options.html')); } }, diff --git a/assets/js/components/Options.jsx b/assets/js/components/Options.jsx index 2ab63ac..dec8dab 100644 --- a/assets/js/components/Options.jsx +++ b/assets/js/components/Options.jsx @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ var React = require('react'); var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); @@ -37,13 +37,13 @@ var Options = React.createClass({ restoreSettings: function () { var that = this; - chrome.storage.sync.get({ + browser.storage.sync.get({ theme: config.theme, blacklist: '', whitelist: '', loggingType: config.loggingType, loggingStyle: config.loggingStyle - }, function (items) { + }).then(function (items) { that.setState({ theme: items.theme, blacklist: items.blacklist, @@ -75,13 +75,13 @@ var Options = React.createClass({ var whitelist = that.state.whitelist.trim(); // Sync options with google storage. - chrome.storage.sync.set({ + browser.storage.sync.set({ theme: theme, blacklist: blacklist, whitelist: whitelist, loggingType: loggingType, loggingStyle: loggingStyle - }, function () { + }).then(function () { // Set state to be newly entered values. that.setState({ theme: theme, diff --git a/assets/js/components/WakaTime.jsx b/assets/js/components/WakaTime.jsx index b505e46..1cbaf32 100644 --- a/assets/js/components/WakaTime.jsx +++ b/assets/js/components/WakaTime.jsx @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ var React = require("react"); var $ = require('jquery'); @@ -40,9 +40,9 @@ var Wakatime = React.createClass({ if (data !== false) { - chrome.storage.sync.get({ + browser.storage.sync.get({ loggingEnabled: config.loggingEnabled - }, function(items) { + }).then(function(items) { that.setState({loggingEnabled: items.loggingEnabled}); if (items.loggingEnabled === true) { @@ -129,7 +129,7 @@ var Wakatime = React.createClass({ changeExtensionState('notLogging'); - chrome.storage.sync.set({ + browser.storage.sync.set({ loggingEnabled: false }); }, @@ -141,7 +141,7 @@ var Wakatime = React.createClass({ changeExtensionState('allGood'); - chrome.storage.sync.set({ + browser.storage.sync.set({ loggingEnabled: true }); }, diff --git a/assets/js/config.js b/assets/js/config.js index 7b336a2..4b4a169 100644 --- a/assets/js/config.js +++ b/assets/js/config.js @@ -1,11 +1,11 @@ -/* global chrome */ +/* global browser */ //jshint esnext:true var config = { // Extension name name: 'WakaTime', // Extension version - version: chrome.app.getDetails().version, + version: browser.runtime.getManifest().version, // Time for idle state of the browser // The user is considered idle if there was // no activity in the browser for x seconds diff --git a/assets/js/core/WakaTimeCore.js b/assets/js/core/WakaTimeCore.js index f7a11bc..8445e7a 100644 --- a/assets/js/core/WakaTimeCore.js +++ b/assets/js/core/WakaTimeCore.js @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ //jshint esnext:true var $ = require('jquery'); @@ -77,19 +77,19 @@ class WakaTimeCore { * and sends it to WakaTime for logging. */ recordHeartbeat() { - chrome.storage.sync.get({ + browser.storage.sync.get({ loggingEnabled: config.loggingEnabled, loggingStyle: config.loggingStyle, blacklist: '', whitelist: '' - }, (items) => { + }).then((items) => { if (items.loggingEnabled === true) { changeExtensionState('allGood'); - chrome.idle.queryState(config.detectionIntervalInSeconds, (newState) => { + browser.idle.queryState(config.detectionIntervalInSeconds).then((newState) => { if (newState === 'active') { // Get current tab URL. - chrome.tabs.query({active: true}, (tabs) => { + browser.tabs.query({active: true}).then((tabs) => { var currentActiveTab = tabs[0]; var debug = false; @@ -193,7 +193,7 @@ class WakaTimeCore { time: moment().format('X'), project: heartbeat.project || '<>', is_debugging: debug, - plugin: 'chrome-wakatime/' + config.version + plugin: 'browser-wakatime/' + config.version }); } @@ -207,9 +207,9 @@ class WakaTimeCore { _getLoggingType() { var deferredObject = $.Deferred(); - chrome.storage.sync.get({ + browser.storage.sync.get({ loggingType: config.loggingType - }, function (items) { + }).then(function (items) { deferredObject.resolve(items.loggingType); }); @@ -284,4 +284,4 @@ class WakaTimeCore { } -export default WakaTimeCore; +//export default WakaTimeCore; diff --git a/assets/js/devtools.js b/assets/js/devtools.js index 3638189..eb1bb12 100644 --- a/assets/js/devtools.js +++ b/assets/js/devtools.js @@ -1,12 +1,12 @@ -/* global chrome */ +/* global browser */ // Create a connection to the background page -var backgroundPageConnection = chrome.runtime.connect({ +var backgroundPageConnection = browser.runtime.connect({ name: "devtools-page" }); // Send a message to background page with the current active tabId backgroundPageConnection.postMessage({ name: 'init', - tabId: chrome.devtools.inspectedWindow.tabId + tabId: browser.devtools.inspectedWindow.tabId }); diff --git a/assets/js/events.js b/assets/js/events.js index 144ce83..f500308 100644 --- a/assets/js/events.js +++ b/assets/js/events.js @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ // Core var WakaTimeCore = require("./core/WakaTimeCore").default; @@ -11,7 +11,7 @@ var wakatime = new WakaTimeCore(); var connections = {}; // Add a listener to resolve alarms -chrome.alarms.onAlarm.addListener(function (alarm) { +browser.alarms.onAlarm.addListener(function (alarm) { // |alarm| can be undefined because onAlarm also gets called from // window.setTimeout on old chrome versions. if (alarm && alarm.name == 'heartbeatAlarm') { @@ -23,14 +23,14 @@ chrome.alarms.onAlarm.addListener(function (alarm) { }); // Create a new alarm for heartbeats. -chrome.alarms.create('heartbeatAlarm', {periodInMinutes: 2}); +browser.alarms.create('heartbeatAlarm', {periodInMinutes: 2}); /** * Whenever a active tab is changed it records a heartbeat with that tab url. */ -chrome.tabs.onActivated.addListener(function (activeInfo) { +browser.tabs.onActivated.addListener(function (activeInfo) { - chrome.tabs.get(activeInfo.tabId, function (tab) { + browser.tabs.get(activeInfo.tabId).then(function (tab) { console.log('recording a heartbeat - active tab changed'); @@ -43,11 +43,11 @@ chrome.tabs.onActivated.addListener(function (activeInfo) { * Whenever any tab is updated it checks if the updated tab is the tab that is * currently active and if it is, then it records a heartbeat. */ -chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { +browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { if (changeInfo.status === 'complete') { // Get current tab URL. - chrome.tabs.query({active: true}, function(tabs) { + browser.tabs.query({active: true}).then(function(tabs) { // If tab updated is the same as active tab if (tabId == tabs[0].id) { console.log('recording a heartbeat - tab updated'); @@ -64,7 +64,7 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { * This is in charge of detecting if devtools are opened or closed * and sending a heartbeat depending on that. */ -chrome.runtime.onConnect.addListener(function (port) { +browser.runtime.onConnect.addListener(function (port) { if (port.name == "devtools-page") { diff --git a/assets/js/helpers/changeExtensionIcon.js b/assets/js/helpers/changeExtensionIcon.js index 7f7cdf9..0a08176 100644 --- a/assets/js/helpers/changeExtensionIcon.js +++ b/assets/js/helpers/changeExtensionIcon.js @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ var config = require('../config'); @@ -19,26 +19,26 @@ function changeExtensionIcon(color) { path = './graphics/wakatime-logo-38' + color + '.png'; - chrome.browserAction.setIcon({ + browser.browserAction.setIcon({ path: path }); } if (color === '') { - chrome.storage.sync.get({ + browser.storage.sync.get({ theme: config.theme - }, function (items) { + }).then(function (items) { if (items.theme == config.theme) { path = './graphics/wakatime-logo-38.png'; - chrome.browserAction.setIcon({ + browser.browserAction.setIcon({ path: path }); } else { path = './graphics/wakatime-logo-38-white.png'; - chrome.browserAction.setIcon({ + browser.browserAction.setIcon({ path: path }); } diff --git a/assets/js/helpers/changeExtensionTooltip.js b/assets/js/helpers/changeExtensionTooltip.js index ac6620d..d230b67 100644 --- a/assets/js/helpers/changeExtensionTooltip.js +++ b/assets/js/helpers/changeExtensionTooltip.js @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ var config = require('../config'); @@ -16,7 +16,7 @@ function changeExtensionTooltip(text) { text = config.name + ' - ' + text; } - chrome.browserAction.setTitle({title: text}); + browser.browserAction.setTitle({title: text}); } module.exports = changeExtensionTooltip; \ No newline at end of file diff --git a/assets/js/options.jsx b/assets/js/options.jsx index e171c53..b7f21ec 100644 --- a/assets/js/options.jsx +++ b/assets/js/options.jsx @@ -1,4 +1,4 @@ -/* global chrome */ +/* global browser */ /* This is a fix for Bootstrap requiring jQuery */ global.jQuery = require('jquery'); diff --git a/assets/less/bootstrap/bootstrap.less b/assets/less/bootstrap/bootstrap.less index 1c04778..f0aa08f 100644 --- a/assets/less/bootstrap/bootstrap.less +++ b/assets/less/bootstrap/bootstrap.less @@ -1,6 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ diff --git a/assets/less/bootstrap/button-groups.less b/assets/less/bootstrap/button-groups.less index 293245a..16db0c6 100644 --- a/assets/less/bootstrap/button-groups.less +++ b/assets/less/bootstrap/button-groups.less @@ -59,7 +59,7 @@ .border-right-radius(0); } } -// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it .btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { .border-left-radius(0); diff --git a/assets/less/bootstrap/forms.less b/assets/less/bootstrap/forms.less index e8b071a..9377d38 100644 --- a/assets/less/bootstrap/forms.less +++ b/assets/less/bootstrap/forms.less @@ -181,7 +181,7 @@ input[type="search"] { // set a pixel line-height that matches the given height of the input, but only // for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848 // -// Note that as of 8.3, iOS doesn't support `datetime` or `week`. +// Note that as of 9.3, iOS doesn't support `week`. @media screen and (-webkit-min-device-pixel-ratio: 0) { input[type="date"], diff --git a/assets/less/bootstrap/input-groups.less b/assets/less/bootstrap/input-groups.less index 5f73eec..d0763db 100644 --- a/assets/less/bootstrap/input-groups.less +++ b/assets/less/bootstrap/input-groups.less @@ -29,7 +29,7 @@ width: 100%; margin-bottom: 0; - + &:focus { z-index: 3; } diff --git a/assets/less/bootstrap/mixins/tab-focus.less b/assets/less/bootstrap/mixins/tab-focus.less index 1f1f05a..d12d236 100644 --- a/assets/less/bootstrap/mixins/tab-focus.less +++ b/assets/less/bootstrap/mixins/tab-focus.less @@ -1,9 +1,9 @@ // WebKit-style focus .tab-focus() { - // Default - outline: thin dotted; - // WebKit + // WebKit-specific. Other browsers will keep their default outline style. + // (Initially tried to also force default via `outline: initial`, + // but that seems to erroneously remove the outline in Firefox altogether.) outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } diff --git a/assets/less/bootstrap/panels.less b/assets/less/bootstrap/panels.less index 425eb5e..65aa3a8 100644 --- a/assets/less/bootstrap/panels.less +++ b/assets/less/bootstrap/panels.less @@ -214,7 +214,7 @@ } -// Collapsable panels (aka, accordion) +// Collapsible panels (aka, accordion) // // Wrap a series of panels in `.panel-group` to turn them into an accordion with // the help of our collapse JavaScript plugin. diff --git a/assets/less/bootstrap/scaffolding.less b/assets/less/bootstrap/scaffolding.less index 1929bfc..64a29c6 100644 --- a/assets/less/bootstrap/scaffolding.less +++ b/assets/less/bootstrap/scaffolding.less @@ -120,7 +120,7 @@ hr { // Only display content to screen readers // -// See: http://a11yproject.com/posts/how-to-hide-content/ +// See: http://a11yproject.com/posts/how-to-hide-content .sr-only { position: absolute; diff --git a/assets/less/bootstrap/theme.less b/assets/less/bootstrap/theme.less index 8f51d91..fb61744 100644 --- a/assets/less/bootstrap/theme.less +++ b/assets/less/bootstrap/theme.less @@ -1,6 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ diff --git a/assets/less/bootstrap/variables.less b/assets/less/bootstrap/variables.less index b057ef5..03b5498 100644 --- a/assets/less/bootstrap/variables.less +++ b/assets/less/bootstrap/variables.less @@ -111,7 +111,7 @@ //** Global background color for active items (e.g., navs or dropdowns). @component-active-bg: @brand-primary; -//** Width of the `border` for generating carets that indicator dropdowns. +//** Width of the `border` for generating carets that indicate dropdowns. @caret-width-base: 4px; //** Carets increase slightly in size for larger components. @caret-width-large: 5px; diff --git a/gulpfile.js b/gulpfile.js index 510d4c6..05a2879 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,6 +1,8 @@ var del = require('del'); var gulp = require('gulp'); var elixir = require('laravel-elixir'); +var exec = require('child_process').exec; +var fs = require('fs'); /* |-------------------------------------------------------------------------- @@ -16,6 +18,15 @@ gulp.task('postinstall', function (cb) { //so we remove them on postinstall del('node_modules/**/*.pem', cb); }); +gulp.task('webextension',function(cb){ + exec('npm install',{ + cwd: 'node_modules/webextension-polyfill/' + },function(){ + var stream = fs.createWriteStream('public/js/browser-polyfill.min.js'); + stream.on('done',cb); + fs.createReadStream('node_modules/webextension-polyfill/dist/browser-polyfill.min.js').pipe(stream); + }); +}); /* |-------------------------------------------------------------------------- @@ -30,14 +41,19 @@ gulp.task('postinstall', function (cb) { elixir.config.assetsPath = 'assets/'; +elixir.extend('webextension', function(){ + return gulp.start('webextension'); +}); + elixir(function (mix) { + mix.webextension(); mix.copy('vendor/bower_components/bootstrap/less', 'assets/less/bootstrap'); - mix.copy('vendor/bower_components/bootstrap/fonts', 'public/fonts'); + /*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.less('app.less'); mix.browserify('app.jsx', 'public/js/app.js', 'assets/js'); mix.browserify('events.js', 'public/js/events.js', 'assets/js'); mix.browserify('options.jsx', 'public/js/options.js', 'assets/js'); - mix.browserify('devtools.js', 'public/js/devtools.js', 'assets/js'); + mix.browserify('devtools.js', 'public/js/devtools.js', 'assets/js');*/ }); diff --git a/manifest.json b/manifest.json index 83cd7fc..cf6d9ee 100644 --- a/manifest.json +++ b/manifest.json @@ -20,6 +20,7 @@ ], "background": { "scripts": [ + "public/js/browser-polyfill.min.js", "public/js/events.js" ], "persistent": false @@ -35,5 +36,10 @@ "options_ui": { "page": "options.html", "chrome_style": false + }, + "applications": { + "gecko": { + "id": "addon@wakatime.com" + } } } diff --git a/package.json b/package.json index 1447f2f..124a5ee 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "moment": "^2.13.0", "react": "^16.2.0", "react-addons-css-transition-group": "^15.1.0", - "react-dom": "^16.2.0" + "react-dom": "^16.2.0", + "webextension-polyfill": "^0.2.1" }, "jshintConfig": { "asi": false, diff --git a/popup.html b/popup.html index 61ddcd7..d6f8133 100644 --- a/popup.html +++ b/popup.html @@ -7,6 +7,7 @@ WakaTime + diff --git a/tests/helpers/changeExtensionIcon.spec.js b/tests/helpers/changeExtensionIcon.spec.js index 98c70be..e91bfe5 100644 --- a/tests/helpers/changeExtensionIcon.spec.js +++ b/tests/helpers/changeExtensionIcon.spec.js @@ -1,7 +1,7 @@ var chai = require('chai'); var expect = chai.expect; -import changeExtensionIcon from '../../assets/js/helpers/changeExtensionIcon'; +//import changeExtensionIcon from '../../assets/js/helpers/changeExtensionIcon'; describe('changeExtensionIcon', function() { it('should be a function', function() { diff --git a/tests/helpers/changeExtensionState.spec.js b/tests/helpers/changeExtensionState.spec.js index 708e661..a5822e2 100644 --- a/tests/helpers/changeExtensionState.spec.js +++ b/tests/helpers/changeExtensionState.spec.js @@ -1,7 +1,7 @@ var chai = require('chai'); var expect = chai.expect; -import changeExtensionState from '../../assets/js/helpers/changeExtensionState'; +//import changeExtensionState from '../../assets/js/helpers/changeExtensionState'; describe('changeExtensionState', function() { it('should be a function', function() { diff --git a/tests/helpers/changeExtensionTooltip.spec.js b/tests/helpers/changeExtensionTooltip.spec.js index c1d53e9..f99b895 100644 --- a/tests/helpers/changeExtensionTooltip.spec.js +++ b/tests/helpers/changeExtensionTooltip.spec.js @@ -3,7 +3,7 @@ var sinon = require('sinon-chai'); var chrome = require('sinon-chrome'); var expect = chai.expect; -import changeExtensionTooltip from '../../assets/js/helpers/changeExtensionTooltip'; +//import changeExtensionTooltip from '../../assets/js/helpers/changeExtensionTooltip'; describe('changeExtensionTooltip', function() { it('should be a function', function() { diff --git a/tests/helpers/contains.spec.js b/tests/helpers/contains.spec.js index c3798e8..c5715a4 100644 --- a/tests/helpers/contains.spec.js +++ b/tests/helpers/contains.spec.js @@ -1,7 +1,7 @@ var chai = require('chai'); var expect = chai.expect; -import contains from '../../assets/js/helpers/contains'; +//import contains from '../../assets/js/helpers/contains'; describe('contains', function() { it('should be a function', function() { diff --git a/tests/helpers/getDomainFromUrl.spec.js b/tests/helpers/getDomainFromUrl.spec.js index a0418bc..78059e0 100644 --- a/tests/helpers/getDomainFromUrl.spec.js +++ b/tests/helpers/getDomainFromUrl.spec.js @@ -1,7 +1,7 @@ var chai = require('chai'); var expect = chai.expect; -import getDomainFromUrl from '../../assets/js/helpers/getDomainFromUrl'; +//import getDomainFromUrl from '../../assets/js/helpers/getDomainFromUrl'; describe('getDomainFromUrl', function() { it('should be a function', function() { diff --git a/tests/helpers/in_array.spec.js b/tests/helpers/in_array.spec.js index 450ca3c..216fa99 100644 --- a/tests/helpers/in_array.spec.js +++ b/tests/helpers/in_array.spec.js @@ -1,7 +1,7 @@ var chai = require('chai'); var expect = chai.expect; -import in_array from '../../assets/js/helpers/in_array'; +//import in_array from '../../assets/js/helpers/in_array'; describe('in_array', function() { it('should be a function', function() {