diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7fb3a9e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +assets +public diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..319ce81 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,26 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: test + +on: + push: + branches: [master] + pull_request: + branches: [master] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your ob can access it + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 11.15.0 + - run: npm ci + - run: npm test diff --git a/.jshintrc b/.jshintrc index 11886c7..2c22b3b 100644 --- a/.jshintrc +++ b/.jshintrc @@ -6,5 +6,5 @@ "undef": true, "unused": true, "trailing": true, - "predef": [ "chrome" ] + "predef": ["chrome"] } diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ddbd0bd --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +coverage +public +vendor \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..3c0f46c --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,5 @@ +module.exports = { + printWidth: 100, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..04e4412 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,6 @@ +## Pre-requisites + +- node v11.15.0 +- npm 6.7.0 + +It is suggested you use [nvm](https://github.com/nvm-sh/nvm) to manage your node version diff --git a/README.md b/README.md index 8ea4cb8..f136426 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ -chrome-wakatime -=============== +# chrome-wakatime Automatic time tracking for stats about your website debugging, research, documentation, etc. Note: Activity from this Chrome extension will not display on leaderboards, so installing this extension may lower your rank. - ## Installation 1. Install the extension: @@ -20,7 +18,6 @@ Note: Activity from this Chrome extension will not display on leaderboards, so i 5. Use in conjunction with [other WakaTime plugins](https://wakatime.com/plugins). - ## Screenshots ![SC open](./screenshots/sc_6-green.png) @@ -29,12 +26,12 @@ Note: Activity from this Chrome extension will not display on leaderboards, so i ![Options SC](./screenshots/sc_8-options.png) - ## Development instructions > For development purposes only. To get started, install NPM and Bower dependencies, and do an initial build with Gulp: + ``` npm start ``` @@ -57,7 +54,7 @@ Run tests: npm test ``` -Lint code *(Both JS and JSX)*: +Lint code _(Both JS and JSX)_: ``` jsxhint --jsx-only . @@ -67,16 +64,14 @@ jsxhint --jsx-only . There is a precommit hook that lints the code before commiting the changes. - ### Load unpacked in Chrome 1. Clone repository to disk 2. Remove `browser_specific_settings` key from manifest.json (only necessary for firefox) -2. Go to `Settings` → `Extensions` -3. Enable `Developer mode` -4. Click `Load unpacked extension...` -5. Select repository directory - +3. Go to `Settings` → `Extensions` +4. Enable `Developer mode` +5. Click `Load unpacked extension...` +6. Select repository directory ### Troubleshooting diff --git a/assets/js/app.jsx b/assets/js/app.jsx index 0797c4d..6da1c43 100644 --- a/assets/js/app.jsx +++ b/assets/js/app.jsx @@ -1,4 +1,3 @@ - /* This is a fix for Bootstrap requiring jQuery */ global.jQuery = require('jquery'); require('bootstrap'); @@ -9,7 +8,4 @@ var ReactDOM = require('react-dom'); // React components var WakaTime = require('./components/WakaTime.jsx'); -ReactDOM.render( - , - document.getElementById('wakatime') -); +ReactDOM.render(, document.getElementById('wakatime')); diff --git a/assets/js/components/Alert.jsx b/assets/js/components/Alert.jsx index 3252f3d..04e121f 100644 --- a/assets/js/components/Alert.jsx +++ b/assets/js/components/Alert.jsx @@ -3,13 +3,9 @@ var reactCreateClass = require('create-react-class'); var classNames = require('classnames'); var Alert = reactCreateClass({ - - render: function() { - return( -
{this.props.text}
- ); - } - + render: function () { + return
{this.props.text}
; + }, }); module.exports = Alert; diff --git a/assets/js/components/MainList.jsx b/assets/js/components/MainList.jsx index e1bb27c..7098203 100644 --- a/assets/js/components/MainList.jsx +++ b/assets/js/components/MainList.jsx @@ -2,106 +2,111 @@ var React = require('react'); var reactCreateClass = require('create-react-class'); - var MainList = reactCreateClass({ - - _openOptionsPage: function() { - if (browser.runtime.openOptionsPage) { - // New way to open options pages, if supported (Chrome 42+). - browser.runtime.openOptionsPage(); - } else { - // Reasonable fallback. - window.open(browser.runtime.getURL('options.html')); - } - }, - - render: function() { - - var that = this; - - var loginLogoutButton = function() { - if (that.props.loggedIn === true) { - return ( -
- - - Logout - -
- ); - } - - return ( - - - Login - - ); - }; - - // If logging is enabled, display that info to user - var loggingStatus = function() { - if(that.props.loggingEnabled === true && that.props.loggedIn === true) - { - return ( -
-
-

- Disable logging -

-
-
- ); - } - else if(that.props.loggingEnabled === false && that.props.loggedIn === true) - { - return ( -
-
-

- Enable logging -

-
-
- ); - } - }; - - var totalTimeLoggedToday = function() { - if (that.props.loggedIn === true) { - return ( -
-
-
-

{that.props.totalTimeLoggedToday}

- TOTAL TIME LOGGED TODAY -
-
-
- ); - } - }; - - return ( -
- - {totalTimeLoggedToday()} - - {loggingStatus()} - -
- - - Options - - - {loginLogoutButton()} - -
-
- ); + _openOptionsPage: function () { + if (browser.runtime.openOptionsPage) { + // New way to open options pages, if supported (Chrome 42+). + browser.runtime.openOptionsPage(); + } else { + // Reasonable fallback. + window.open(browser.runtime.getURL('options.html')); } + }, + render: function () { + var that = this; + + var loginLogoutButton = function () { + if (that.props.loggedIn === true) { + return ( +
+ + + Logout + +
+ ); + } + + return ( + + + Login + + ); + }; + + // If logging is enabled, display that info to user + var loggingStatus = function () { + if (that.props.loggingEnabled === true && that.props.loggedIn === true) { + return ( +
+
+

+ + Disable logging + +

