Propmt when a api key can not be use + house keeping (#173)

* chore: remove old files

* chore: change JS tests to TS, delete dummy tests

* chore: bump manifests version
This commit is contained in:
Juan Sebastian velez Posada
2023-02-22 08:11:16 -05:00
committed by GitHub
parent fe49f50b65
commit 35543489e5
46 changed files with 132 additions and 1611 deletions

View File

@@ -1,11 +0,0 @@
/* This is a fix for Bootstrap requiring jQuery */
global.jQuery = require('jquery');
require('bootstrap');
var React = require('react');
var ReactDOM = require('react-dom');
// React components
var WakaTime = require('./components/WakaTime.jsx');
ReactDOM.render(<WakaTime />, document.getElementById('wakatime'));

View File

@@ -1,11 +0,0 @@
var React = require('react');
var reactCreateClass = require('create-react-class');
var classNames = require('classnames');
var Alert = reactCreateClass({
render: function () {
return <div className={classNames('alert', 'alert-' + this.props.type)}>{this.props.text}</div>;
},
});
module.exports = Alert;

View File

@@ -1,112 +0,0 @@
/* global browser */
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 (
<div>
<a href="#" className="list-group-item" onClick={that.props.logoutUser}>
<i className="fa fa-fw fa-sign-out"></i>
Logout
</a>
</div>
);
}
return (
<a target="_blank" href="https://wakatime.com/login" className="list-group-item">
<i className="fa fa-fw fa-sign-in"></i>
Login
</a>
);
};
// If logging is enabled, display that info to user
var loggingStatus = function () {
if (that.props.loggingEnabled === true && that.props.loggedIn === true) {
return (
<div className="row">
<div className="col-xs-12">
<p>
<a
href="#"
onClick={that.props.disableLogging}
className="btn btn-danger btn-block"
>
Disable logging
</a>
</p>
</div>
</div>
);
} else if (that.props.loggingEnabled === false && that.props.loggedIn === true) {
return (
<div className="row">
<div className="col-xs-12">
<p>
<a
href="#"
onClick={that.props.enableLogging}
className="btn btn-success btn-block"
>
Enable logging
</a>
</p>
</div>
</div>
);
}
};
var totalTimeLoggedToday = function () {
if (that.props.loggedIn === true) {
return (
<div className="row">
<div className="col-xs-12">
<blockquote>
<p>{that.props.totalTimeLoggedToday}</p>
<small>
<cite>TOTAL TIME LOGGED TODAY</cite>
</small>
</blockquote>
</div>
</div>
);
}
};
return (
<div>
{totalTimeLoggedToday()}
{loggingStatus()}
<div className="list-group">
<a href="#" className="list-group-item" onClick={this._openOptionsPage}>
<i className="fa fa-fw fa-cogs"></i>
Options
</a>
{loginLogoutButton()}
</div>
</div>
);
},
});
module.exports = MainList;

View File

@@ -1,102 +0,0 @@
var React = require('react');
var reactCreateClass = require('create-react-class');
var NavBar = reactCreateClass({
render: function () {
var that = this;
var signedInAs = function () {
if (that.props.loggedIn === true) {
return (
<p className="navbar-text">
Signed in as <b>{that.props.user.full_name}</b>
</p>
);
}
};
var dashboard = function () {
if (that.props.loggedIn === true) {
return (
<li>
<a target="_blank" href="https://wakatime.com/dashboard">
<i className="fa fa-fw fa-tachometer"></i>
Dashboard
</a>
</li>
);
}
};
var customRules = function () {
if (that.props.loggedIn === true) {
return (
<li>
<a target="_blank" href="https://wakatime.com/settings/rules">
<i className="fa fa-fw fa-filter"></i>
Custom Rules
</a>
</li>
);
}
};
return (
<nav className="navbar navbar-default" role="navigation">
<div className="container-fluid">
<div className="navbar-header">
<button
type="button"
className="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1"
>
<span className="sr-only">Toggle navigation</span>
<i className="fa fa-fw fa-cogs"></i>
</button>
<a target="_blank" className="navbar-brand" href="https://wakatime.com">
WakaTime
<img src="graphics/wakatime-logo-48.png" />
</a>
</div>
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
{signedInAs()}
<ul className="nav navbar-nav">
{customRules()}
{dashboard()}
<li className="dropdown">
<a
href="#"
className="dropdown-toggle"
data-toggle="dropdown"
role="button"
aria-expanded="false"
>
<i className="fa fa-fw fa-info"></i>
About
<span className="caret"></span>
</a>
<ul className="dropdown-menu" role="menu">
<li>
<a target="_blank" href="https://github.com/wakatime/chrome-wakatime/issues">
<i className="fa fa-fw fa-bug"></i>
Report an Issue
</a>
</li>
<li>
<a target="_blank" href="https://github.com/wakatime/chrome-wakatime">
<i className="fa fa-fw fa-github"></i>
View on GitHub
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
);
},
});
module.exports = NavBar;

