Initial work to get working in Firefox

This commit is contained in:
Nathaniel van Diepen
2016-12-14 13:55:43 -07:00
parent 628d6eb2f1
commit 9823acc03f
81 changed files with 5501 additions and 5496 deletions

View File

@@ -1,15 +1,15 @@
/* 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')
);
/* 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,19 +1,19 @@
var React = require('react');
var classNames = require('classnames');
var Alert = React.createClass({
propTypes: {
type: React.PropTypes.string.isRequired,
text: React.PropTypes.string.isRequired
},
render: function() {
return(
<div className={classNames('alert', 'alert-' + this.props.type)}>{this.props.text}</div>
);
}
});
module.exports = Alert;
var React = require('react');
var classNames = require('classnames');
var Alert = React.createClass({
propTypes: {
type: React.PropTypes.string.isRequired,
text: React.PropTypes.string.isRequired
},
render: function() {
return(
<div className={classNames('alert', 'alert-' + this.props.type)}>{this.props.text}</div>
);
}
});
module.exports = Alert;

View File

@@ -1,106 +1,106 @@
/* global chrome */
var React = require('react');
var MainList = React.createClass({
_openOptionsPage: function() {
if (chrome.runtime.openOptionsPage) {
// New way to open options pages, if supported (Chrome 42+).
chrome.runtime.openOptionsPage();
} else {
// Reasonable fallback.
window.open(chrome.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;
/* global browser */
var React = require('react');
var MainList = React.createClass({
_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,89 +1,89 @@
var React = require('react');
var NavBar = React.createClass({
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;
var React = require('react');
var NavBar = React.createClass({
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,214 +1,214 @@
/* global chrome */
var React = require('react');
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
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 = React.createClass({
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;
chrome.storage.sync.get({
theme: config.theme,
blacklist: '',
whitelist: '',
loggingType: config.loggingType,
loggingStyle: config.loggingStyle
}, 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.
chrome.storage.sync.set({
theme: theme,
blacklist: blacklist,
whitelist: whitelist,
loggingType: loggingType,
loggingStyle: loggingStyle
}, 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}
helpText="Sites that you want to show in your reports." />
);
};
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;
/* global browser */
var React = require('react');
var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
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 = React.createClass({
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}
helpText="Sites that you want to show in your reports." />
);
};
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,35 +1,35 @@
var React = require('react');
var SitesList = React.createClass({
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;
var React = require('react');
var SitesList = React.createClass({
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,173 +1,173 @@
/* global chrome */
var React = require("react");
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 = React.createClass({
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) {
chrome.storage.sync.get({
loggingEnabled: config.loggingEnabled
}, 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
});
});
}
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');
chrome.storage.sync.set({
loggingEnabled: false
});
},
_enableLogging: function() {
this.setState({
loggingEnabled: true
});
changeExtensionState('allGood');
chrome.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;
/* global browser */
var React = require("react");
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 = React.createClass({
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
});
});
}
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,67 +1,67 @@
/* global chrome */
//jshint esnext:true
var config = {
// Extension name
name: 'WakaTime',
// Extension version
version: chrome.app.getDetails().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://api.wakatime.com/api/v1/users/current/heartbeats',
// Url from which to detect if the user is logged in
currentUserApiUrl: 'https://api.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://api.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;
/* 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://api.wakatime.com/api/v1/users/current/heartbeats',
// Url from which to detect if the user is logged in
currentUserApiUrl: 'https://api.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://api.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,256 +1,256 @@
/* global chrome */
//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() {
chrome.storage.sync.get({
loggingEnabled: config.loggingEnabled,
loggingStyle: config.loggingStyle,
blacklist: '',
whitelist: ''
}, (items) => {
if (items.loggingEnabled === true) {
changeExtensionState('allGood');
chrome.idle.queryState(config.detectionIntervalInSeconds, (newState) => {
if (newState === 'active') {
// Get current tab URL.
chrome.tabs.query({active: true}, (tabs) => {
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(currentActiveTab.url, debug);
}
else {
changeExtensionState('blacklisted');
console.log(currentActiveTab.url + ' is on a blacklist.');
}
}
if (items.loggingStyle == 'whitelist') {
if (contains(currentActiveTab.url, items.whitelist)) {
this.sendHeartbeat(currentActiveTab.url, debug);
}
else {
changeExtensionState('whitelisted');
console.log(currentActiveTab.url + ' is not on a whitelist.');
}
}
});
}
});
}
else {
changeExtensionState('notLogging');
}
});
}
/**
* Creates payload for the heartbeat and returns it as JSON.
*
* @param entity
* @param type
* @param debug
* @returns {*}
* @private
*/
_preparePayload(entity, type, debug = false) {
return JSON.stringify({
entity: entity,
type: type,
time: moment().format('X'),
project: '<<LAST_PROJECT>>',
is_debugging: debug,
plugin: 'chrome-wakatime/' + config.version
});
}
/**
* Returns a promise with logging type variable.
*
* @returns {*}
* @private
*/
_getLoggingType() {
var deferredObject = $.Deferred();
chrome.storage.sync.get({
loggingType: config.loggingType
}, function (items) {
deferredObject.resolve(items.loggingType);
});
return deferredObject.promise();
}
/**
* Given the entity and logging type it creates a payload and
* sends an ajax post request to the API.
*
* @param entity
* @param debug
*/
sendHeartbeat(entity, debug) {
var payload = null;
this._getLoggingType().done((loggingType) => {
// Get only the domain from the entity.
// And send that in heartbeat
if (loggingType == 'domain') {
var domain = getDomainFromUrl(entity);
payload = this._preparePayload(domain, 'domain', debug);
console.log(payload);
this.sendAjaxRequestToApi(payload);
}
// Send entity in heartbeat
else if (loggingType == 'url') {
payload = this._preparePayload(entity, '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;
/* 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({active: true}).then((tabs) => {
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(currentActiveTab.url, debug);
}
else {
changeExtensionState('blacklisted');
console.log(currentActiveTab.url + ' is on a blacklist.');
}
}
if (items.loggingStyle == 'whitelist') {
if (contains(currentActiveTab.url, items.whitelist)) {
this.sendHeartbeat(currentActiveTab.url, debug);
}
else {
changeExtensionState('whitelisted');
console.log(currentActiveTab.url + ' is not on a whitelist.');
}
}
});
}
});
}
else {
changeExtensionState('notLogging');
}
});
}
/**
* Creates payload for the heartbeat and returns it as JSON.
*
* @param entity
* @param type
* @param debug
* @returns {*}
* @private
*/
_preparePayload(entity, type, debug = false) {
return JSON.stringify({
entity: entity,
type: type,
time: moment().format('X'),
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 entity and logging type it creates a payload and
* sends an ajax post request to the API.
*
* @param entity
* @param debug
*/
sendHeartbeat(entity, debug) {
var payload = null;
this._getLoggingType().done((loggingType) => {
// Get only the domain from the entity.
// And send that in heartbeat
if (loggingType == 'domain') {
var domain = getDomainFromUrl(entity);
payload = this._preparePayload(domain, 'domain', debug);
console.log(payload);
this.sendAjaxRequestToApi(payload);
}
// Send entity in heartbeat
else if (loggingType == 'url') {
payload = this._preparePayload(entity, '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 +1,12 @@
/* global chrome */
// Create a connection to the background page
var backgroundPageConnection = chrome.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
});
/* 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,100 +1,100 @@
/* global chrome */
// 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
chrome.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.
chrome.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) {
chrome.tabs.get(activeInfo.tabId, function (tab) {
console.log('recording a heartbeat - active tab changed');
wakatime.recordHeartbeat();
});
});
/**
* 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) {
if (changeInfo.status === 'complete') {
// Get current tab URL.
chrome.tabs.query({active: true}, 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.
*/
chrome.runtime.onConnect.addListener(function (port) {
if (port.name == "devtools-page") {
// Listen to messages sent from the DevTools page
port.onMessage.addListener(function (message, sender, sendResponse) {
if (message.name == "init") {
connections[message.tabId] = port;
wakatime.setTabsWithDevtoolsOpen(Object.keys(connections));
wakatime.recordHeartbeat();
}
});
port.onDisconnect.addListener(function (port) {
var tabs = Object.keys(connections);
for (var i = 0, len = tabs.length; i < len; i ++) {
if (connections[tabs[i]] == port) {
delete connections[tabs[i]];
break;
}
}
wakatime.setTabsWithDevtoolsOpen(Object.keys(connections));
wakatime.recordHeartbeat();
});
}
});
/* 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 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({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,50 +1,50 @@
/* global chrome */
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';
chrome.browserAction.setIcon({
path: path
});
}
if (color === '') {
chrome.storage.sync.get({
theme: config.theme
}, function (items) {
if (items.theme == config.theme) {
path = './graphics/wakatime-logo-38.png';
chrome.browserAction.setIcon({
path: path
});
}
else {
path = './graphics/wakatime-logo-38-white.png';
chrome.browserAction.setIcon({
path: path
});
}
});
}
}
module.exports = changeExtensionIcon;
/* 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 +1,42 @@
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;
}
}
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,22 +1,22 @@
/* global chrome */
var config = require('../config');
/**
* It changes the extension title
*
* @param text
*/
function changeExtensionTooltip(text) {
if (text === '') {
text = config.name;
}
else {
text = config.name + ' - ' + text;
}
chrome.browserAction.setTitle({title: text});
}
/* 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,29 +1,29 @@
/**
* 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;
// If url contains the current line return true
if (url.indexOf(cleanLine) > -1) {
return true;
}
}
return false;
}
module.exports = contains;
/**
* 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;
// If url contains the current line return true
if (url.indexOf(cleanLine) > -1) {
return true;
}
}
return false;
}
module.exports = contains;

View File

@@ -1,13 +1,13 @@
/**
* Returns domain from given URL.
*
* @param url
* @returns {string}
*/
function getDomainFromUrl(url) {
var parts = url.split('/');
return parts[0] + "//" + parts[2];
}
/**
* 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 +1,18 @@
/**
* 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;
}
/**
* 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,16 +1,16 @@
/* global chrome */
/* 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')
);
/* 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')
);

View File

@@ -1,30 +1,30 @@
@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;
}
a.navbar-brand {
img {
margin-top: -12px;
float: left;
margin-right: 7px;
}
}
div.container {
margin-top: 20px;
}
canvas#icon {
display: none;
}
div#status {
display: none;
}
@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;
}
a.navbar-brand {
img {
margin-top: -12px;
float: left;
margin-right: 7px;
}
}
div.container {
margin-top: 20px;
}
canvas#icon {
display: none;
}
div#status {
display: none;
}

View File

@@ -1,304 +1,304 @@
{
"always-semicolon": true,
"block-indent": 2,
"color-case": "lower",
"color-shorthand": true,
"element-case": "lower",
"eof-newline": true,
"leading-zero": false,
"remove-empty-rulesets": true,
"space-after-colon": 1,
"space-after-combinator": 1,
"space-before-selector-delimiter": 0,
"space-between-declarations": "\n",
"space-after-opening-brace": "\n",
"space-before-closing-brace": "\n",
"space-before-colon": 0,
"space-before-combinator": 1,
"space-before-opening-brace": 1,
"strip-spaces": true,
"unitless-zero": true,
"vendor-prefix-align": true,
"sort-order": [
[
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"float",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"-webkit-appearance",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"overflow",
"overflow-x",
"overflow-y",
"-webkit-overflow-scrolling",
"-ms-overflow-x",
"-ms-overflow-y",
"-ms-overflow-style",
"clip",
"clear",
"font",
"font-family",
"font-size",
"font-style",
"font-weight",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"line-height",
"color",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-decoration",
"text-indent",
"text-justify",
"text-outline",
"-ms-text-overflow",
"text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"text-shadow",
"text-transform",
"text-wrap",
"-webkit-text-size-adjust",
"-ms-text-size-adjust",
"letter-spacing",
"-ms-word-break",
"word-break",
"word-spacing",
"-ms-word-wrap",
"word-wrap",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"white-space",
"vertical-align",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image",
"pointer-events",
"-ms-touch-action",
"touch-action",
"cursor",
"visibility",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align",
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"-webkit-user-select",
"-moz-user-select",
"-ms-user-select",
"-o-user-select",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"background",
"background-color",
"background-image",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
"filter:progid:DXImageTransform.Microsoft.gradient",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"filter",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"border",
"border-color",
"border-style",
"border-width",
"border-top",
"border-top-color",
"border-top-style",
"border-top-width",
"border-right",
"border-right-color",
"border-right-style",
"border-right-width",
"border-bottom",
"border-bottom-color",
"border-bottom-style",
"border-bottom-width",
"border-left",
"border-left-color",
"border-left-style",
"border-left-width",
"border-radius",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"opacity",
"-ms-interpolation-mode",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction"
]
]
}
{
"always-semicolon": true,
"block-indent": 2,
"color-case": "lower",
"color-shorthand": true,
"element-case": "lower",
"eof-newline": true,
"leading-zero": false,
"remove-empty-rulesets": true,
"space-after-colon": 1,
"space-after-combinator": 1,
"space-before-selector-delimiter": 0,
"space-between-declarations": "\n",
"space-after-opening-brace": "\n",
"space-before-closing-brace": "\n",
"space-before-colon": 0,
"space-before-combinator": 1,
"space-before-opening-brace": 1,
"strip-spaces": true,
"unitless-zero": true,
"vendor-prefix-align": true,
"sort-order": [
[
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"float",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"-webkit-appearance",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"overflow",
"overflow-x",
"overflow-y",
"-webkit-overflow-scrolling",
"-ms-overflow-x",
"-ms-overflow-y",
"-ms-overflow-style",
"clip",
"clear",
"font",
"font-family",
"font-size",
"font-style",
"font-weight",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"line-height",
"color",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-decoration",
"text-indent",
"text-justify",
"text-outline",
"-ms-text-overflow",
"text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"text-shadow",
"text-transform",
"text-wrap",
"-webkit-text-size-adjust",
"-ms-text-size-adjust",
"letter-spacing",
"-ms-word-break",
"word-break",
"word-spacing",
"-ms-word-wrap",
"word-wrap",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"white-space",
"vertical-align",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image",
"pointer-events",
"-ms-touch-action",
"touch-action",
"cursor",
"visibility",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align",
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"-webkit-user-select",
"-moz-user-select",
"-ms-user-select",
"-o-user-select",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"background",
"background-color",
"background-image",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
"filter:progid:DXImageTransform.Microsoft.gradient",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"filter",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"border",
"border-color",
"border-style",
"border-width",
"border-top",
"border-top-color",
"border-top-style",
"border-top-width",
"border-right",
"border-right-color",
"border-right-style",
"border-right-width",
"border-bottom",
"border-bottom-color",
"border-bottom-style",
"border-bottom-width",
"border-left",
"border-left-color",
"border-left-style",
"border-left-width",
"border-radius",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"opacity",
"-ms-interpolation-mode",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction"
]
]
}

View File

@@ -1,19 +1,19 @@
{
"adjoining-classes": false,
"box-sizing": false,
"box-model": false,
"compatible-vendor-prefixes": false,
"floats": false,
"font-sizes": false,
"gradients": false,
"important": false,
"known-properties": false,
"outline-none": false,
"qualified-headings": false,
"regex-selectors": false,
"shorthand": false,
"text-indent": false,
"unique-headings": false,
"universal-selector": false,
"unqualified-attributes": false
}
{
"adjoining-classes": false,
"box-sizing": false,
"box-model": false,
"compatible-vendor-prefixes": false,
"floats": false,
"font-sizes": false,
"gradients": false,
"important": false,
"known-properties": false,
"outline-none": false,
"qualified-headings": false,
"regex-selectors": false,
"shorthand": false,
"text-indent": false,
"unique-headings": false,
"universal-selector": false,
"unqualified-attributes": false
}

View File

@@ -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)
*/

View File

@@ -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);

View File

@@ -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"],

View File

@@ -29,7 +29,7 @@
width: 100%;
margin-bottom: 0;
&:focus {
z-index: 3;
}

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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;

View File

@@ -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)
*/

View File

@@ -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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,34 @@
// Animated Icons
// --------------------------
.@{fa-css-prefix}-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.@{fa-css-prefix}-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
// Animated Icons
// --------------------------
.@{fa-css-prefix}-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.@{fa-css-prefix}-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}

View File

@@ -1,25 +1,25 @@
// Bordered & Pulled
// -------------------------
.@{fa-css-prefix}-border {
padding: .2em .25em .15em;
border: solid .08em @fa-border-color;
border-radius: .1em;
}
.@{fa-css-prefix}-pull-left { float: left; }
.@{fa-css-prefix}-pull-right { float: right; }
.@{fa-css-prefix} {
&.@{fa-css-prefix}-pull-left { margin-right: .3em; }
&.@{fa-css-prefix}-pull-right { margin-left: .3em; }
}
/* Deprecated as of 4.4.0 */
.pull-right { float: right; }
.pull-left { float: left; }
.@{fa-css-prefix} {
&.pull-left { margin-right: .3em; }
&.pull-right { margin-left: .3em; }
}
// Bordered & Pulled
// -------------------------
.@{fa-css-prefix}-border {
padding: .2em .25em .15em;
border: solid .08em @fa-border-color;
border-radius: .1em;
}
.@{fa-css-prefix}-pull-left { float: left; }
.@{fa-css-prefix}-pull-right { float: right; }
.@{fa-css-prefix} {
&.@{fa-css-prefix}-pull-left { margin-right: .3em; }
&.@{fa-css-prefix}-pull-right { margin-left: .3em; }
}
/* Deprecated as of 4.4.0 */
.pull-right { float: right; }
.pull-left { float: left; }
.@{fa-css-prefix} {
&.pull-left { margin-right: .3em; }
&.pull-right { margin-left: .3em; }
}

View File

@@ -1,12 +1,12 @@
// Base Class Definition
// -------------------------
.@{fa-css-prefix} {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Base Class Definition
// -------------------------
.@{fa-css-prefix} {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@@ -1,6 +1,6 @@
// Fixed Width Icons
// -------------------------
.@{fa-css-prefix}-fw {
width: (18em / 14);
text-align: center;
}
// Fixed Width Icons
// -------------------------
.@{fa-css-prefix}-fw {
width: (18em / 14);
text-align: center;
}

View File

@@ -1,18 +1,18 @@
/*!
* Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@import "variables.less";
@import "mixins.less";
@import "path.less";
@import "core.less";
@import "larger.less";
@import "fixed-width.less";
@import "list.less";
@import "bordered-pulled.less";
@import "animated.less";
@import "rotated-flipped.less";
@import "stacked.less";
@import "icons.less";
@import "screen-reader.less";
/*!
* Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@import "variables.less";
@import "mixins.less";
@import "path.less";
@import "core.less";
@import "larger.less";
@import "fixed-width.less";
@import "list.less";
@import "bordered-pulled.less";
@import "animated.less";
@import "rotated-flipped.less";
@import "stacked.less";
@import "icons.less";
@import "screen-reader.less";

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
// Icon Sizes
// -------------------------
/* makes the font 33% larger relative to the icon container */
.@{fa-css-prefix}-lg {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.@{fa-css-prefix}-2x { font-size: 2em; }
.@{fa-css-prefix}-3x { font-size: 3em; }
.@{fa-css-prefix}-4x { font-size: 4em; }
.@{fa-css-prefix}-5x { font-size: 5em; }
// Icon Sizes
// -------------------------
/* makes the font 33% larger relative to the icon container */
.@{fa-css-prefix}-lg {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.@{fa-css-prefix}-2x { font-size: 2em; }
.@{fa-css-prefix}-3x { font-size: 3em; }
.@{fa-css-prefix}-4x { font-size: 4em; }
.@{fa-css-prefix}-5x { font-size: 5em; }

View File

@@ -1,19 +1,19 @@
// List Icons
// -------------------------
.@{fa-css-prefix}-ul {
padding-left: 0;
margin-left: @fa-li-width;
list-style-type: none;
> li { position: relative; }
}
.@{fa-css-prefix}-li {
position: absolute;
left: -@fa-li-width;
width: @fa-li-width;
top: (2em / 14);
text-align: center;
&.@{fa-css-prefix}-lg {
left: (-@fa-li-width + (4em / 14));
}
}
// List Icons
// -------------------------
.@{fa-css-prefix}-ul {
padding-left: 0;
margin-left: @fa-li-width;
list-style-type: none;
> li { position: relative; }
}
.@{fa-css-prefix}-li {
position: absolute;
left: -@fa-li-width;
width: @fa-li-width;
top: (2em / 14);
text-align: center;
&.@{fa-css-prefix}-lg {
left: (-@fa-li-width + (4em / 14));
}
}

View File

@@ -1,60 +1,60 @@
// Mixins
// --------------------------
.fa-icon() {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-icon-rotate(@degrees, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
-webkit-transform: rotate(@degrees);
-ms-transform: rotate(@degrees);
transform: rotate(@degrees);
}
.fa-icon-flip(@horiz, @vert, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
-webkit-transform: scale(@horiz, @vert);
-ms-transform: scale(@horiz, @vert);
transform: scale(@horiz, @vert);
}
// Only display content to screen readers. A la Bootstrap 4.
//
// See: http://a11yproject.com/posts/how-to-hide-content/
.sr-only() {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
// Use in conjunction with .sr-only to only display content when it's focused.
//
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
//
// Credit: HTML5 Boilerplate
.sr-only-focusable() {
&:active,
&:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
}
// Mixins
// --------------------------
.fa-icon() {
display: inline-block;
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
font-size: inherit; // can't have font-size inherit on line above, so need to override
text-rendering: auto; // optimizelegibility throws things off #1094
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-icon-rotate(@degrees, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
-webkit-transform: rotate(@degrees);
-ms-transform: rotate(@degrees);
transform: rotate(@degrees);
}
.fa-icon-flip(@horiz, @vert, @rotation) {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
-webkit-transform: scale(@horiz, @vert);
-ms-transform: scale(@horiz, @vert);
transform: scale(@horiz, @vert);
}
// Only display content to screen readers. A la Bootstrap 4.
//
// See: http://a11yproject.com/posts/how-to-hide-content/
.sr-only() {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
// Use in conjunction with .sr-only to only display content when it's focused.
//
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
//
// Credit: HTML5 Boilerplate
.sr-only-focusable() {
&:active,
&:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
}

View File

@@ -1,15 +1,15 @@
/* FONT PATH
* -------------------------- */
@font-face {
font-family: 'FontAwesome';
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;
}
/* FONT PATH
* -------------------------- */
@font-face {
font-family: 'FontAwesome';
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;
}

View File

@@ -1,20 +1,20 @@
// Rotated & Flipped Icons
// -------------------------
.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
// Hook for IE8-9
// -------------------------
:root .@{fa-css-prefix}-rotate-90,
:root .@{fa-css-prefix}-rotate-180,
:root .@{fa-css-prefix}-rotate-270,
:root .@{fa-css-prefix}-flip-horizontal,
:root .@{fa-css-prefix}-flip-vertical {
filter: none;
}
// Rotated & Flipped Icons
// -------------------------
.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
// Hook for IE8-9
// -------------------------
:root .@{fa-css-prefix}-rotate-90,
:root .@{fa-css-prefix}-rotate-180,
:root .@{fa-css-prefix}-rotate-270,
:root .@{fa-css-prefix}-flip-horizontal,
:root .@{fa-css-prefix}-flip-vertical {
filter: none;
}

View File

@@ -1,5 +1,5 @@
// Screen Readers
// -------------------------
.sr-only { .sr-only(); }
.sr-only-focusable { .sr-only-focusable(); }
// Screen Readers
// -------------------------
.sr-only { .sr-only(); }
.sr-only-focusable { .sr-only-focusable(); }

View File

@@ -1,20 +1,20 @@
// Stacked Icons
// -------------------------
.@{fa-css-prefix}-stack {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
line-height: 2em;
vertical-align: middle;
}
.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
position: absolute;
left: 0;
width: 100%;
text-align: center;
}
.@{fa-css-prefix}-stack-1x { line-height: inherit; }
.@{fa-css-prefix}-stack-2x { font-size: 2em; }
.@{fa-css-prefix}-inverse { color: @fa-inverse; }
// Stacked Icons
// -------------------------
.@{fa-css-prefix}-stack {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
line-height: 2em;
vertical-align: middle;
}
.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
position: absolute;
left: 0;
width: 100%;
text-align: center;
}
.@{fa-css-prefix}-stack-1x { line-height: inherit; }
.@{fa-css-prefix}-stack-2x { font-size: 2em; }
.@{fa-css-prefix}-inverse { color: @fa-inverse; }

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,17 @@
.alert-enter {
opacity: 0.01;
transition: opacity 1s ease-in;
}
.alert-enter.alert-enter-active {
opacity: 1;
}
.alert-leave {
opacity: 1;
transition: opacity 1s ease-in;
}
.alert-leave.alert-leave-active {
opacity: 0.01;
.alert-enter {
opacity: 0.01;
transition: opacity 1s ease-in;
}
.alert-enter.alert-enter-active {
opacity: 1;
}
.alert-leave {
opacity: 1;
transition: opacity 1s ease-in;
}
.alert-leave.alert-leave-active {
opacity: 0.01;
}

View File

@@ -1,14 +1,14 @@
::-webkit-scrollbar {
height: 12px;
width: 12px;
background: @body-bg;
}
::-webkit-scrollbar-thumb {
background: @brand-primary;
-webkit-border-radius: 0;
}
::-webkit-scrollbar-corner {
background: #000;
}
::-webkit-scrollbar {
height: 12px;
width: 12px;
background: @body-bg;
}
::-webkit-scrollbar-thumb {
background: @brand-primary;
-webkit-border-radius: 0;
}
::-webkit-scrollbar-corner {
background: #000;
}

View File

@@ -1,2 +1,2 @@
@navbar-margin-bottom: 0px;
@navbar-border-radius: 0px;
@navbar-margin-bottom: 0px;
@navbar-border-radius: 0px;