+
+
+ ); + } else if (that.props.loggingEnabled === false && that.props.loggedIn === true) { + return ( +
+
+

+ + Enable logging + +

+
+
+ ); + } + }; + + var totalTimeLoggedToday = function () { + if (that.props.loggedIn === true) { + return ( +
+
+
+

{that.props.totalTimeLoggedToday}

+ + TOTAL TIME LOGGED TODAY + +
+
+
+ ); + } + }; + + return ( +
+ {totalTimeLoggedToday()} + + {loggingStatus()} + +
+ + + Options + + + {loginLogoutButton()} +
+
+ ); + }, }); module.exports = MainList; diff --git a/assets/js/components/NavBar.jsx b/assets/js/components/NavBar.jsx index e10562e..790a173 100644 --- a/assets/js/components/NavBar.jsx +++ b/assets/js/components/NavBar.jsx @@ -2,89 +2,101 @@ var React = require('react'); var reactCreateClass = require('create-react-class'); var NavBar = reactCreateClass({ + render: function () { + var that = this; - render: function() { - - var that = this; - - var signedInAs = function() { - if (that.props.loggedIn === true) { - return ( -

Signed in as {that.props.user.full_name}

- ); - } - }; - - var dashboard = function() { - if (that.props.loggedIn === true) { - return ( -
  • - - - Dashboard - -
  • - ); - } - }; - - var customRules = function() { - if (that.props.loggedIn === true) { - return ( -
  • - - - Custom Rules - -
  • - ); - } - }; - + var signedInAs = function () { + if (that.props.loggedIn === true) { return ( - +

    + Signed in as {that.props.user.full_name} +

    ); - } + } + }; + var dashboard = function () { + if (that.props.loggedIn === true) { + return ( +
  • + + + Dashboard + +
  • + ); + } + }; + + var customRules = function () { + if (that.props.loggedIn === true) { + return ( +
  • + + + Custom Rules + +
  • + ); + } + }; + + return ( + + ); + }, }); module.exports = NavBar; diff --git a/assets/js/components/Options.jsx b/assets/js/components/Options.jsx index 1bd9e7b..62a8c79 100644 --- a/assets/js/components/Options.jsx +++ b/assets/js/components/Options.jsx @@ -17,200 +17,215 @@ var SitesList = require('./SitesList.jsx'); * @type {*|Function} */ var Options = reactCreateClass({ + getInitialState: function () { + return { + theme: config.theme, + blacklist: '', + whitelist: '', + loggingType: config.loggingType, + loggingStyle: config.loggingStyle, + displayAlert: false, + alertType: config.alert.success.type, + alertText: config.alert.success.text, + }; + }, - getInitialState: function () { - return { - theme: config.theme, - blacklist: '', - whitelist: '', - loggingType: config.loggingType, - loggingStyle: config.loggingStyle, - displayAlert: false, - alertType: config.alert.success.type, - alertText: config.alert.success.text - }; - }, + componentDidMount: function () { + this.restoreSettings(); + }, - componentDidMount: function () { - this.restoreSettings(); - }, + restoreSettings: function () { + var that = this; - restoreSettings: function () { - var that = this; - - browser.storage.sync.get({ - theme: config.theme, - blacklist: '', - whitelist: '', - loggingType: config.loggingType, - loggingStyle: config.loggingStyle - }).then(function (items) { - that.setState({ - theme: items.theme, - blacklist: items.blacklist, - whitelist: items.whitelist, - loggingType: items.loggingType, - loggingStyle: items.loggingStyle - }); - - that.refs.theme.value = items.theme; - that.refs.loggingType.value = items.loggingType; - that.refs.loggingStyle.value = items.loggingStyle; + browser.storage.sync + .get({ + theme: config.theme, + blacklist: '', + whitelist: '', + loggingType: config.loggingType, + loggingStyle: config.loggingStyle, + }) + .then(function (items) { + that.setState({ + theme: items.theme, + blacklist: items.blacklist, + whitelist: items.whitelist, + loggingType: items.loggingType, + loggingStyle: items.loggingStyle, }); - }, - _handleSubmit: function (e) { - e.preventDefault(); + that.refs.theme.value = items.theme; + that.refs.loggingType.value = items.loggingType; + that.refs.loggingStyle.value = items.loggingStyle; + }); + }, - this.saveSettings(); - }, + _handleSubmit: function (e) { + e.preventDefault(); - saveSettings: function () { - var that = this; + this.saveSettings(); + }, - var theme = this.refs.theme.value.trim(); - var loggingType = this.refs.loggingType.value.trim(); - var loggingStyle = this.refs.loggingStyle.value.trim(); - // Trimming blacklist and whitelist removes blank lines and spaces. - var blacklist = that.state.blacklist.trim(); - var whitelist = that.state.whitelist.trim(); + saveSettings: function () { + var that = this; - // Sync options with google storage. - browser.storage.sync.set({ - theme: theme, - blacklist: blacklist, - whitelist: whitelist, - loggingType: loggingType, - loggingStyle: loggingStyle - }).then(function () { - // Set state to be newly entered values. - that.setState({ - theme: theme, - blacklist: blacklist, - whitelist: whitelist, - loggingType: loggingType, - loggingStyle: loggingStyle, - displayAlert: true - }); + var theme = this.refs.theme.value.trim(); + var loggingType = this.refs.loggingType.value.trim(); + var loggingStyle = this.refs.loggingStyle.value.trim(); + // Trimming blacklist and whitelist removes blank lines and spaces. + var blacklist = that.state.blacklist.trim(); + var whitelist = that.state.whitelist.trim(); + + // Sync options with google storage. + browser.storage.sync + .set({ + theme: theme, + blacklist: blacklist, + whitelist: whitelist, + loggingType: loggingType, + loggingStyle: loggingStyle, + }) + .then(function () { + // Set state to be newly entered values. + that.setState({ + theme: theme, + blacklist: blacklist, + whitelist: whitelist, + loggingType: loggingType, + loggingStyle: loggingStyle, + displayAlert: true, }); - }, + }); + }, - _displayBlackOrWhiteList: function () { - var loggingStyle = this.refs.loggingStyle.value.trim(); + _displayBlackOrWhiteList: function () { + var loggingStyle = this.refs.loggingStyle.value.trim(); - this.setState({loggingStyle: loggingStyle}); - }, + this.setState({ loggingStyle: loggingStyle }); + }, - _updateBlacklistState: function(sites){ - this.setState({ - blacklist: sites - }); - }, + _updateBlacklistState: function (sites) { + this.setState({ + blacklist: sites, + }); + }, - _updateWhitelistState: function(sites){ - this.setState({ - whitelist: sites - }); - }, + _updateWhitelistState: function (sites) { + this.setState({ + whitelist: sites, + }); + }, - render: function () { + render: function () { + var that = this; - var that = this; - - var alert = function() { - if(that.state.displayAlert === true){ - - setTimeout(function () { - that.setState({displayAlert:false}); - }, 2000); - - return( - - ); - } - }; - - var loggingStyle = function () { - - if (that.state.loggingStyle == 'blacklist') { - return ( - - ); - } - - return ( - - ); - - }; + var alert = function () { + if (that.state.displayAlert === true) { + setTimeout(function () { + that.setState({ displayAlert: false }); + }, 2000); return ( -
    -
    -
    - - - {alert()} - - -
    - -
    - - -
    - -
    -
    - - {loggingStyle()} - -
    - - -
    - -
    -
    - -
    - - -
    - -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    -
    + ); - } + } + }; + + var loggingStyle = function () { + if (that.state.loggingStyle == 'blacklist') { + return ( + + ); + } + + return ( + + ); + }; + + return ( +
    +
    +
    + + {alert()} + + +
    +
    + + +
    + +
    +
    + + {loggingStyle()} + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + ); + }, }); module.exports = Options; diff --git a/assets/js/components/SitesList.jsx b/assets/js/components/SitesList.jsx index af0eb67..8aeaf60 100644 --- a/assets/js/components/SitesList.jsx +++ b/assets/js/components/SitesList.jsx @@ -2,35 +2,43 @@ var React = require('react'); var reactCreateClass = require('create-react-class'); var SitesList = reactCreateClass({ + getDefaultProps: function () { + return { + placeholder: 'http://google.com', + }; + }, - getDefaultProps: function () { - return { - placeholder: 'http://google.com' - }; - }, + _handleChange: function (event) { + var sites = event.target.value; - _handleChange: function (event) { - var sites = event.target.value; + this.props.handleChange(sites); + }, - this.props.handleChange(sites); - }, + render: function () { + return ( +
    + - render: function () { - - return ( -
    - - -
    - - {this.props.helpText} -
    - One line per site.
    -
    -
    - ); - } +
    + + + {this.props.helpText} +
    + One line per site. +
    +
    +
    + ); + }, }); module.exports = SitesList; diff --git a/assets/js/components/WakaTime.jsx b/assets/js/components/WakaTime.jsx index 5d40db7..d953c0b 100644 --- a/assets/js/components/WakaTime.jsx +++ b/assets/js/components/WakaTime.jsx @@ -1,6 +1,6 @@ /* global browser */ -var React = require("react"); +var React = require('react'); var reactCreateClass = require('create-react-class'); var $ = require('jquery'); @@ -17,160 +17,147 @@ var WakaTimeCore = require('../core/WakaTimeCore').default; var changeExtensionState = require('../helpers/changeExtensionState'); var Wakatime = reactCreateClass({ + getInitialState: function () { + return { + user: { + full_name: null, + email: null, + photo: null, + }, + loggedIn: false, + loggingEnabled: config.loggingEnabled, + totalTimeLoggedToday: '0 minutes', + }; + }, - getInitialState: function() { - return { - user: { - full_name: null, - email: null, - photo: null - }, - loggedIn: false, + componentDidMount: function () { + var wakatime = new WakaTimeCore(); + + var that = this; + + wakatime.checkAuth().done(function (data) { + if (data !== false) { + browser.storage.sync + .get({ loggingEnabled: config.loggingEnabled, - totalTimeLoggedToday: '0 minutes' - }; - }, + }) + .then(function (items) { + that.setState({ loggingEnabled: items.loggingEnabled }); - componentDidMount: function() { - - var wakatime = new WakaTimeCore(); - - var that = this; - - wakatime.checkAuth().done(function(data) { - - if (data !== false) { - - browser.storage.sync.get({ - loggingEnabled: config.loggingEnabled - }).then(function(items) { - that.setState({loggingEnabled: items.loggingEnabled}); - - if (items.loggingEnabled === true) { - changeExtensionState('allGood'); - } - else { - changeExtensionState('notLogging'); - } - }); - - that.setState({ - user: { - full_name: data.full_name, - email: data.email, - photo: data.photo - }, - loggedIn: true - }); - - wakatime.getTotalTimeLoggedToday().done(function(grand_total) { - that.setState({ - totalTimeLoggedToday: grand_total.text - }); - }); - - wakatime.recordHeartbeat(); - } - else { - changeExtensionState('notSignedIn'); + if (items.loggingEnabled === true) { + changeExtensionState('allGood'); + } else { + changeExtensionState('notLogging'); } + }); + + that.setState({ + user: { + full_name: data.full_name, + email: data.email, + photo: data.photo, + }, + loggedIn: true, }); - }, - - logoutUser: function() { - var deferredObject = $.Deferred(); - - var that = this; - - $.ajax({ - url: config.logoutUserUrl, - method: 'GET', - success: function() { - - deferredObject.resolve(that); - - }, - error: function(xhr, status, err) { - - console.error(config.logoutUserUrl, status, err.toString()); - - deferredObject.resolve(that); - } + wakatime.getTotalTimeLoggedToday().done(function (grand_total) { + that.setState({ + totalTimeLoggedToday: grand_total.text, + }); }); - return deferredObject.promise(); - }, + wakatime.recordHeartbeat(); + } else { + changeExtensionState('notSignedIn'); + } + }); + }, - _logoutUser: function() { + logoutUser: function () { + var deferredObject = $.Deferred(); - var that = this; + var that = this; - this.logoutUser().done(function(){ + $.ajax({ + url: config.logoutUserUrl, + method: 'GET', + success: function () { + deferredObject.resolve(that); + }, + error: function (xhr, status, err) { + console.error(config.logoutUserUrl, status, err.toString()); - that.setState({ - user: { - full_name: null, - email: null, - photo: null - }, - loggedIn: false, - loggingEnabled: false - }); + deferredObject.resolve(that); + }, + }); - changeExtensionState('notSignedIn'); + return deferredObject.promise(); + }, - }); - }, + _logoutUser: function () { + var that = this; - _disableLogging: function() { - this.setState({ - loggingEnabled: false - }); + this.logoutUser().done(function () { + that.setState({ + user: { + full_name: null, + email: null, + photo: null, + }, + loggedIn: false, + loggingEnabled: false, + }); - changeExtensionState('notLogging'); + changeExtensionState('notSignedIn'); + }); + }, - browser.storage.sync.set({ - loggingEnabled: false - }); - }, + _disableLogging: function () { + this.setState({ + loggingEnabled: false, + }); - _enableLogging: function() { - this.setState({ - loggingEnabled: true - }); + changeExtensionState('notLogging'); - changeExtensionState('allGood'); + browser.storage.sync.set({ + loggingEnabled: false, + }); + }, - browser.storage.sync.set({ - loggingEnabled: true - }); - }, + _enableLogging: function () { + this.setState({ + loggingEnabled: true, + }); - render: function() { - return ( -
    - -
    -
    -
    - -
    -
    -
    + changeExtensionState('allGood'); + + browser.storage.sync.set({ + loggingEnabled: true, + }); + }, + + render: function () { + return ( +
    + +
    +
    +
    +
    - ); - } - +
    +
    +
    + ); + }, }); module.exports = Wakatime; diff --git a/assets/js/config.js b/assets/js/config.js index 4b4a169..01d9d06 100644 --- a/assets/js/config.js +++ b/assets/js/config.js @@ -1,67 +1,60 @@ /* global browser */ //jshint esnext:true - var config = { - // Extension name - name: 'WakaTime', - // Extension 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 - detectionIntervalInSeconds: 60, - // Default logging style - // Log all except blacklisted sites - // or log only the white listed sites. - loggingStyle: 'blacklist', - // Default logging type - loggingType: 'domain', - // By default logging is enabled - loggingEnabled: true, - // Url to which to send the heartbeat - heartbeatApiUrl: 'https://wakatime.com/api/v1/users/current/heartbeats', - // Url from which to detect if the user is logged in - currentUserApiUrl: 'https://wakatime.com/api/v1/users/current', - // The url to logout the user from wakatime - logoutUserUrl: 'https://wakatime.com/logout', - // Gets stats from the WakaTime API - summariesApiUrl: 'https://wakatime.com/api/v1/users/current/summaries', - // Different colors for different states of the extension - colors: { - allGood: '', - notLogging: 'gray', - notSignedIn: 'red', - lightTheme: 'white' + // Extension name + name: 'WakaTime', + // Extension version + version: process.env.NODE_ENV === 'test' ? 'test' : 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 + detectionIntervalInSeconds: 60, + // Default logging style + // Log all except blacklisted sites + // or log only the white listed sites. + loggingStyle: 'blacklist', + // Default logging type + loggingType: 'domain', + // By default logging is enabled + loggingEnabled: true, + // Url to which to send the heartbeat + heartbeatApiUrl: 'https://wakatime.com/api/v1/users/current/heartbeats', + // Url from which to detect if the user is logged in + currentUserApiUrl: 'https://wakatime.com/api/v1/users/current', + // The url to logout the user from wakatime + logoutUserUrl: 'https://wakatime.com/logout', + // Gets stats from the WakaTime API + summariesApiUrl: 'https://wakatime.com/api/v1/users/current/summaries', + // Different colors for different states of the extension + colors: { + allGood: '', + notLogging: 'gray', + notSignedIn: 'red', + lightTheme: 'white', + }, + // Tooltips for each of the extension states + tooltips: { + allGood: '', + notLogging: 'Not logging', + notSignedIn: 'Not signed In', + blacklisted: 'This URL is blacklisted', + whitelisted: 'This URL is not on your whitelist', + }, + // Default theme + theme: 'light', + // Valid extension states + states: ['allGood', 'notLogging', 'notSignedIn', 'blacklisted', 'whitelisted'], + // Predefined alert type and text for success and failure. + alert: { + success: { + type: 'success', + text: 'Options have been saved!', }, - // Tooltips for each of the extension states - tooltips: { - allGood: '', - notLogging: 'Not logging', - notSignedIn: 'Not signed In', - blacklisted: 'This URL is blacklisted', - whitelisted: 'This URL is not on your whitelist' + failure: { + type: 'danger', + text: 'There was an error while saving the options!', }, - // Default theme - theme: 'light', - // Valid extension states - states: [ - 'allGood', - 'notLogging', - 'notSignedIn', - 'blacklisted', - 'whitelisted' - ], - // Predefined alert type and text for success and failure. - alert: { - success: { - type: 'success', - text: 'Options have been saved!' - }, - failure: { - type: 'danger', - text: 'There was an error while saving the options!' - } - } + }, }; module.exports = config; diff --git a/assets/js/core/WakaTimeCore.js b/assets/js/core/WakaTimeCore.js index c8808c3..7dd93e2 100644 --- a/assets/js/core/WakaTimeCore.js +++ b/assets/js/core/WakaTimeCore.js @@ -32,7 +32,7 @@ class WakaTimeCore { $.ajax({ url: config.summariesApiUrl + '?start=' + today + '&end=' + today, dataType: 'json', - success: data => { + success: (data) => { deferredObject.resolve(data.data[0].grand_total); }, error: (xhr, status, err) => { @@ -56,7 +56,7 @@ class WakaTimeCore { $.ajax({ url: config.currentUserApiUrl, dataType: 'json', - success: data => { + success: (data) => { deferredObject.resolve(data.data); }, error: (xhr, status, err) => { @@ -80,14 +80,14 @@ class WakaTimeCore { blacklist: '', whitelist: '', }) - .then(items => { + .then((items) => { if (items.loggingEnabled === true) { changeExtensionState('allGood'); - browser.idle.queryState(config.detectionIntervalInSeconds).then(newState => { + browser.idle.queryState(config.detectionIntervalInSeconds).then((newState) => { if (newState === 'active') { // Get current tab URL. - browser.tabs.query({ currentWindow: true, active: true }).then(tabs => { + browser.tabs.query({ currentWindow: true, active: true }).then((tabs) => { if (tabs.length == 0) return; var currentActiveTab = tabs[0]; @@ -141,9 +141,9 @@ class WakaTimeCore { * @returns {object} */ getHeartbeat(url, list) { - const projectIndicatorCharacters = '@@'; + var projectIndicatorCharacters = '@@'; - const lines = list.split('\n'); + var lines = list.split('\n'); for (var i = 0; i < lines.length; i++) { // strip (http:// or https://) and trailing (`/` or `@@`) var cleanLine = lines[i] @@ -241,7 +241,7 @@ class WakaTimeCore { sendHeartbeat(heartbeat, debug) { var payload = null; - this._getLoggingType().done(loggingType => { + this._getLoggingType().done((loggingType) => { // Get only the domain from the entity. // And send that in heartbeat if (loggingType == 'domain') { @@ -283,7 +283,7 @@ class WakaTimeCore { // nothing to do here }, }, - success: response => { + success: (response) => { deferredObject.resolve(this); }, error: (xhr, status, err) => { diff --git a/assets/js/devtools.js b/assets/js/devtools.js index eb1bb12..b54892d 100644 --- a/assets/js/devtools.js +++ b/assets/js/devtools.js @@ -2,11 +2,11 @@ // Create a connection to the background page var backgroundPageConnection = browser.runtime.connect({ - name: "devtools-page" + name: 'devtools-page', }); // Send a message to background page with the current active tabId backgroundPageConnection.postMessage({ - name: 'init', - tabId: browser.devtools.inspectedWindow.tabId + name: 'init', + tabId: browser.devtools.inspectedWindow.tabId, }); diff --git a/assets/js/events.js b/assets/js/events.js index 3652e7e..f7daea0 100644 --- a/assets/js/events.js +++ b/assets/js/events.js @@ -1,7 +1,7 @@ /* global browser */ // Core -var WakaTimeCore = require("./core/WakaTimeCore").default; +var WakaTimeCore = require('./core/WakaTimeCore').default; // initialize class var wakatime = new WakaTimeCore(); @@ -12,46 +12,40 @@ var connections = {}; // Add a listener to resolve alarms 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') { + // |alarm| can be undefined because onAlarm also gets called from + // window.setTimeout on old chrome versions. + if (alarm && alarm.name == 'heartbeatAlarm') { + console.log('recording a heartbeat - alarm triggered'); - console.log('recording a heartbeat - alarm triggered'); - - wakatime.recordHeartbeat(); - } + wakatime.recordHeartbeat(); + } }); // Create a new alarm for heartbeats. -browser.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. */ browser.tabs.onActivated.addListener(function (activeInfo) { + browser.tabs.get(activeInfo.tabId).then(function (tab) { + console.log('recording a heartbeat - active tab changed'); - browser.tabs.get(activeInfo.tabId).then(function (tab) { - - console.log('recording a heartbeat - active tab changed'); - - wakatime.recordHeartbeat(); - }); - + wakatime.recordHeartbeat(); + }); }); /** * Whenever a active window is changed it records a heartbeat with the active tab url. */ browser.windows.onFocusChanged.addListener(function (windowId) { + if (windowId != browser.windows.WINDOW_ID_NONE) { + console.log('recording a heartbeat - active window changed'); - if (windowId != browser.windows.WINDOW_ID_NONE) { - console.log('recording a heartbeat - active window changed'); - - wakatime.recordHeartbeat(); - } else { - console.log('lost focus'); - } - + wakatime.recordHeartbeat(); + } else { + console.log('lost focus'); + } }); /** @@ -59,57 +53,49 @@ browser.windows.onFocusChanged.addListener(function (windowId) { * currently active and if it is, then it records a heartbeat. */ browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { + if (changeInfo.status === 'complete') { + // Get current tab URL. + browser.tabs.query({ currentWindow: true, 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'); - if (changeInfo.status === 'complete') { - // Get current tab URL. - browser.tabs.query({currentWindow: true, 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'); - - wakatime.recordHeartbeat(); - } - }); - } - + wakatime.recordHeartbeat(); + } + }); + } }); - /** * This is in charge of detecting if devtools are opened or closed * and sending a heartbeat depending on that. */ browser.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; - if (port.name == "devtools-page") { + wakatime.setTabsWithDevtoolsOpen(Object.keys(connections)); - // Listen to messages sent from the DevTools page - port.onMessage.addListener(function (message, sender, sendResponse) { - if (message.name == "init") { + wakatime.recordHeartbeat(); + } + }); - connections[message.tabId] = port; + port.onDisconnect.addListener(function (port) { + var tabs = Object.keys(connections); - wakatime.setTabsWithDevtoolsOpen(Object.keys(connections)); + for (var i = 0, len = tabs.length; i < len; i++) { + if (connections[tabs[i]] == port) { + delete connections[tabs[i]]; + break; + } + } - wakatime.recordHeartbeat(); - } - }); + wakatime.setTabsWithDevtoolsOpen(Object.keys(connections)); - 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(); - }); - - } + wakatime.recordHeartbeat(); + }); + } }); diff --git a/assets/js/helpers/changeExtensionIcon.js b/assets/js/helpers/changeExtensionIcon.js index 0a08176..7905eb0 100644 --- a/assets/js/helpers/changeExtensionIcon.js +++ b/assets/js/helpers/changeExtensionIcon.js @@ -9,42 +9,41 @@ var config = require('../config'); * @param color */ function changeExtensionIcon(color) { + color = color ? color : ''; - color = color ? color : ''; + var path = null; - var path = null; + if (color !== '') { + color = '-' + color; - if (color !== '') { - color = '-' + color; + path = './graphics/wakatime-logo-38' + color + '.png'; - path = './graphics/wakatime-logo-38' + color + '.png'; + browser.browserAction.setIcon({ + path: path, + }); + } - browser.browserAction.setIcon({ - path: path - }); - } + if (color === '') { + browser.storage.sync + .get({ + theme: config.theme, + }) + .then(function (items) { + if (items.theme == config.theme) { + path = './graphics/wakatime-logo-38.png'; - if (color === '') { - browser.storage.sync.get({ - theme: config.theme - }).then(function (items) { - if (items.theme == config.theme) { - path = './graphics/wakatime-logo-38.png'; - - browser.browserAction.setIcon({ - path: path - }); - } - else { - path = './graphics/wakatime-logo-38-white.png'; - - browser.browserAction.setIcon({ - path: path - }); - } - }); - } + browser.browserAction.setIcon({ + path: path, + }); + } else { + path = './graphics/wakatime-logo-38-white.png'; + browser.browserAction.setIcon({ + path: path, + }); + } + }); + } } module.exports = changeExtensionIcon; diff --git a/assets/js/helpers/changeExtensionState.js b/assets/js/helpers/changeExtensionState.js index e879059..f881bc9 100644 --- a/assets/js/helpers/changeExtensionState.js +++ b/assets/js/helpers/changeExtensionState.js @@ -11,32 +11,32 @@ var in_array = require('./in_array'); * @param state */ function changeExtensionState(state) { - if (! in_array(state, config.states)) { - throw new Error('Not a valid state!'); - } + if (!in_array(state, config.states)) { + throw new Error('Not a valid state!'); + } - switch (state) { - case 'allGood': - changeExtensionIcon(config.colors.allGood); - changeExtensionTooltip(config.tooltips.allGood); - break; - case 'notLogging': - changeExtensionIcon(config.colors.notLogging); - changeExtensionTooltip(config.tooltips.notLogging); - break; - case 'notSignedIn': - changeExtensionIcon(config.colors.notSignedIn); - changeExtensionTooltip(config.tooltips.notSignedIn); - break; - case 'blacklisted': - changeExtensionIcon(config.colors.notLogging); - changeExtensionTooltip(config.tooltips.blacklisted); - break; - case 'whitelisted': - changeExtensionIcon(config.colors.notLogging); - changeExtensionTooltip(config.tooltips.whitelisted); - break; - } + switch (state) { + case 'allGood': + changeExtensionIcon(config.colors.allGood); + changeExtensionTooltip(config.tooltips.allGood); + break; + case 'notLogging': + changeExtensionIcon(config.colors.notLogging); + changeExtensionTooltip(config.tooltips.notLogging); + break; + case 'notSignedIn': + changeExtensionIcon(config.colors.notSignedIn); + changeExtensionTooltip(config.tooltips.notSignedIn); + break; + case 'blacklisted': + changeExtensionIcon(config.colors.notLogging); + changeExtensionTooltip(config.tooltips.blacklisted); + break; + case 'whitelisted': + changeExtensionIcon(config.colors.notLogging); + changeExtensionTooltip(config.tooltips.whitelisted); + break; + } } -module.exports = changeExtensionState; \ No newline at end of file +module.exports = changeExtensionState; diff --git a/assets/js/helpers/changeExtensionTooltip.js b/assets/js/helpers/changeExtensionTooltip.js index d230b67..b65caf0 100644 --- a/assets/js/helpers/changeExtensionTooltip.js +++ b/assets/js/helpers/changeExtensionTooltip.js @@ -8,15 +8,13 @@ var config = require('../config'); * @param text */ function changeExtensionTooltip(text) { + if (text === '') { + text = config.name; + } else { + text = config.name + ' - ' + text; + } - if (text === '') { - text = config.name; - } - else { - text = config.name + ' - ' + text; - } - - browser.browserAction.setTitle({title: text}); + browser.browserAction.setTitle({ title: text }); } -module.exports = changeExtensionTooltip; \ No newline at end of file +module.exports = changeExtensionTooltip; diff --git a/assets/js/helpers/contains.js b/assets/js/helpers/contains.js index d40f1b2..62751ad 100644 --- a/assets/js/helpers/contains.js +++ b/assets/js/helpers/contains.js @@ -7,25 +7,24 @@ * @returns {boolean} */ function contains(url, list) { - var lines = list.split('\n'); + var lines = list.split('\n'); - for (var i = 0; i < lines.length; i ++) { + for (var i = 0; i < lines.length; i++) { + // Trim all lines from the list one by one + var cleanLine = lines[i].trim(); - // Trim all lines from the list one by one - var cleanLine = lines[i].trim(); + // If by any chance one line in the list is empty, ignore it + if (cleanLine === '') continue; - // If by any chance one line in the list is empty, ignore it - if(cleanLine === '') continue; + var lineRe = new RegExp(cleanLine.replace('.', '.').replace('*', '.*')); - var lineRe = new RegExp(cleanLine.replace('.', '\.').replace('*', '.*')); - - // If url matches the current line return true - if (lineRe.test(url)) { - return true; - } + // If url matches the current line return true + if (lineRe.test(url)) { + return true; } + } - return false; + return false; } module.exports = contains; diff --git a/assets/js/helpers/getDomainFromUrl.js b/assets/js/helpers/getDomainFromUrl.js index 4195875..fd45232 100644 --- a/assets/js/helpers/getDomainFromUrl.js +++ b/assets/js/helpers/getDomainFromUrl.js @@ -5,9 +5,9 @@ * @returns {string} */ function getDomainFromUrl(url) { - var parts = url.split('/'); + var parts = url.split('/'); - return parts[0] + "//" + parts[2]; + return parts[0] + '//' + parts[2]; } -module.exports = getDomainFromUrl; \ No newline at end of file +module.exports = getDomainFromUrl; diff --git a/assets/js/helpers/in_array.js b/assets/js/helpers/in_array.js index 66ccbde..2a6774b 100644 --- a/assets/js/helpers/in_array.js +++ b/assets/js/helpers/in_array.js @@ -6,13 +6,13 @@ * @returns {boolean} */ function in_array(needle, haystack) { - for (var i = 0; i < haystack.length; i ++) { - if (needle == haystack[i]) { - return true; - } + for (var i = 0; i < haystack.length; i++) { + if (needle == haystack[i]) { + return true; } + } - return false; + return false; } -module.exports = in_array; \ No newline at end of file +module.exports = in_array; diff --git a/assets/js/options.jsx b/assets/js/options.jsx index b7f21ec..de9c79f 100644 --- a/assets/js/options.jsx +++ b/assets/js/options.jsx @@ -10,7 +10,4 @@ var ReactDOM = require('react-dom'); // React components var Options = require('./components/Options.jsx'); -ReactDOM.render( - , - document.getElementById('wakatime-options') -); +ReactDOM.render(, document.getElementById('wakatime-options')); diff --git a/assets/less/app.less b/assets/less/app.less index 4debeed..abc7d5f 100644 --- a/assets/less/app.less +++ b/assets/less/app.less @@ -1,9 +1,9 @@ -@import "bootstrap/bootstrap"; -@import "font-awesome/font-awesome"; -@import "bootswatch/paper/bootswatch"; -@import "bootswatch/paper/variables"; -@import "variables"; -@import "partials/_animations"; +@import 'bootstrap/bootstrap'; +@import 'font-awesome/font-awesome'; +@import 'bootswatch/paper/bootswatch'; +@import 'bootswatch/paper/variables'; +@import 'variables'; +@import 'partials/_animations'; body { min-width: 357px; @@ -18,11 +18,11 @@ a.navbar-brand { } div.container { - margin-top: 20px; + margin-top: 20px; } canvas#icon { - display: none; + display: none; } div#status { diff --git a/assets/less/bootstrap/alerts.less b/assets/less/bootstrap/alerts.less index c4199db..5f18343 100644 --- a/assets/less/bootstrap/alerts.less +++ b/assets/less/bootstrap/alerts.less @@ -2,7 +2,6 @@ // Alerts // -------------------------------------------------- - // Base styles // ------------------------- diff --git a/assets/less/bootstrap/badges.less b/assets/less/bootstrap/badges.less index 6ee16dc..39d80e8 100644 --- a/assets/less/bootstrap/badges.less +++ b/assets/less/bootstrap/badges.less @@ -2,7 +2,6 @@ // Badges // -------------------------------------------------- - // Base class .badge { display: inline-block; diff --git a/assets/less/bootstrap/bootstrap.less b/assets/less/bootstrap/bootstrap.less index 1c04778..32c3463 100644 --- a/assets/less/bootstrap/bootstrap.less +++ b/assets/less/bootstrap/bootstrap.less @@ -1,56 +1,56 @@ /*! - * 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) */ // Core variables and mixins -@import "variables.less"; -@import "mixins.less"; +@import 'variables.less'; +@import 'mixins.less'; // Reset and dependencies -@import "normalize.less"; -@import "print.less"; -@import "glyphicons.less"; +@import 'normalize.less'; +@import 'print.less'; +@import 'glyphicons.less'; // Core CSS -@import "scaffolding.less"; -@import "type.less"; -@import "code.less"; -@import "grid.less"; -@import "tables.less"; -@import "forms.less"; -@import "buttons.less"; +@import 'scaffolding.less'; +@import 'type.less'; +@import 'code.less'; +@import 'grid.less'; +@import 'tables.less'; +@import 'forms.less'; +@import 'buttons.less'; // Components -@import "component-animations.less"; -@import "dropdowns.less"; -@import "button-groups.less"; -@import "input-groups.less"; -@import "navs.less"; -@import "navbar.less"; -@import "breadcrumbs.less"; -@import "pagination.less"; -@import "pager.less"; -@import "labels.less"; -@import "badges.less"; -@import "jumbotron.less"; -@import "thumbnails.less"; -@import "alerts.less"; -@import "progress-bars.less"; -@import "media.less"; -@import "list-group.less"; -@import "panels.less"; -@import "responsive-embed.less"; -@import "wells.less"; -@import "close.less"; +@import 'component-animations.less'; +@import 'dropdowns.less'; +@import 'button-groups.less'; +@import 'input-groups.less'; +@import 'navs.less'; +@import 'navbar.less'; +@import 'breadcrumbs.less'; +@import 'pagination.less'; +@import 'pager.less'; +@import 'labels.less'; +@import 'badges.less'; +@import 'jumbotron.less'; +@import 'thumbnails.less'; +@import 'alerts.less'; +@import 'progress-bars.less'; +@import 'media.less'; +@import 'list-group.less'; +@import 'panels.less'; +@import 'responsive-embed.less'; +@import 'wells.less'; +@import 'close.less'; // Components w/ JavaScript -@import "modals.less"; -@import "tooltip.less"; -@import "popovers.less"; -@import "carousel.less"; +@import 'modals.less'; +@import 'tooltip.less'; +@import 'popovers.less'; +@import 'carousel.less'; // Utility classes -@import "utilities.less"; -@import "responsive-utilities.less"; +@import 'utilities.less'; +@import 'responsive-utilities.less'; diff --git a/assets/less/bootstrap/breadcrumbs.less b/assets/less/bootstrap/breadcrumbs.less index cb01d50..5053a0d 100644 --- a/assets/less/bootstrap/breadcrumbs.less +++ b/assets/less/bootstrap/breadcrumbs.less @@ -2,7 +2,6 @@ // Breadcrumbs // -------------------------------------------------- - .breadcrumb { padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; margin-bottom: @line-height-computed; @@ -14,7 +13,7 @@ display: inline-block; + li:before { - content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space + content: '@{breadcrumb-separator}\00a0'; // Unicode space added since inline-block means non-collapsing white-space padding: 0 5px; color: @breadcrumb-color; } diff --git a/assets/less/bootstrap/button-groups.less b/assets/less/bootstrap/button-groups.less index 293245a..487846c 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); @@ -88,15 +88,19 @@ outline: 0; } - // Sizing // // Remix the default button sizing classes into new ones for easier manipulation. -.btn-group-xs > .btn { &:extend(.btn-xs); } -.btn-group-sm > .btn { &:extend(.btn-sm); } -.btn-group-lg > .btn { &:extend(.btn-lg); } - +.btn-group-xs > .btn { + &:extend(.btn-xs); +} +.btn-group-sm > .btn { + &:extend(.btn-sm); +} +.btn-group-lg > .btn { + &:extend(.btn-lg); +} // Split button dropdowns // ---------------------- @@ -114,7 +118,7 @@ // The clickable button for toggling the menu // Remove the gradient and set the same inset shadow as the :active state .btn-group.open .dropdown-toggle { - .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + .box-shadow(inset 0 3px 5px rgba(0,0,0,0.125)); // Show no shadow for `.btn-link` since it has no other button styles. &.btn-link { @@ -122,7 +126,6 @@ } } - // Reposition the caret .btn .caret { margin-left: 0; @@ -137,7 +140,6 @@ border-width: 0 @caret-width-large @caret-width-large; } - // Vertical button groups // ---------------------- @@ -194,7 +196,6 @@ .border-top-radius(0); } - // Justified button groups // ---------------------- @@ -218,7 +219,6 @@ } } - // Checkbox and radio options // // In order to support the browser's form validation feedback, powered by the @@ -231,13 +231,13 @@ // See https://github.com/twbs/bootstrap/pull/12794 and // https://github.com/twbs/bootstrap/pull/14559 for more information. -[data-toggle="buttons"] { +[data-toggle='buttons'] { > .btn, > .btn-group > .btn { - input[type="radio"], - input[type="checkbox"] { + input[type='radio'], + input[type='checkbox'] { position: absolute; - clip: rect(0,0,0,0); + clip: rect(0, 0, 0, 0); pointer-events: none; } } diff --git a/assets/less/bootstrap/buttons.less b/assets/less/bootstrap/buttons.less index 9cbb8f4..e42f740 100644 --- a/assets/less/bootstrap/buttons.less +++ b/assets/less/bootstrap/buttons.less @@ -2,7 +2,6 @@ // Buttons // -------------------------------------------------- - // Base styles // -------------------------------------------------- @@ -40,14 +39,14 @@ &.active { outline: 0; background-image: none; - .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + .box-shadow(inset 0 3px 5px rgba(0,0,0,0.125)); } &.disabled, &[disabled], fieldset[disabled] & { cursor: @cursor-disabled; - .opacity(.65); + .opacity(0.65); .box-shadow(none); } @@ -59,7 +58,6 @@ } } - // Alternate buttons // -------------------------------------------------- @@ -86,7 +84,6 @@ .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border); } - // Link buttons // ------------------------- @@ -126,7 +123,6 @@ } } - // Button Sizes // -------------------------------------------------- @@ -142,7 +138,6 @@ .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); } - // Block button // -------------------------------------------------- @@ -157,9 +152,9 @@ } // Specificity overrides -input[type="submit"], -input[type="reset"], -input[type="button"] { +input[type='submit'], +input[type='reset'], +input[type='button'] { &.btn-block { width: 100%; } diff --git a/assets/less/bootstrap/carousel.less b/assets/less/bootstrap/carousel.less index 252011e..df7bec5 100644 --- a/assets/less/bootstrap/carousel.less +++ b/assets/less/bootstrap/carousel.less @@ -2,7 +2,6 @@ // Carousel // -------------------------------------------------- - // Wrapper for the slide container and indicators .carousel { position: relative; @@ -16,7 +15,7 @@ > .item { display: none; position: relative; - .transition(.6s ease-in-out left); + .transition(0.6s ease-in-out left); // Account for jankitude on images > img, @@ -84,7 +83,6 @@ > .active.right { left: 100%; } - } // Left/right controls for nav @@ -107,12 +105,12 @@ // Set gradients for backgrounds &.left { - #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001)); + #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));; } &.right { left: auto; right: 0; - #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5)); + #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));; } // Hover/focus state @@ -121,7 +119,7 @@ outline: 0; color: @carousel-control-color; text-decoration: none; - .opacity(.9); + .opacity(0.9); } // Toggles @@ -147,21 +145,20 @@ } .icon-prev, .icon-next { - width: 20px; + width: 20px; height: 20px; line-height: 1; font-family: serif; } - .icon-prev { &:before { - content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) + content: '\2039'; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) } } .icon-next { &:before { - content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) + content: '\203a'; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) } } } @@ -184,7 +181,7 @@ li { display: inline-block; - width: 10px; + width: 10px; height: 10px; margin: 1px; text-indent: -999px; @@ -202,11 +199,11 @@ // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we // set alpha transparency for the best results possible. background-color: #000 \9; // IE8 - background-color: rgba(0,0,0,0); // IE9 + background-color: rgba(0, 0, 0, 0); // IE9 } .active { margin: 0; - width: 12px; + width: 12px; height: 12px; background-color: @carousel-indicator-active-bg; } @@ -231,10 +228,8 @@ } } - // Scale up controls for tablets and up @media screen and (min-width: @screen-sm-min) { - // Scale up the controls a smidge .carousel-control { .glyphicon-chevron-left, diff --git a/assets/less/bootstrap/close.less b/assets/less/bootstrap/close.less index 6d5bfe0..b1ae0dd 100644 --- a/assets/less/bootstrap/close.less +++ b/assets/less/bootstrap/close.less @@ -2,7 +2,6 @@ // Close icons // -------------------------------------------------- - .close { float: right; font-size: (@font-size-base * 1.5); @@ -10,14 +9,14 @@ line-height: 1; color: @close-color; text-shadow: @close-text-shadow; - .opacity(.2); + .opacity(0.2); &:hover, &:focus { color: @close-color; text-decoration: none; cursor: pointer; - .opacity(.5); + .opacity(0.5); } // Additional properties for button version diff --git a/assets/less/bootstrap/code.less b/assets/less/bootstrap/code.less index a08b4d4..f4fd010 100644 --- a/assets/less/bootstrap/code.less +++ b/assets/less/bootstrap/code.less @@ -2,7 +2,6 @@ // Code (inline and block) // -------------------------------------------------- - // Inline and block code styles code, kbd, @@ -27,7 +26,7 @@ kbd { color: @kbd-color; background-color: @kbd-bg; border-radius: @border-radius-small; - box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); kbd { padding: 0; diff --git a/assets/less/bootstrap/component-animations.less b/assets/less/bootstrap/component-animations.less index 0bcee91..6dceb7b 100644 --- a/assets/less/bootstrap/component-animations.less +++ b/assets/less/bootstrap/component-animations.less @@ -9,7 +9,7 @@ .fade { opacity: 0; - .transition(opacity .15s linear); + .transition(opacity 0.15s linear); &.in { opacity: 1; } @@ -18,16 +18,22 @@ .collapse { display: none; - &.in { display: block; } - tr&.in { display: table-row; } - tbody&.in { display: table-row-group; } + &.in { + display: block; + } + tr&.in { + display: table-row; + } + tbody&.in { + display: table-row-group; + } } .collapsing { position: relative; height: 0; overflow: hidden; - .transition-property(~"height, visibility"); - .transition-duration(.35s); + .transition-property(~'height, visibility'); + .transition-duration(0.35s); .transition-timing-function(ease); } diff --git a/assets/less/bootstrap/dropdowns.less b/assets/less/bootstrap/dropdowns.less index f6876c1..cac6b80 100644 --- a/assets/less/bootstrap/dropdowns.less +++ b/assets/less/bootstrap/dropdowns.less @@ -2,7 +2,6 @@ // Dropdown menus // -------------------------------------------------- - // Dropdown arrow/caret .caret { display: inline-block; @@ -10,10 +9,10 @@ height: 0; margin-left: 2px; vertical-align: middle; - border-top: @caret-width-base dashed; - border-top: @caret-width-base solid ~"\9"; // IE8 + border-top: @caret-width-base dashed; + border-top: @caret-width-base solid ~'\9'; // IE8 border-right: @caret-width-base solid transparent; - border-left: @caret-width-base solid transparent; + border-left: @caret-width-base solid transparent; } // The dropdown wrapper (div) @@ -45,7 +44,7 @@ border: 1px solid @dropdown-fallback-border; // IE8 fallback border: 1px solid @dropdown-border; border-radius: @border-radius-base; - .box-shadow(0 6px 12px rgba(0,0,0,.175)); + .box-shadow(0 6px 12px rgba(0,0,0,0.175)); background-clip: padding-box; // Aligns the dropdown menu to right @@ -186,8 +185,8 @@ .caret { border-top: 0; border-bottom: @caret-width-base dashed; - border-bottom: @caret-width-base solid ~"\9"; // IE8 - content: ""; + border-bottom: @caret-width-base solid ~'\9'; // IE8 + content: ''; } // Different positioning for bottom up menu .dropdown-menu { @@ -197,7 +196,6 @@ } } - // Component alignment // // Reiterate per navbar.less and the modified component alignment there. diff --git a/assets/less/bootstrap/forms.less b/assets/less/bootstrap/forms.less index e8b071a..fe755e6 100644 --- a/assets/less/bootstrap/forms.less +++ b/assets/less/bootstrap/forms.less @@ -2,7 +2,6 @@ // Forms // -------------------------------------------------- - // Normalize non-controls // // Restyle and baseline non-control form elements. @@ -36,7 +35,6 @@ label { font-weight: bold; } - // Normalize form controls // // While most of our form styles require extra classes, some basic normalization @@ -44,24 +42,24 @@ label { // address browser inconsistencies. // Override content-box in Normalize (* isn't specific enough) -input[type="search"] { +input[type='search'] { .box-sizing(border-box); } // Position radios and checkboxes better -input[type="radio"], -input[type="checkbox"] { +input[type='radio'], +input[type='checkbox'] { margin: 4px 0 0; margin-top: 1px \9; // IE8-9 line-height: normal; } -input[type="file"] { +input[type='file'] { display: block; } // Make range inputs behave like textual form controls -input[type="range"] { +input[type='range'] { display: block; width: 100%; } @@ -73,9 +71,9 @@ select[size] { } // Focus for file, radio, and checkbox -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { +input[type='file']:focus, +input[type='radio']:focus, +input[type='checkbox']:focus { .tab-focus(); } @@ -88,7 +86,6 @@ output { color: @input-color; } - // Common form controls // // Shared size and type resets for form controls. Apply `.form-control` to any @@ -123,8 +120,8 @@ output { background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 border: 1px solid @input-border; border-radius: @input-border-radius; // Note: This has no effect on s in CSS. - .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); - .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s"); + .box-shadow(inset 0 1px 1px rgba(0,0,0,0.075)); + .transition(~'border-color ease-in-out .15s, box-shadow ease-in-out .15s'); // Customize the `:focus` state to imitate native WebKit styles. .form-control-focus(); @@ -161,7 +158,6 @@ output { } } - // Search inputs in iOS // // This overrides the extra rounded corners on search inputs in iOS so that our @@ -169,11 +165,10 @@ output { // be added to `.form-control` as it's not specific enough. For details, see // https://github.com/twbs/bootstrap/issues/11586. -input[type="search"] { +input[type='search'] { -webkit-appearance: none; } - // Special styles for iOS temporal inputs // // In Mobile Safari, setting `display: block` on temporal inputs causes the @@ -181,13 +176,13 @@ 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"], - input[type="time"], - input[type="datetime-local"], - input[type="month"] { + input[type='date'], + input[type='time'], + input[type='datetime-local'], + input[type='month'] { &.form-control { line-height: @input-height-base; } @@ -204,7 +199,6 @@ input[type="search"] { } } - // Form groups // // Designed to help with the organization and spacing of vertical forms. For @@ -214,7 +208,6 @@ input[type="search"] { margin-bottom: @form-group-margin-bottom; } - // Checkboxes and radios // // Indent the labels to position radios/checkboxes as hanging controls. @@ -234,10 +227,10 @@ input[type="search"] { cursor: pointer; } } -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { +.radio input[type='radio'], +.radio-inline input[type='radio'], +.checkbox input[type='checkbox'], +.checkbox-inline input[type='checkbox'] { position: absolute; margin-left: -20px; margin-top: 4px \9; @@ -269,8 +262,8 @@ input[type="search"] { // Some special care is needed because