/* global applyOnMessage installed */ 'use strict'; // eslint-disable-next-line no-var var hotkeys = (() => { const entries = document.getElementsByClassName('entry'); let togglablesShown; let togglables; let enabled = false; let ready = false; window.addEventListener('showStyles:done', function _() { window.removeEventListener('showStyles:done', _); togglablesShown = true; togglables = getTogglables(); ready = true; setState(true); initHotkeyInfo(); }); window.addEventListener('resize', adjustInfoPosition); 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; } } function onKeyDown(event) { if (event.ctrlKey || event.altKey || event.metaKey || !enabled) { return; } let entry; 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) { invertTogglables(); } 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) { const letter = new RegExp(key ? '^' + key : '^\\x' + k.toString(16), 'i'); entry = [...entries].find(entry => letter.test(entry.textContent)); } if (!entry) { return; } const target = $(event.shiftKey ? '.style-edit-link' : '.checker', entry); target.dispatchEvent(new MouseEvent('click', {cancelable: true})); } function getTogglables() { const enabledOrAll = $('.entry.enabled') ? $$('.entry.enabled') : [...entries]; return enabledOrAll.map(entry => entry.id); } 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); task = task.then(() => saveStyleSafe({ id: entry.styleId, enabled: enable, notify: false, })); } } if (results.length) { task.then(refreshAllTabs); } return results; } function refreshAllTabs() { getStylesSafe({matchUrl: location.href, enabled: true, asHash: true}) .then(styles => applyOnMessage({method: 'styleReplaceAll', styles})); queryTabs().then(tabs => tabs.forEach(tab => (!FIREFOX || tab.width) && refreshTab(tab))); } function refreshTab(tab) { const tabId = tab.id; chrome.webNavigation.getAllFrames({tabId}, frames => { frames = frames && frames[0] ? frames : [{frameId: 0}]; frames.forEach(({frameId}) => getStylesSafe({matchUrl: tab.url, enabled: true, asHash: true}).then(styles => { const message = {method: 'styleReplaceAll', tabId, frameId, styles}; invokeOrPostpone(tab.active, sendMessage, message, ignoreChromeError); if (frameId === 0) { setTimeout(BG.updateIcon, 0, tab, styles); } })); ignoreChromeError(); }); } 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; window.addEventListener('resize', adjustInfoPosition); } function open() { window.removeEventListener('resize', adjustInfoPosition); debounce.unregister(adjustInfoPosition); title = container.title; container.title = ''; container.style = ''; container.dataset.active = true; if (!container.firstElementChild) { buildElement(); } const height = 3 + container.firstElementChild.scrollHeight + container.lastElementChild.scrollHeight; if (height > document.body.clientHeight) { document.body.style.height = height + 'px'; } } function buildElement() { const keysToElements = line => line .split(/(<.*?>)/) .map(s => (!s.startsWith('<') ? s : $create('mark', s.slice(1, -1)))); const linesToElements = text => text .trim() .split('\n') .map((line, i, array) => $create(i < array.length - 1 ? { tag: 'p', appendChild: keysToElements(line), } : { tag: 'a', target: '_blank', href: 'https://github.com/openstyles/stylus/wiki/Popup', textContent: line, })); [ linesToElements(t('popupHotkeysInfo')), $create('button', t('confirmOK')), ].forEach(child => { container.appendChild($create('div', child)); }); } } function adjustInfoPosition(debounced) { if (debounced !== true) { debounce(adjustInfoPosition, 100, true); return; } } })();