dom.js: extract common DOM functions

This commit is contained in:
tophf 2017-03-25 08:54:58 +03:00
parent 0f8fd5c07c
commit 4936426fa3
10 changed files with 88 additions and 97 deletions

View File

@ -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

View File

@ -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) {

61
dom.js Normal file
View File

@ -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)];
}

View File

@ -53,6 +53,7 @@
<script src="storage.js"></script>
<script src="messaging.js"></script>
<script src="apply.js"></script>
<script src="dom.js"></script>
<script src="localization.js"></script>
</head>

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -43,6 +43,7 @@
<script src="storage.js"></script>
<script src="messaging.js"></script>
<script src="apply.js"></script>
<script src="dom.js"></script>
<script src="msgbox/confirm.js"></script>
<script src="popup.js"></script>

View File

@ -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);
}
}