View File

@@ -1,231 +0,0 @@
/* global browser */
var React = require('react');
var reactCreateClass = require('create-react-class');
var ReactCSSTransitionGroup = require('react-transition-group/CSSTransitionGroup');
var config = require('../config');
// React components
var Alert = require('./Alert.jsx');
var SitesList = require('./SitesList.jsx');
/**
* One thing to keep in mind is that you cannot use this.refs.blacklist if
* the blacklist select box is not being rendered on the form.
*
* @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,
};
},
componentDidMount: function () {
this.restoreSettings();
},
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;
});
},
_handleSubmit: function (e) {
e.preventDefault();
this.saveSettings();
},
saveSettings: function () {
var that = this;
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();
this.setState({ loggingStyle: loggingStyle });
},
_updateBlacklistState: function (sites) {
this.setState({
blacklist: sites,
});
},
_updateWhitelistState: function (sites) {
this.setState({
whitelist: sites,
});
},
render: function () {
var that = this;
var alert = function () {
if (that.state.displayAlert === true) {
setTimeout(function () {
that.setState({ displayAlert: false });
}, 2000);
return (
<Alert
key={that.state.alertText}
type={that.state.alertType}
text={that.state.alertText}
/>
);
}
};
var loggingStyle = function () {
if (that.state.loggingStyle == 'blacklist') {
return (
<SitesList
handleChange={that._updateBlacklistState}
label="Blacklist"
sites={that.state.blacklist}
helpText="Sites that you don't want to show in your reports."
/>
);
}
return (
<SitesList
handleChange={that._updateWhitelistState}
label="Whitelist"
sites={that.state.whitelist}
placeholder="http://google.com&#10;http://myproject.com/MyProject"
helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line."
/>
);
};
return (
<div className="container">
<div className="row">
<div className="col-md-12">
<ReactCSSTransitionGroup
transitionName="alert"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
>
{alert()}
</ReactCSSTransitionGroup>
<form className="form-horizontal" onSubmit={this._handleSubmit}>
<div className="form-group">
<label className="col-lg-2 control-label">Logging style</label>
<div className="col-lg-10">
<select
className="form-control"
ref="loggingStyle"
defaultValue="blacklist"
onChange={this._displayBlackOrWhiteList}
>
<option value="blacklist">All except blacklisted sites</option>
<option value="whitelist">Only whitelisted sites</option>
</select>
</div>
</div>
{loggingStyle()}
<div className="form-group">
<label className="col-lg-2 control-label">Logging type</label>
<div className="col-lg-10">
<select className="form-control" ref="loggingType" defaultValue="domain">
<option value="domain">Only the domain</option>
<option value="url">Entire URL</option>
</select>
</div>
</div>
<div className="form-group">
<label htmlFor="theme" className="col-lg-2 control-label">
Theme
</label>
<div className="col-lg-10">
<select className="form-control" ref="theme" defaultValue="light">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</div>
<div className="form-group">
<div className="col-lg-10 col-lg-offset-2">
<button type="submit" className="btn btn-primary">
Save
</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
},
});
module.exports = Options;

View File

@@ -1,44 +0,0 @@
var React = require('react');
var reactCreateClass = require('create-react-class');
var SitesList = reactCreateClass({
getDefaultProps: function () {
return {
placeholder: 'http://google.com',
};
},
_handleChange: function (event) {
var sites = event.target.value;
this.props.handleChange(sites);
},
render: function () {
return (
<div className="form-group">
<label htmlFor="sites" className="col-lg-2 control-label">
{this.props.label}
</label>
<div className="col-lg-10">
<textarea
className="form-control"
rows="3"
ref="sites"
onChange={this._handleChange}
placeholder={this.props.placeholder}
value={this.props.sites}
></textarea>
<span className="help-block">
{this.props.helpText}
<br />
One line per site.
</span>
</div>
</div>
);
},
});
module.exports = SitesList;

View File

@@ -1,163 +0,0 @@
/* global browser */
var React = require('react');
var reactCreateClass = require('create-react-class');
var $ = require('jquery');
var config = require('../config');
// React components
var NavBar = require('./NavBar.jsx');
var MainList = require('./MainList.jsx');
// Core
var WakaTimeCore = require('../core/WakaTimeCore').default;
// Helpers
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',
};
},
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');
}
});
},
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);
},
});
return deferredObject.promise();
},
_logoutUser: function () {
var that = this;
this.logoutUser().done(function () {
that.setState({
user: {
full_name: null,
email: null,
photo: null,
},
loggedIn: false,
loggingEnabled: false,
});
changeExtensionState('notSignedIn');
});
},
_disableLogging: function () {
this.setState({
loggingEnabled: false,
});
changeExtensionState('notLogging');
browser.storage.sync.set({
loggingEnabled: false,
});
},
_enableLogging: function () {
this.setState({
loggingEnabled: true,
});
changeExtensionState('allGood');
browser.storage.sync.set({
loggingEnabled: true,
});
},
render: function () {
return (
<div>
<NavBar user={this.state.user} loggedIn={this.state.loggedIn} />
<div className="container">
<div className="row">
<div className="col-md-12">
<MainList
disableLogging={this._disableLogging}
enableLogging={this._enableLogging}
loggingEnabled={this.state.loggingEnabled}
user={this.state.user}
totalTimeLoggedToday={this.state.totalTimeLoggedToday}
logoutUser={this._logoutUser}
loggedIn={this.state.loggedIn}
/>
</div>
</div>
</div>
</div>
);
},
});
module.exports = Wakatime;

