From c2f993db27fd4ddf520c77359bce404860a897d9 Mon Sep 17 00:00:00 2001 From: Jeremy Schomery Date: Wed, 3 May 2017 19:19:40 +0430 Subject: [PATCH] scheduler implementation part/2 --- background.js | 5 ++--- manage.html | 2 +- manage.js | 5 +++++ schedule/core.js | 56 +++++++++++++++++++++++------------------------- schedule/ui.js | 54 +++++++++++++++++++++++++++++++--------------- 5 files changed, 72 insertions(+), 50 deletions(-) diff --git a/background.js b/background.js index ec16d00d..99797fe9 100644 --- a/background.js +++ b/background.js @@ -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; } } diff --git a/manage.html b/manage.html index 87d455db..68609646 100644 --- a/manage.html +++ b/manage.html @@ -226,8 +226,8 @@ - + diff --git a/manage.js b/manage.js index d1f3149e..dad7e455 100644 --- a/manage.js +++ b/manage.js @@ -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 + })); } diff --git a/schedule/core.js b/schedule/core.js index 45d1d646..63bf2b56 100644 --- a/schedule/core.js +++ b/schedule/core.js @@ -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( - start < 0 ? start + 24 * 60 * 60 * 1000 : start, - end < 0 ? end + 24 * 60 * 60 * 1000 : end - ) - }); + 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))); }); } diff --git a/schedule/ui.js b/schedule/ui.js index 1bee241b..e4ddff08 100644 --- a/schedule/ui.js +++ b/schedule/ui.js @@ -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)); }); -} - -window.setTimeout(test, 1000); +}); +/* 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); + } + }); +});