Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ec4e0a69f2 | ||
|
52ae781960 | ||
|
c2f993db27 | ||
|
9f9b8be0f4 |
|
@ -706,5 +706,37 @@
|
|||
},
|
||||
"optionsCheck": {
|
||||
"message": "Update styles"
|
||||
},
|
||||
"scheduleButton": {
|
||||
"message": "Schedule"
|
||||
},
|
||||
"scheduleButtonActive": {
|
||||
"message": "Scheduled"
|
||||
},
|
||||
"scheduleTitle": {
|
||||
"message": "Add/Edit this schedule",
|
||||
"description": "Title for the messageBox"
|
||||
},
|
||||
"scheduleButtonRetry": {
|
||||
"message": "Retry",
|
||||
"description": "First button for the messageBox"
|
||||
},
|
||||
"scheduleButtonGiveUp": {
|
||||
"message": "I give up ",
|
||||
"description": "Second button for the messageBox"
|
||||
},
|
||||
"scheduleOneEntry": {
|
||||
"message": "Either clear both start and end values to disable the schedule or set both values to enable it",
|
||||
"description": "Description for the messageBox when only one time value is present"
|
||||
},
|
||||
"scheduleEqualEntries": {
|
||||
"message": "Start and end time values cannot be equal",
|
||||
"description": "Description for the messageBox when both start and end time values are equal"
|
||||
},
|
||||
"scheduleFrom": {
|
||||
"message": "From:"
|
||||
},
|
||||
"scheduleTo": {
|
||||
"message": "To:"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global dbExec, getStyles, saveStyle */
|
||||
/* global dbExec, getStyles, saveStyle, schedule, download */
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
|
@ -278,5 +278,10 @@ function onRuntimeMessage(request, sender, sendResponse) {
|
|||
.then(sendResponse)
|
||||
.catch(() => sendResponse(null));
|
||||
return KEEP_CHANNEL_OPEN;
|
||||
case 'schedule':
|
||||
schedule.entry(request)
|
||||
.then(() => sendResponse(true))
|
||||
.catch(() => sendResponse(false));
|
||||
return KEEP_CHANNEL_OPEN;
|
||||
}
|
||||
}
|
||||
|
|
30
manage.css
30
manage.css
|
@ -145,6 +145,36 @@ a:hover {
|
|||
margin-left: 1ex;
|
||||
}
|
||||
|
||||
.schedule {
|
||||
position: relative;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.schedule:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.schedule[data-edit=true],
|
||||
.schedule[data-active=true] {
|
||||
opacity: 1;
|
||||
}
|
||||
.schedule>input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.schedule span {
|
||||
margin: 0 5px;
|
||||
}
|
||||
.schedule>div {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 25%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.schedule[data-edit=false]>div {
|
||||
display: none;
|
||||
}
|
||||
.schedule[data-edit=true]>input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
summary {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
|
|
11
manage.html
11
manage.html
|
@ -57,6 +57,15 @@
|
|||
<div class="targets"></div>
|
||||
<span class="expander">...</span>
|
||||
</div>
|
||||
<div class="schedule" data-edit="false">
|
||||
<input type="button" i18n-value="scheduleButton" data-cmd="schedule">
|
||||
<div>
|
||||
<span i18n-text="scheduleFrom"></span>
|
||||
<input type="time">
|
||||
<span i18n-text="scheduleTo"></span>
|
||||
<input type="time">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -218,6 +227,8 @@
|
|||
|
||||
<script src="backup/fileSaveLoad.js"></script>
|
||||
<script src="msgbox/msgbox.js"></script>
|
||||
<script src="/schedule/core.js"></script>
|
||||
<script src="/schedule/ui.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -131,6 +131,7 @@ function showStyles(styles = []) {
|
|||
if (newUI.enabled && newUI.favicons) {
|
||||
debounce(handleEvent.loadFavicons, 16);
|
||||
}
|
||||
document.dispatchEvent(new Event('styles-ready'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,6 +437,10 @@ function handleUpdate(style, {reason, method} = {}) {
|
|||
$('.update-note', entry).textContent = t('updateCompleted');
|
||||
renderUpdatesOnlyFilter();
|
||||
}
|
||||
|
||||
document.dispatchEvent(new CustomEvent('style-edited', {
|
||||
detail: style
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,8 +18,12 @@
|
|||
"storage",
|
||||
"<all_urls>"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"idle",
|
||||
"alarms"
|
||||
],
|
||||
"background": {
|
||||
"scripts": ["messaging.js", "storage.js", "prefs.js", "background.js", "update.js"]
|
||||
"scripts": ["messaging.js", "storage.js", "prefs.js", "schedule/core.js" ,"background.js", "update.js"]
|
||||
},
|
||||
"commands": {
|
||||
"openManage": {
|
||||
|
|
119
schedule/core.js
Normal file
119
schedule/core.js
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* globals getStylesSafe, saveStyleSafe, BG */
|
||||
'use strict';
|
||||
|
||||
var SCHEDULE_PREFIX = 'schedule';
|
||||
|
||||
var schedule = {};
|
||||
|
||||
schedule.prefs = {
|
||||
name (id) {
|
||||
return SCHEDULE_PREFIX + '.' + id;
|
||||
},
|
||||
validate (name) {
|
||||
return name.startsWith(SCHEDULE_PREFIX + '.');
|
||||
},
|
||||
get (name, callback) {
|
||||
chrome.storage.local.get(name, callback);
|
||||
},
|
||||
getAll (callback) {
|
||||
schedule.prefs.get(null, prefs => {
|
||||
callback(
|
||||
Object.keys(prefs).filter(schedule.prefs.validate)
|
||||
.map(n => [n, prefs[n]])
|
||||
);
|
||||
});
|
||||
},
|
||||
set (name, value, callback = () => {}) {
|
||||
chrome.storage.local.set({
|
||||
[name]: value
|
||||
}, callback);
|
||||
},
|
||||
remove (name) {
|
||||
chrome.storage.local.remove(name);
|
||||
},
|
||||
subscribe (callback) {
|
||||
chrome.storage.onChanged.addListener(prefs => {
|
||||
Object.keys(prefs)
|
||||
.filter(n => prefs[n].newValue)
|
||||
.forEach(n => callback(n, prefs[n].newValue));
|
||||
});
|
||||
}
|
||||
};
|
||||
/* call this function when schedule timing is modified; if timing is not modified, nothing happens */
|
||||
schedule.entry = request => {
|
||||
console.log('schedule.entry', 'schedule timing might have been changed', request);
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.permissions.request({
|
||||
permissions: ['idle', 'alarms']
|
||||
}, (granted) => {
|
||||
if (granted) {
|
||||
schedule.prefs.set(schedule.prefs.name(request.id), {
|
||||
id: request.id,
|
||||
start: request.start,
|
||||
end: request.end,
|
||||
enabled: request.enabled
|
||||
}, resolve);
|
||||
}
|
||||
else {
|
||||
reject(new Error('Required permissions are not granted'));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
/* call this to update current alarm. If request.enabled = false, then alarm is cleared and this job will be removed from the storage */
|
||||
schedule.execute = (name, request) => {
|
||||
console.log('schedule.execute', 'evaluating response', name, request);
|
||||
chrome.alarms.clear(name, () => {
|
||||
if (request.enabled) {
|
||||
const now = new Date();
|
||||
let start = new Date(now.toDateString() + ' ' + request.start).getTime() - now;
|
||||
let end = new Date(now.toDateString() + ' ' + request.end).getTime() - now;
|
||||
const when = now.getTime() + Math.min(
|
||||
start < 0 ? start + 24 * 60 * 60 * 1000 : start,
|
||||
end < 0 ? end + 24 * 60 * 60 * 1000 : end
|
||||
);
|
||||
console.log(`next alarm is set for id = ${request.id}`, new Date(when), start, end);
|
||||
chrome.alarms.create(name, {when});
|
||||
getStylesSafe({id: request.id}).then(([style]) => {
|
||||
if (style) {
|
||||
const enabled = (start <= 0 && end > 0) || (start > end && start * end > 0) ;
|
||||
console.log(`style with id = ${style.id}; enabled = `, enabled);
|
||||
|
||||
saveStyleSafe({
|
||||
id: request.id,
|
||||
enabled
|
||||
});
|
||||
}
|
||||
else {
|
||||
// clear schedule if style is not found
|
||||
console.log('removing from storage since style is not found', request);
|
||||
schedule.execute(name, Object.assign(
|
||||
request, {enabled: false}
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log('removing pref since request.enabled is false', name);
|
||||
schedule.prefs.remove(name);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// background only
|
||||
if (BG === window) {
|
||||
// listen for pref changes to update chrome.alarms
|
||||
schedule.prefs.subscribe((name, pref) => schedule.prefs.validate(name) && schedule.execute(name, pref));
|
||||
|
||||
chrome.alarms.onAlarm.addListener(({name}) => {
|
||||
schedule.prefs.get(name, prefs => prefs[name] && schedule.execute(name, prefs[name]));
|
||||
});
|
||||
|
||||
(function (callback) {
|
||||
chrome.idle.onStateChanged.addListener(state => state === 'active' && callback());
|
||||
window.setTimeout(callback);
|
||||
})(function () {
|
||||
console.log('updating all schedules');
|
||||
schedule.prefs.getAll(prefs => prefs.forEach(a => schedule.execute(...a)));
|
||||
});
|
||||
}
|
107
schedule/ui.js
Normal file
107
schedule/ui.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* global t, schedule, $, $$, messageBox */
|
||||
'use strict';
|
||||
|
||||
schedule.ui = {};
|
||||
|
||||
/* get start and end inputs */
|
||||
schedule.ui.inputs = (parent) => $$('input[type=time]', parent);
|
||||
|
||||
/* updating schedule section of a single style */
|
||||
schedule.ui.update = (request) => {
|
||||
console.log('updating schedule ui', request);
|
||||
const parent = $(`[id="style-${request.id}"] .schedule`);
|
||||
if (parent) {
|
||||
parent.dataset.active = request.enabled;
|
||||
$('input[type=button]', parent).value = t(request.enabled ? 'scheduleButtonActive' : 'scheduleButton');
|
||||
const [start, end] = schedule.ui.inputs(parent);
|
||||
start.value = request.start;
|
||||
end.value = request.end;
|
||||
}
|
||||
};
|
||||
|
||||
/* display schedule panel and hide it when user selects outside area */
|
||||
document.addEventListener('click', e => {
|
||||
const target = e.target;
|
||||
let parent;
|
||||
// hide schedule panel
|
||||
function observe (e) {
|
||||
if (!parent.contains(e.target)) {
|
||||
const [start, end] = schedule.ui.inputs(parent);
|
||||
const id = target.closest('.entry').id.replace('style-', '');
|
||||
let len = [start.value, end.value].filter(v => v).length;
|
||||
len = len === 2 && start.value === end.value ? 3 : len;
|
||||
switch (len) {
|
||||
case 0: // reset schedule for this id
|
||||
chrome.runtime.sendMessage({
|
||||
method: 'schedule',
|
||||
enabled: false,
|
||||
id
|
||||
}, () => {
|
||||
schedule.ui.update({ // reset UI
|
||||
enabled: false,
|
||||
id,
|
||||
start: '',
|
||||
end: ''
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 3: // when both start and end have equal values
|
||||
case 1: // when only start or end value is set
|
||||
return messageBox({
|
||||
title: t('scheduleTitle'),
|
||||
contents: t(len === 1 ? 'scheduleOneEntry' : 'scheduleEqualEntries'),
|
||||
buttons: [t('scheduleButtonGiveUp'), t('scheduleButtonRetry')],
|
||||
onshow: e => e.addEventListener('click', e => e.stopPropagation())
|
||||
}).then((r) => {
|
||||
if (r.button === 1 && len === 1) { // retry
|
||||
[start, end].filter(o => !o.value).forEach(o => o.focus());
|
||||
}
|
||||
else if (r.button === 1 && len === 3) {
|
||||
start.focus();
|
||||
}
|
||||
else {
|
||||
// clear and hide UI
|
||||
start.value = end.value = '';
|
||||
document.body.click();
|
||||
}
|
||||
});
|
||||
default:
|
||||
chrome.runtime.sendMessage({
|
||||
method: 'schedule',
|
||||
enabled: true,
|
||||
id,
|
||||
start: start.value,
|
||||
end: end.value
|
||||
}, () => {});
|
||||
}
|
||||
|
||||
document.removeEventListener('click', observe);
|
||||
parent.dataset.edit = false;
|
||||
}
|
||||
}
|
||||
// display schedule panel
|
||||
if (target.dataset.cmd === 'schedule') {
|
||||
parent = target.closest('div');
|
||||
parent.dataset.edit = true;
|
||||
document.addEventListener('click', observe);
|
||||
}
|
||||
});
|
||||
/* update schedule section on styles ready */
|
||||
document.addEventListener('styles-ready', () => {
|
||||
console.log('"styles-ready" is called');
|
||||
schedule.prefs.getAll(prefs => {
|
||||
prefs.forEach(([name, pref]) => schedule.ui.update(pref));
|
||||
});
|
||||
});
|
||||
/* update schedule section on style change */
|
||||
document.addEventListener('style-edited', e => {
|
||||
console.log('"style-edited" is called');
|
||||
const id = e.detail.id;
|
||||
const name = schedule.prefs.name(id);
|
||||
schedule.prefs.get(name, prefs => {
|
||||
const pref = prefs[name];
|
||||
if (pref) {
|
||||
schedule.ui.update(pref);
|
||||
}
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user