View File

@@ -1,60 +0,0 @@
/* global browser */
//jshint esnext:true
var config = {
// 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!',
},
failure: {
type: 'danger',
text: 'There was an error while saving the options!',
},
},
};
module.exports = config;

View File

@@ -1,300 +0,0 @@
/* global browser */
//jshint esnext:true
var $ = require('jquery');
var moment = require('moment');
var config = require('./../config');
// Helpers
var getDomainFromUrl = require('./../helpers/getDomainFromUrl');
var changeExtensionState = require('../helpers/changeExtensionState');
var in_array = require('./../helpers/in_array');
var contains = require('./../helpers/contains');
class WakaTimeCore {
constructor() {
this.tabsWithDevtoolsOpen = [];
}
/**
* Settter for tabsWithDevtoolsOpen
*
* @param tabs
*/
setTabsWithDevtoolsOpen(tabs) {
this.tabsWithDevtoolsOpen = tabs;
}
getTotalTimeLoggedToday() {
var deferredObject = $.Deferred();
var today = moment().format('YYYY-MM-DD');
$.ajax({
url: config.summariesApiUrl + '?start=' + today + '&end=' + today,
dataType: 'json',
success: (data) => {
deferredObject.resolve(data.data[0].grand_total);
},
error: (xhr, status, err) => {
console.error(config.summariesApiUrl, status, err.toString());
deferredObject.resolve(false);
},
});
return deferredObject.promise();
}
/**
* Checks if the user is logged in.
*
* @returns {*}
*/
checkAuth() {
var deferredObject = $.Deferred();
$.ajax({
url: config.currentUserApiUrl,
dataType: 'json',
success: (data) => {
deferredObject.resolve(data.data);
},
error: (xhr, status, err) => {
console.error(config.currentUserApiUrl, status, err.toString());
deferredObject.resolve(false);
},
});
return deferredObject.promise();
}
/**
* Depending on various factors detects the current active tab URL or domain,
* and sends it to WakaTime for logging.
*/
recordHeartbeat() {
browser.storage.sync
.get({
loggingEnabled: config.loggingEnabled,
loggingStyle: config.loggingStyle,
blacklist: '',
whitelist: '',
})
.then((items) => {
if (items.loggingEnabled === true) {
changeExtensionState('allGood');
browser.idle.queryState(config.detectionIntervalInSeconds).then((newState) => {
if (newState === 'active') {
// Get current tab URL.
browser.tabs.query({ currentWindow: true, active: true }).then((tabs) => {
if (tabs.length == 0) return;
var currentActiveTab = tabs[0];
var debug = false;
// If the current active tab has devtools open
if (in_array(currentActiveTab.id, this.tabsWithDevtoolsOpen)) {
debug = true;
}
if (items.loggingStyle == 'blacklist') {
if (!contains(currentActiveTab.url, items.blacklist)) {
this.sendHeartbeat(
{
url: currentActiveTab.url,
project: null,
},
debug,
);
} else {
changeExtensionState('blacklisted');
console.log(currentActiveTab.url + ' is on a blacklist.');
}
}
if (items.loggingStyle == 'whitelist') {
var heartbeat = this.getHeartbeat(currentActiveTab.url, items.whitelist);
if (heartbeat.url) {
this.sendHeartbeat(heartbeat, debug);
} else {
changeExtensionState('whitelisted');
console.log(currentActiveTab.url + ' is not on a whitelist.');
}
}
});
}
});
} else {
changeExtensionState('notLogging');
}
});
}
/**
* Creates an array from list using \n as delimiter
* and checks if any element in list is contained in the url.
* Also checks if element is assigned to a project using @@ as delimiter
*
* @param url
* @param list
* @returns {object}
*/
getHeartbeat(url, list) {
var projectIndicatorCharacters = '@@';
var lines = list.split('\n');
for (var i = 0; i < lines.length; i++) {
// strip (http:// or https://) and trailing (`/` or `@@`)
var cleanLine = lines[i]
.trim()
.replace(/(\/|@@)$/, '')
.replace(/^(?:https?:\/\/)?/i, '');
if (cleanLine === '') continue;
var projectIndicatorIndex = cleanLine.lastIndexOf(projectIndicatorCharacters);
var projectIndicatorExists = projectIndicatorIndex > -1;
var projectName = null;
var urlFromLine = cleanLine;
if (projectIndicatorExists) {
var start = projectIndicatorIndex + projectIndicatorCharacters.length;
projectName = cleanLine.substring(start);
urlFromLine = cleanLine
.replace(cleanLine.substring(projectIndicatorIndex), '')
.replace(/\/$/, '');
}
var schemaHttpExists = url.match(/^http:\/\//i);
var schemaHttpsExists = url.match(/^https:\/\//i);
var schema = '';
if (schemaHttpExists) {
schema = 'http://';
}
if (schemaHttpsExists) {
schema = 'https://';
}
var cleanUrl = url
.trim()
.replace(/(\/|@@)$/, '')
.replace(/^(?:https?:\/\/)?/i, '');
var startsWithUrl = cleanUrl.toLowerCase().indexOf(urlFromLine.toLowerCase()) > -1;
if (startsWithUrl) {
return {
url: schema + urlFromLine,
project: projectName,
};
}
}
return {
url: null,
project: null,
};
}
/**
* Creates payload for the heartbeat and returns it as JSON.
*
* @param heartbeat
* @param type
* @param debug
* @returns {*}
* @private
*/
_preparePayload(heartbeat, type, debug = false) {
return JSON.stringify({
entity: heartbeat.url,
type: type,
time: moment().format('X'),
project: heartbeat.project || '<<LAST_PROJECT>>',
is_debugging: debug,
plugin: 'browser-wakatime/' + config.version,
});
}
/**
* Returns a promise with logging type variable.
*
* @returns {*}
* @private
*/
_getLoggingType() {
var deferredObject = $.Deferred();
browser.storage.sync
.get({
loggingType: config.loggingType,
})
.then(function (items) {
deferredObject.resolve(items.loggingType);
});
return deferredObject.promise();
}
/**
* Given the heartbeat and logging type it creates a payload and
* sends an ajax post request to the API.
*
* @param heartbeat
* @param debug
*/
sendHeartbeat(heartbeat, debug) {
var payload = null;
this._getLoggingType().done((loggingType) => {
// Get only the domain from the entity.
// And send that in heartbeat
if (loggingType == 'domain') {
heartbeat.url = getDomainFromUrl(heartbeat.url);
payload = this._preparePayload(heartbeat, 'domain', debug);
console.log(payload);
this.sendAjaxRequestToApi(payload);
}
// Send entity in heartbeat
else if (loggingType == 'url') {
payload = this._preparePayload(heartbeat, 'url', debug);
console.log(payload);
this.sendAjaxRequestToApi(payload);
}
});
}
/**
* Sends AJAX request with payload to the heartbeat API as JSON.
*
* @param payload
* @param method
* @returns {*}
*/
sendAjaxRequestToApi(payload, method = 'POST') {
var deferredObject = $.Deferred();
$.ajax({
url: config.heartbeatApiUrl,
dataType: 'json',
contentType: 'application/json',
method: method,
data: payload,
statusCode: {
401: function () {
changeExtensionState('notSignedIn');
},
201: function () {
// nothing to do here
},
},
success: (response) => {
deferredObject.resolve(this);
},
error: (xhr, status, err) => {
console.error(config.heartbeatApiUrl, status, err.toString());
deferredObject.resolve(this);
},
});
return deferredObject.promise();
}
}
export default WakaTimeCore;

View File

@@ -1,12 +0,0 @@
/* global browser */
// Create a connection to the background page
var backgroundPageConnection = browser.runtime.connect({
name: 'devtools-page',
});
// Send a message to background page with the current active tabId
backgroundPageConnection.postMessage({
name: 'init',
tabId: browser.devtools.inspectedWindow.tabId,
});

View File

@@ -1,101 +0,0 @@
/* global browser */
// Core
var WakaTimeCore = require('./core/WakaTimeCore').default;
// initialize class
var wakatime = new WakaTimeCore();
// Holds currently open connections (ports) with devtools
// Uses tabId as index key.
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') {
console.log('recording a heartbeat - alarm triggered');
wakatime.recordHeartbeat();
}
});
// Create a new alarm for heartbeats.
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');
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');
wakatime.recordHeartbeat();
} else {
console.log('lost focus');
}
});
/**
* 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.
*/
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');
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;
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();
});
}
});

