scheduler implementation part/1
This commit is contained in:
parent
f3c42fc27b
commit
9f9b8be0f4
|
@ -706,5 +706,14 @@
|
||||||
},
|
},
|
||||||
"optionsCheck": {
|
"optionsCheck": {
|
||||||
"message": "Update styles"
|
"message": "Update styles"
|
||||||
|
},
|
||||||
|
"scheduleButton": {
|
||||||
|
"message": "Schedule"
|
||||||
|
},
|
||||||
|
"scheduleButtonActive": {
|
||||||
|
"message": "Scheduled"
|
||||||
|
},
|
||||||
|
"scheduleMSG": {
|
||||||
|
"message": "Either clear both start and end values to disable the schedule or set both to enable it"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global dbExec, getStyles, saveStyle */
|
/* global dbExec, getStyles, saveStyle, schedule, download */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// eslint-disable-next-line no-var
|
// eslint-disable-next-line no-var
|
||||||
|
@ -278,5 +278,9 @@ function onRuntimeMessage(request, sender, sendResponse) {
|
||||||
.then(sendResponse)
|
.then(sendResponse)
|
||||||
.catch(() => sendResponse(null));
|
.catch(() => sendResponse(null));
|
||||||
return KEEP_CHANNEL_OPEN;
|
return KEEP_CHANNEL_OPEN;
|
||||||
|
case 'schedule':
|
||||||
|
schedule.entry(request)
|
||||||
|
.then(sendResponse)
|
||||||
|
.catch(e => sendResponse(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
manage.css
27
manage.css
|
@ -145,6 +145,33 @@ a:hover {
|
||||||
margin-left: 1ex;
|
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>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 {
|
summary {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
10
manage.html
10
manage.html
|
@ -57,6 +57,14 @@
|
||||||
<div class="targets"></div>
|
<div class="targets"></div>
|
||||||
<span class="expander">...</span>
|
<span class="expander">...</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="schedule" data-edit="false">
|
||||||
|
<input type="button" i18n-value="scheduleButton" data-cmd="schedule">
|
||||||
|
<div>
|
||||||
|
<input type="time">
|
||||||
|
-
|
||||||
|
<input type="time">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -218,6 +226,8 @@
|
||||||
|
|
||||||
<script src="backup/fileSaveLoad.js"></script>
|
<script src="backup/fileSaveLoad.js"></script>
|
||||||
<script src="msgbox/msgbox.js"></script>
|
<script src="msgbox/msgbox.js"></script>
|
||||||
|
<script src="/schedule/ui.js"></script>
|
||||||
|
<script src="/schedule/core.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -18,8 +18,12 @@
|
||||||
"storage",
|
"storage",
|
||||||
"<all_urls>"
|
"<all_urls>"
|
||||||
],
|
],
|
||||||
|
"optional_permissions": [
|
||||||
|
"idle",
|
||||||
|
"alarms"
|
||||||
|
],
|
||||||
"background": {
|
"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": {
|
"commands": {
|
||||||
"openManage": {
|
"openManage": {
|
||||||
|
|
121
schedule/core.js
Normal file
121
schedule/core.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/* globals getStylesSafe, saveStyleSafe, BG */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var SCHEDULE_PREFIX = 'schedule';
|
||||||
|
|
||||||
|
var schedule = {};
|
||||||
|
|
||||||
|
schedule.prefs = {
|
||||||
|
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 + '.'))
|
||||||
|
.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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
schedule.entry = request => {
|
||||||
|
console.error('schedule.entry', request);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.permissions.request({
|
||||||
|
permissions: ['idle', 'alarms']
|
||||||
|
}, (granted) => {
|
||||||
|
if (granted) {
|
||||||
|
schedule.prefs.set(SCHEDULE_PREFIX + '.' + request.id, {
|
||||||
|
id: request.id,
|
||||||
|
start: request.start,
|
||||||
|
end: request.end,
|
||||||
|
enabled: request.enabled
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reject(new Error('Required permissions are not granted'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
schedule.execute = (name, request) => {
|
||||||
|
console.error('schedule.execute', 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
|
||||||
|
)
|
||||||
|
});
|
||||||
|
getStylesSafe({id: request.id}).then(([style]) => {
|
||||||
|
if (style) {
|
||||||
|
const enabled = start <= 0 && end > 0;
|
||||||
|
console.error('Changing state', enabled, style.id);
|
||||||
|
|
||||||
|
saveStyleSafe({
|
||||||
|
id: request.id,
|
||||||
|
enabled
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// clear schedule if style is not found
|
||||||
|
console.error('removing since stlye is not found', request);
|
||||||
|
schedule.execute(name, Object.assign(
|
||||||
|
request, {enabled: false}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error('removing pref', name);
|
||||||
|
schedule.prefs.remove(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// background only
|
||||||
|
if (BG === window) {
|
||||||
|
schedule.prefs.subscribe((name, pref) => name.startsWith(SCHEDULE_PREFIX + '.') && schedule.execute(name, pref));
|
||||||
|
|
||||||
|
chrome.alarms.onAlarm.addListener(({name}) => {
|
||||||
|
schedule.prefs.get(name, prefs => {
|
||||||
|
if (prefs[name]) {
|
||||||
|
schedule.execute(name, prefs[name]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
(function (callback) {
|
||||||
|
chrome.idle.onStateChanged.addListener(state => {
|
||||||
|
if (state === 'active') {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.setTimeout(callback);
|
||||||
|
})(function () {
|
||||||
|
schedule.prefs.getAll(prefs => prefs.forEach(a => schedule.execute(...a)));
|
||||||
|
});
|
||||||
|
}
|
61
schedule/ui.js
Normal file
61
schedule/ui.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* global t, schedule */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
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 id = target.closest('.entry').id.replace('style-', '');
|
||||||
|
switch ([start.value, end.value].filter(v => v).length) {
|
||||||
|
case 0:
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
method: 'schedule',
|
||||||
|
enabled: false,
|
||||||
|
id
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 1: // when only start or end value is set; display an alert
|
||||||
|
window.alert(t('scheduleMSG'));
|
||||||
|
[start, end].filter(o => !o.value).forEach(o => o.focus());
|
||||||
|
return;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function test () {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(test, 1000);
|
Loading…
Reference in New Issue
Block a user