diff --git a/.eslintrc b/.eslintrc
index c32b677b..a646543e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -35,6 +35,12 @@ globals:
importStyles: true
getActiveTabRealURL: true
openURL: true
+ $: true
+ $$: true
+ animateElement: true
+ scrollElementIntoView: true
+ getClickedStyleElement: true
+ getClickedStyleId: true
onDOMready: true
getDomains: true
webSqlStorage: true
diff --git a/backup/fileSaveLoad.js b/backup/fileSaveLoad.js
index 7d7528ae..f835bb47 100644
--- a/backup/fileSaveLoad.js
+++ b/backup/fileSaveLoad.js
@@ -1,9 +1,10 @@
-/* globals getStyles, saveStyle, invalidateCache, refreshAllTabs, handleUpdate */
+/* globals getStyles, saveStyle, invalidateCache, refreshAllTabs */
'use strict';
const STYLISH_DUMP_FILE_EXT = '.txt';
const STYLUS_BACKUP_FILE_EXT = '.json';
+
function importFromFile({fileTypeFilter, file} = {}) {
return new Promise(resolve => {
const fileInput = document.createElement('input');
@@ -44,6 +45,7 @@ function importFromFile({fileTypeFilter, file} = {}) {
});
}
+
function importFromString(jsonString) {
const json = runTryCatch(() => Array.from(JSON.parse(jsonString))) || [];
const oldStyles = json.length && deepCopyStyles();
@@ -177,14 +179,14 @@ function importFromString(jsonString) {
}
function bindClick(box) {
- for (let block of [...box.querySelectorAll('details')]) {
+ for (let block of $$('details')) {
if (block.dataset.id != 'invalid') {
block.style.cursor = 'pointer';
block.onclick = event => {
const styleElement = $(`[style-id="${event.target.dataset.id}"]`);
if (styleElement) {
scrollElementIntoView(styleElement);
- highlightElement(styleElement);
+ animateElement(styleElement, {className: 'highlight'});
}
};
}
@@ -221,7 +223,8 @@ function importFromString(jsonString) {
}
}
-document.getElementById('file-all-styles').onclick = () => {
+
+$('#file-all-styles').onclick = () => {
getStyles({}, function (styles) {
const text = JSON.stringify(styles, null, '\t');
const fileName = generateFileName();
@@ -248,7 +251,7 @@ document.getElementById('file-all-styles').onclick = () => {
};
-document.getElementById('unfile-all-styles').onclick = () => {
+$('#unfile-all-styles').onclick = () => {
importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT});
};
@@ -264,11 +267,9 @@ Object.assign(document.body, {
}
},
ondragend(event) {
- this.classList.add('fadeout');
- this.addEventListener('animationend', function _() {
- this.removeEventListener('animationend', _);
+ animateElement(this, {className: 'fadeout'}).then(() => {
this.style.animationDuration = '';
- this.classList.remove('dropzone', 'fadeout');
+ this.classList.remove('dropzone');
});
},
ondragleave(event) {
diff --git a/dom.js b/dom.js
new file mode 100644
index 00000000..403d1449
--- /dev/null
+++ b/dom.js
@@ -0,0 +1,61 @@
+'use strict';
+
+function onDOMready() {
+ if (document.readyState != 'loading') {
+ return Promise.resolve();
+ }
+ return new Promise(resolve => {
+ document.addEventListener('DOMContentLoaded', function _() {
+ document.removeEventListener('DOMContentLoaded', _);
+ resolve();
+ });
+ });
+}
+
+
+function getClickedStyleId(event) {
+ return (getClickedStyleElement(event) || {}).styleId;
+}
+
+
+function getClickedStyleElement(event) {
+ return event.target.closest('.entry');
+}
+
+
+function scrollElementIntoView(element) {
+ // align to the top/bottom of the visible area if wasn't visible
+ const bounds = element.getBoundingClientRect();
+ if (bounds.top < 0 || bounds.top > innerHeight - bounds.height) {
+ element.scrollIntoView(bounds.top < 0);
+ }
+}
+
+
+function animateElement(element, {className, remove = false}) {
+ return new Promise(resolve => {
+ element.addEventListener('animationend', function _() {
+ element.removeEventListener('animationend', _);
+ element.classList.remove(className);
+ // TODO: investigate why animation restarts if the elements is removed in .then()
+ if (remove) {
+ element.remove();
+ }
+ resolve();
+ });
+ element.classList.add(className);
+ });
+}
+
+
+function $(selector, base = document) {
+ // we have ids with . like #manage.onlyEdited which look like #id.class
+ // so since getElementById is superfast we'll try it anyway
+ const byId = selector.startsWith('#') && document.getElementById(selector.slice(1));
+ return byId || base.querySelector(selector);
+}
+
+
+function $$(selector, base = document) {
+ return [...base.querySelectorAll(selector)];
+}
diff --git a/manage.html b/manage.html
index 4726eeec..7e39d6d6 100644
--- a/manage.html
+++ b/manage.html
@@ -53,6 +53,7 @@
+
diff --git a/manage.js b/manage.js
index f6c4ed1c..6b19ea37 100644
--- a/manage.js
+++ b/manage.js
@@ -230,7 +230,7 @@ class EntryOnClick {
function handleUpdate(style, {reason} = {}) {
const element = createStyleElement(style);
const oldElement = $(`[style-id="${style.id}"]`, installed);
- highlightElement(element);
+ animateElement(element, {className: 'highlight'});
if (!oldElement) {
installed.appendChild(element);
} else {
@@ -260,12 +260,11 @@ function applyUpdateAll() {
btnApply.disabled = false;
}, 1000);
- [...document.querySelectorAll('.can-update .update')]
- .forEach(button => {
- // align to the bottom of the visible area if wasn't visible
- button.scrollIntoView(false);
- button.click();
- });
+ $$('.can-update .update').forEach(button => {
+ // align to the bottom of the visible area if wasn't visible
+ button.scrollIntoView(false);
+ button.click();
+ });
}
@@ -278,8 +277,7 @@ function checkUpdateAll() {
btnApply.classList.add('hidden');
noUpdates.classList.add('hidden');
- const elements = document.querySelectorAll('[style-update-url]');
- Promise.all([...elements].map(checkUpdate))
+ Promise.all($$('[style-update-url]').map(checkUpdate))
.then(updatables => {
btnCheck.disabled = false;
if (updatables.includes(true)) {
@@ -445,43 +443,6 @@ function searchStyles(immediately, bin) {
}
-function getClickedStyleId(event) {
- return (getClickedStyleElement(event) || {}).styleId;
-}
-
-
-function getClickedStyleElement(event) {
- return event.target.closest('.entry');
-}
-
-
-function scrollElementIntoView(element) {
- // align to the top/bottom of the visible area if wasn't visible
- const bounds = element.getBoundingClientRect();
- if (bounds.top < 0 || bounds.top > innerHeight - bounds.height) {
- element.scrollIntoView(bounds.top < 0);
- }
-}
-
-
-function highlightElement(element) {
- element.addEventListener('animationend', function _() {
- element.removeEventListener('animationend', _);
- element.classList.remove('highlight');
- });
- element.classList.add('highlight');
-}
-
-
function rememberScrollPosition() {
history.replaceState({scrollY}, document.title);
}
-
-
-function $(selector, base = document) {
- if (selector.startsWith('#') && /^#[^,\s]+$/.test(selector)) {
- return document.getElementById(selector.slice(1));
- } else {
- return base.querySelector(selector);
- }
-}
diff --git a/messaging.js b/messaging.js
index f3f24364..dd09681f 100644
--- a/messaging.js
+++ b/messaging.js
@@ -163,19 +163,6 @@ function openURL({url}) {
}
-function onDOMready() {
- if (document.readyState != 'loading') {
- return Promise.resolve();
- }
- return new Promise(resolve => {
- document.addEventListener('DOMContentLoaded', function _() {
- document.removeEventListener('DOMContentLoaded', _);
- resolve();
- });
- });
-}
-
-
function stringAsRegExp(s, flags) {
return new RegExp(s.replace(/[{}()\[\]\/\\.+?^$:=*!|]/g, '\\$&'), flags);
}
diff --git a/msgbox/confirm.js b/msgbox/confirm.js
index 2094c5f3..f77cc489 100644
--- a/msgbox/confirm.js
+++ b/msgbox/confirm.js
@@ -29,11 +29,8 @@ function confirmDelete(event, {float = false} = {}) {
function doDelete(confirmed) {
window.removeEventListener('keydown', onKey);
window.removeEventListener('scroll', preventScroll);
- box.classList.add('lights-on');
- box.addEventListener('animationend', function _() {
- box.removeEventListener('animationend', _);
+ animateElement(box, {className: 'lights-on'}).then(() => {
box.dataset.display = false;
- box.classList.remove('lights-on');
});
Promise.resolve(confirmed && deleteStyle(id))
.then(resolveMe);
diff --git a/msgbox/msgbox.js b/msgbox/msgbox.js
index 3cafe8e6..af5f3617 100644
--- a/msgbox/msgbox.js
+++ b/msgbox/msgbox.js
@@ -31,12 +31,7 @@ function messageBox({title, contents, buttons, onclick}) {
|| event.type == 'click'
|| event.keyCode == 27 && !event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey)
&& messageBox.element) {
- const box = messageBox.element;
- box.classList.add('fadeout');
- box.addEventListener('animationend', function _() {
- box.removeEventListener('animationend', _);
- box.remove();
- });
+ animateElement(messageBox.element, {className: 'fadeout', remove: true});
document.removeEventListener('keydown', messageBox.close);
$(`#${id}-buttons`).onclick = null;
messageBox.element = null;
diff --git a/popup.html b/popup.html
index d0084d96..9ef10321 100644
--- a/popup.html
+++ b/popup.html
@@ -43,6 +43,7 @@
+
diff --git a/popup.js b/popup.js
index 01e86ba6..079737b1 100644
--- a/popup.js
+++ b/popup.js
@@ -199,16 +199,6 @@ class EntryOnClick {
}
-function getClickedStyleId(event) {
- return (getClickedStyleElement(event) || {}).styleId;
-}
-
-
-function getClickedStyleElement(event) {
- return event.target.closest('.entry');
-}
-
-
function openLinkInTabOrWindow(event) {
if (!prefs.get('openEditInWindow', false)) {
openURLandHide(event);
@@ -272,12 +262,3 @@ function handleDelete(id) {
installed.removeChild(styleElement);
}
}
-
-
-function $(selector, base = document) {
- if (selector.startsWith('#') && /^#[^,\s]+$/.test(selector)) {
- return document.getElementById(selector.slice(1));
- } else {
- return base.querySelector(selector);
- }
-}