2017-11-28 22:46:42 +00:00
|
|
|
/* global applyOnMessage installed */
|
|
|
|
'use strict';
|
|
|
|
|
2017-12-05 21:14:21 +00:00
|
|
|
// eslint-disable-next-line no-var
|
|
|
|
var hotkeys = (() => {
|
2017-12-14 02:50:58 +00:00
|
|
|
const entries = document.getElementsByClassName('entry');
|
2017-12-05 21:14:21 +00:00
|
|
|
let togglablesShown;
|
|
|
|
let togglables;
|
|
|
|
let enabled = false;
|
|
|
|
let ready = false;
|
2017-11-28 22:46:42 +00:00
|
|
|
|
2017-12-05 21:14:21 +00:00
|
|
|
window.addEventListener('showStyles:done', function _() {
|
|
|
|
window.removeEventListener('showStyles:done', _);
|
|
|
|
togglablesShown = true;
|
|
|
|
togglables = getTogglables();
|
|
|
|
ready = true;
|
|
|
|
setState(true);
|
|
|
|
initHotkeyInfo();
|
|
|
|
});
|
2017-11-28 22:46:42 +00:00
|
|
|
|
2017-12-08 20:16:59 +00:00
|
|
|
window.addEventListener('resize', adjustInfoPosition);
|
|
|
|
|
2017-12-05 21:14:21 +00:00
|
|
|
return {setState};
|
|
|
|
|
|
|
|
function setState(newState = !enabled) {
|
|
|
|
if (!ready) {
|
|
|
|
throw new Error('hotkeys no ready');
|
|
|
|
}
|
|
|
|
if (newState !== enabled) {
|
|
|
|
window[`${newState ? 'add' : 'remove'}EventListener`]('keydown', onKeyDown);
|
|
|
|
enabled = newState;
|
|
|
|
}
|
|
|
|
}
|
2017-11-28 22:46:42 +00:00
|
|
|
|
|
|
|
function onKeyDown(event) {
|
2017-12-05 21:14:21 +00:00
|
|
|
if (event.ctrlKey || event.altKey || event.metaKey || !enabled) {
|
2017-11-28 22:46:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let entry;
|
2017-12-14 02:50:58 +00:00
|
|
|
const {which: k, key, code} = event;
|
|
|
|
|
|
|
|
if (code.startsWith('Digit') || code.startsWith('Numpad') && code.length === 7) {
|
|
|
|
entry = entries[(Number(code.slice(-1)) || 10) - 1];
|
|
|
|
|
|
|
|
} else if (
|
|
|
|
code === 'Backquote' || code === 'NumpadMultiply' ||
|
|
|
|
key && (key === '`' || key === '*') ||
|
|
|
|
k === 192 || k === 106) {
|
2017-11-28 22:46:42 +00:00
|
|
|
invertTogglables();
|
2017-12-14 02:50:58 +00:00
|
|
|
|
|
|
|
} else if (
|
|
|
|
code === 'NumpadSubtract' ||
|
|
|
|
key && key === '-' ||
|
|
|
|
k === 109) {
|
|
|
|
toggleState(entries, 'enabled', false);
|
|
|
|
|
|
|
|
} else if (
|
|
|
|
code === 'NumpadAdd' ||
|
|
|
|
key && key === '+' ||
|
|
|
|
k === 107) {
|
|
|
|
toggleState(entries, 'disabled', true);
|
|
|
|
|
|
|
|
} else if (
|
|
|
|
// any single character
|
|
|
|
key && key.length === 1 ||
|
|
|
|
k >= 65 && k <= 90) {
|
2017-12-06 23:11:50 +00:00
|
|
|
const letter = new RegExp(key ? '^' + key : '^\\x' + k.toString(16), 'i');
|
2017-12-14 02:50:58 +00:00
|
|
|
entry = [...entries].find(entry => letter.test(entry.textContent));
|
2017-11-28 22:46:42 +00:00
|
|
|
}
|
|
|
|
if (!entry) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const target = $(event.shiftKey ? '.style-edit-link' : '.checker', entry);
|
2017-12-14 02:50:58 +00:00
|
|
|
target.dispatchEvent(new MouseEvent('click', {cancelable: true}));
|
2017-11-28 22:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getTogglables() {
|
2017-12-14 02:50:58 +00:00
|
|
|
const enabledOrAll = $('.entry.enabled') ? $$('.entry.enabled') : [...entries];
|
|
|
|
return enabledOrAll.map(entry => entry.id);
|
2017-11-28 22:46:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function countEnabledTogglables() {
|
|
|
|
let num = 0;
|
|
|
|
for (const id of togglables) {
|
|
|
|
num += $(`#${id}`).classList.contains('enabled');
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
function invertTogglables() {
|
|
|
|
togglables = togglables.length ? togglables : getTogglables();
|
|
|
|
togglablesShown = countEnabledTogglables() > togglables.length / 2;
|
|
|
|
toggleState(togglables, null, !togglablesShown);
|
|
|
|
togglablesShown = !togglablesShown;
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleState(list, match, enable) {
|
|
|
|
const results = [];
|
|
|
|
let task = Promise.resolve();
|
|
|
|
for (let entry of list) {
|
|
|
|
entry = typeof entry === 'string' ? $('#' + entry) : entry;
|
|
|
|
if (!match && $('.checker', entry).checked !== enable || entry.classList.contains(match)) {
|
|
|
|
results.push(entry.id);
|
2018-01-01 17:02:49 +00:00
|
|
|
task = task.then(() => API.saveStyle({
|
2017-11-28 22:46:42 +00:00
|
|
|
id: entry.styleId,
|
|
|
|
enabled: enable,
|
|
|
|
notify: false,
|
2018-01-01 17:02:49 +00:00
|
|
|
})).then(() => {
|
|
|
|
entry.classList.toggle('enabled', enable);
|
|
|
|
entry.classList.toggle('disabled', !enable);
|
|
|
|
$('.checker', entry).checked = enable;
|
|
|
|
});
|
2017-11-28 22:46:42 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-03 15:26:31 +00:00
|
|
|
if (results.length) task.then(API.refreshAllTabs);
|
2017-11-28 22:46:42 +00:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2017-12-01 21:49:59 +00:00
|
|
|
function initHotkeyInfo() {
|
|
|
|
const container = $('#hotkey-info');
|
|
|
|
let title;
|
|
|
|
container.onclick = ({target}) => {
|
|
|
|
if (target.localName === 'button') {
|
|
|
|
close();
|
|
|
|
} else if (!container.dataset.active) {
|
|
|
|
open();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function close() {
|
|
|
|
delete container.dataset.active;
|
|
|
|
document.body.style.height = '';
|
|
|
|
container.title = title;
|
2017-12-08 20:16:59 +00:00
|
|
|
window.addEventListener('resize', adjustInfoPosition);
|
2017-12-01 21:49:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function open() {
|
2017-12-08 20:16:59 +00:00
|
|
|
window.removeEventListener('resize', adjustInfoPosition);
|
|
|
|
debounce.unregister(adjustInfoPosition);
|
2017-12-01 21:49:59 +00:00
|
|
|
title = container.title;
|
|
|
|
container.title = '';
|
2017-12-08 20:16:59 +00:00
|
|
|
container.style = '';
|
2017-12-01 21:49:59 +00:00
|
|
|
container.dataset.active = true;
|
|
|
|
if (!container.firstElementChild) {
|
|
|
|
buildElement();
|
|
|
|
}
|
2017-12-12 14:04:58 +00:00
|
|
|
const height = 3 +
|
2017-12-01 21:49:59 +00:00
|
|
|
container.firstElementChild.scrollHeight +
|
2017-12-12 14:04:58 +00:00
|
|
|
container.lastElementChild.scrollHeight;
|
2017-12-01 21:49:59 +00:00
|
|
|
if (height > document.body.clientHeight) {
|
|
|
|
document.body.style.height = height + 'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function buildElement() {
|
|
|
|
const keysToElements = line =>
|
|
|
|
line
|
|
|
|
.split(/(<.*?>)/)
|
|
|
|
.map(s => (!s.startsWith('<') ? s :
|
2017-12-03 21:12:09 +00:00
|
|
|
$create('mark', s.slice(1, -1))));
|
2017-12-01 21:49:59 +00:00
|
|
|
const linesToElements = text =>
|
|
|
|
text
|
|
|
|
.trim()
|
|
|
|
.split('\n')
|
|
|
|
.map((line, i, array) =>
|
2017-12-03 21:12:09 +00:00
|
|
|
$create(i < array.length - 1 ? {
|
2017-12-01 21:49:59 +00:00
|
|
|
tag: 'p',
|
|
|
|
appendChild: keysToElements(line),
|
|
|
|
} : {
|
|
|
|
tag: 'a',
|
|
|
|
target: '_blank',
|
|
|
|
href: 'https://github.com/openstyles/stylus/wiki/Popup',
|
|
|
|
textContent: line,
|
|
|
|
}));
|
|
|
|
[
|
|
|
|
linesToElements(t('popupHotkeysInfo')),
|
2017-12-03 21:12:09 +00:00
|
|
|
$create('button', t('confirmOK')),
|
2017-12-01 21:49:59 +00:00
|
|
|
].forEach(child => {
|
2017-12-03 21:12:09 +00:00
|
|
|
container.appendChild($create('div', child));
|
2017-12-01 21:49:59 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2017-12-08 20:16:59 +00:00
|
|
|
|
|
|
|
function adjustInfoPosition(debounced) {
|
|
|
|
if (debounced !== true) {
|
|
|
|
debounce(adjustInfoPosition, 100, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-12-05 21:14:21 +00:00
|
|
|
})();
|