scheduler implementation part/2

This commit is contained in:
Jeremy Schomery 2017-05-03 19:19:40 +04:30
parent 9f9b8be0f4
commit c2f993db27
5 changed files with 72 additions and 50 deletions

View File

@ -279,8 +279,7 @@ function onRuntimeMessage(request, sender, sendResponse) {
.catch(() => sendResponse(null));
return KEEP_CHANNEL_OPEN;
case 'schedule':
schedule.entry(request)
.then(sendResponse)
.catch(e => sendResponse(e));
schedule.entry(request);
return KEEP_CHANNEL_OPEN;
}
}

View File

@ -226,8 +226,8 @@
<script src="backup/fileSaveLoad.js"></script>
<script src="msgbox/msgbox.js"></script>
<script src="/schedule/ui.js"></script>
<script src="/schedule/core.js"></script>
<script src="/schedule/ui.js"></script>
</body>
</html>

View File

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

View File

@ -6,13 +6,19 @@ 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(n => n.startsWith(SCHEDULE_PREFIX + '.'))
Object.keys(prefs).filter(schedule.prefs.validate)
.map(n => [n, prefs[n]])
);
});
@ -33,21 +39,20 @@ schedule.prefs = {
});
}
};
/* call this function when schedule timing is modified; if timing is not modified, nothing happens */
schedule.entry = request => {
console.error('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_PREFIX + '.' + request.id, {
schedule.prefs.set(schedule.prefs.name(request.id), {
id: request.id,
start: request.start,
end: request.end,
enabled: request.enabled
});
resolve();
}, resolve);
}
else {
reject(new Error('Required permissions are not granted'));
@ -55,25 +60,24 @@ schedule.entry = request => {
});
});
};
/* 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.error('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;
console.error('next alarm is set for', request.id);
chrome.alarms.create(name, {
when: now.getTime() + Math.min(
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;
console.error('Changing state', enabled, style.id);
console.log(`style with id = ${style.id}; enabled = `, enabled);
saveStyleSafe({
id: request.id,
@ -82,7 +86,7 @@ schedule.execute = (name, request) => {
}
else {
// clear schedule if style is not found
console.error('removing since stlye is not found', request);
console.log('removing from storage since style is not found', request);
schedule.execute(name, Object.assign(
request, {enabled: false}
));
@ -90,7 +94,7 @@ schedule.execute = (name, request) => {
});
}
else {
console.error('removing pref', name);
console.log('removing pref since request.enabled is false', name);
schedule.prefs.remove(name);
}
});
@ -98,24 +102,18 @@ schedule.execute = (name, request) => {
// background only
if (BG === window) {
schedule.prefs.subscribe((name, pref) => name.startsWith(SCHEDULE_PREFIX + '.') && schedule.execute(name, pref));
// 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 => {
if (prefs[name]) {
schedule.execute(name, prefs[name]);
}
});
schedule.prefs.get(name, prefs => prefs[name] && schedule.execute(name, prefs[name]));
});
(function (callback) {
chrome.idle.onStateChanged.addListener(state => {
if (state === 'active') {
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)));
});
}

View File

@ -1,13 +1,31 @@
/* global t, schedule */
/* global t, schedule, $, $$ */
'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) => {
const parent = $(`[id="style-${request.id}"] .schedule`);
if (parent) {
parent.dataset.active = true;
$('input[type=button]', parent).value = t('scheduleButtonActive');
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] = parent.querySelectorAll('input[type=time]');
const [start, end] = schedule.ui.inputs(parent);
const id = target.closest('.entry').id.replace('style-', '');
switch ([start.value, end.value].filter(v => v).length) {
case 0:
@ -42,20 +60,22 @@ document.addEventListener('click', e => {
document.addEventListener('click', observe);
}
});
function test () {
/* update schedule section on styles ready */
document.addEventListener('styles-ready', () => {
console.log('"styles-ready" is called');
schedule.prefs.getAll(prefs => {
prefs.forEach(([name, pref]) => {
const parent = document.querySelector(`[id="style-${pref.id}"] .schedule`);
if (parent) {
parent.dataset.active = true;
parent.querySelector('input[type=button]').value = t('scheduleButtonActive');
const [start, end] = parent.querySelectorAll('input[type=time');
start.value = pref.start;
end.value = pref.end;
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);
}
});
});
}
window.setTimeout(test, 1000);