View File

@@ -1,49 +0,0 @@
/* global browser */
var config = require('../config');
/**
* It changes the extension icon color.
* Supported values are: 'red', 'white', 'gray' and ''.
*
* @param color
*/
function changeExtensionIcon(color) {
color = color ? color : '';
var path = null;
if (color !== '') {
color = '-' + color;
path = './graphics/wakatime-logo-38' + color + '.png';
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';
browser.browserAction.setIcon({
path: path,
});
} else {
path = './graphics/wakatime-logo-38-white.png';
browser.browserAction.setIcon({
path: path,
});
}
});
}
}
module.exports = changeExtensionIcon;

View File

@@ -1,42 +0,0 @@
var config = require('../config');
// Helpers
var changeExtensionIcon = require('./changeExtensionIcon');
var changeExtensionTooltip = require('./changeExtensionTooltip');
var in_array = require('./in_array');
/**
* Sets the current state of the extension.
*
* @param state
*/
function changeExtensionState(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;
}
}
module.exports = changeExtensionState;

View File

@@ -1,20 +0,0 @@
/* global browser */
var config = require('../config');
/**
* It changes the extension title
*
* @param text
*/
function changeExtensionTooltip(text) {
if (text === '') {
text = config.name;
} else {
text = config.name + ' - ' + text;
}
browser.browserAction.setTitle({ title: text });
}
module.exports = changeExtensionTooltip;

View File

@@ -1,30 +0,0 @@
/**
* Creates an array from list using \n as delimiter
* and checks if any element in list is contained in the url.
*
* @param url
* @param list
* @returns {boolean}
*/
function contains(url, list) {
var lines = list.split('\n');
for (var i = 0; i < lines.length; i++) {
// 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;
var lineRe = new RegExp(cleanLine.replace('.', '.').replace('*', '.*'));
// If url matches the current line return true
if (lineRe.test(url)) {
return true;
}
}
return false;
}
module.exports = contains;

View File

@@ -1,13 +0,0 @@
/**
* Returns domain from given URL.
*
* @param url
* @returns {string}
*/
function getDomainFromUrl(url) {
var parts = url.split('/');
return parts[0] + '//' + parts[2];
}
module.exports = getDomainFromUrl;

View File

@@ -1,18 +0,0 @@
/**
* Returns boolean if needle is found in haystack or not.
*
* @param needle
* @param haystack
* @returns {boolean}
*/
function in_array(needle, haystack) {
for (var i = 0; i < haystack.length; i++) {
if (needle == haystack[i]) {
return true;
}
}
return false;
}
module.exports = in_array;

View File

@@ -1,13 +0,0 @@
/* global browser */
/* This is a fix for Bootstrap requiring jQuery */
global.jQuery = require('jquery');
require('bootstrap');
var React = require('react');
var ReactDOM = require('react-dom');
// React components
var Options = require('./components/Options.jsx');
ReactDOM.render(<Options />, document.getElementById('wakatime-options'));