Use messageBox in manage for confirm; partially revert c5741aff

This commit is contained in:
tophf 2017-03-25 22:50:37 +03:00
parent 54bb7cdd4e
commit 363f752934
10 changed files with 250 additions and 220 deletions

View File

@ -130,13 +130,16 @@ function importFromString(jsonString) {
</small> </small>
</details>`) </details>`)
.join(''); .join('');
const box = messageBox({ messageBox({
title: 'Finished importing styles', title: 'Finished importing styles',
contents: report || 'Nothing was changed.', contents: report || 'Nothing was changed.',
buttons: [t('confirmOK'), numChanged && t('undo')], buttons: [t('confirmOK'), numChanged && t('undo')],
onclick: btnIndex => btnIndex == 1 && undo(), onshow: bindClick,
}); }).then(({button, enter, esc}) => {
bindClick(box); if (button == 1) {
undo();
}
});
resolve(numChanged); resolve(numChanged);
}); });
} }

View File

@ -5,7 +5,6 @@
<title i18n-text="manageTitle"></title> <title i18n-text="manageTitle"></title>
<link rel="stylesheet" href="manage.css"> <link rel="stylesheet" href="manage.css">
<link rel="stylesheet" href="msgbox/msgbox.css"> <link rel="stylesheet" href="msgbox/msgbox.css">
<link rel="stylesheet" href="msgbox/confirm.css">
<template data-id="style"> <template data-id="style">
<div class="entry"> <div class="entry">
@ -117,17 +116,6 @@
</div> </div>
<div id="installed"></div> <div id="installed"></div>
<div id="confirm">
<div>
<b>Style's Name</b>
<span i18n-text="deleteStyleConfirm"></span>
<div>
<button i18n-text="confirmCancel" data-cmd="cancel"></button>
<button i18n-text="confirmDelete" data-cmd="ok"></button>
</div>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none"> <svg xmlns="http://www.w3.org/2000/svg" style="display: none">
<symbol id="svg-icon-external-link" height="16" width="16" viewBox="0 0 8 8"> <symbol id="svg-icon-external-link" height="16" width="16" viewBox="0 0 8 8">
<path d="M0 0v8h8v-2h-1v1h-6v-6h1v-1h-2zm4 0l1.5 1.5-2.5 2.5 1 1 2.5-2.5 1.5 1.5v-4h-4z"></path> <path d="M0 0v8h8v-2h-1v1h-6v-6h1v-1h-2zm4 0l1.5 1.5-2.5 2.5 1 1 2.5-2.5 1.5 1.5v-4h-4z"></path>

View File

@ -172,7 +172,7 @@ function createStyleElement(style) {
$('.disable', entry).onclick = EntryOnClick.toggle; $('.disable', entry).onclick = EntryOnClick.toggle;
$('.check-update', entry).onclick = EntryOnClick.check; $('.check-update', entry).onclick = EntryOnClick.check;
$('.update', entry).onclick = EntryOnClick.update; $('.update', entry).onclick = EntryOnClick.update;
$('.delete', entry).onclick = event => confirmDelete(event, {float: true}); $('.delete', entry).onclick = EntryOnClick.delete;
return entry; return entry;
} }
@ -224,6 +224,23 @@ class EntryOnClick {
})); }));
} }
static delete(event) {
const styleElement = getClickedStyleElement(event);
const id = styleElement.styleId;
const name = ((cachedStyles.byId.get(id) || {}).style || {}).name;
animateElement(styleElement, {className: 'highlight'});
messageBox({
title: t('deleteStyleConfirm'),
contents: name,
className: 'danger center',
buttons: [t('confirmDelete'), t('confirmCancel')],
})
.then(({button, enter, esc}) => {
if (button == 0 || enter) {
deleteStyle(id);
}
});
}
} }

View File

@ -1,80 +0,0 @@
#confirm,
#confirm > div > span {
align-items: center;
justify-content: center;
}
#confirm {
z-index: 2147483647;
display: none;
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
margin: 0 !important;
box-sizing: border-box;
animation: lights-off .5s cubic-bezier(.03, .67, .08, .94);
animation-fill-mode: both;
}
#confirm.lights-on {
animation: lights-on .25s ease-in-out;
animation-fill-mode: both;
}
#confirm.lights-on > div{
display: none;
}
#confirm[data-display=true] {
display: flex;
}
#confirm > div {
width: 80vw;
max-width: 16em;
min-height: 8em;
max-height: 80vh;
background-color: #fff;
display: flex;
flex-direction: column;
border: solid 2px rgba(0, 0, 0, 0.5);
}
#confirm > div > span {
display: flex;
flex: 1;
padding: 0 10px;
}
#confirm > div > b {
padding: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#confirm > div > div {
padding: 10px;
direction: rtl;
}
@keyframes lights-off {
from {
background-color: transparent;
}
to {
background-color: rgba(0, 0, 0, 0.4);
}
}
@keyframes lights-on {
from {
background-color: rgba(0, 0, 0, 0.4);
}
to {
background-color: transparent;
}
}

View File

@ -1,50 +0,0 @@
function confirmDelete(event, {float = false} = {}) {
const id = getClickedStyleId(event);
const box = $('#confirm');
box.dataset.id = id;
box.dataset.display = true;
box.style.cssText = '';
$('b', box).textContent = ((cachedStyles.byId.get(id) || {}).style || {}).name;
if (float) {
const GAP = 50;
const {width:W, height:H} = box.firstElementChild.getBoundingClientRect();
const {left:L, top:T, right:R, bottom:B} = event.target.getBoundingClientRect();
Object.assign(box.style, {
paddingTop: (Math.min(T - H/2, innerHeight - H) - GAP) + 'px',
paddingLeft: (Math.min(L - W/2, innerWidth - W) - GAP) + 'px',
paddingRight: (innerWidth - Math.max(R + W/2, W) - GAP) + 'px',
paddingBottom: (innerHeight - Math.max(B + H/2, H) - GAP) + 'px',
});
}
let resolveMe;
$('[data-cmd="ok"]', box).onclick = event => doDelete(true);
$('[data-cmd="cancel"]', box).onclick = event => doDelete(false);
window.addEventListener('keydown', onKey);
const stopScroll = {x: scrollX, y: scrollY};
window.addEventListener('scroll', preventScroll);
return new Promise(resolve => resolveMe = resolve);
function doDelete(confirmed) {
window.removeEventListener('keydown', onKey);
window.removeEventListener('scroll', preventScroll);
animateElement(box, {className: 'lights-on'}).then(() => {
box.dataset.display = false;
});
Promise.resolve(confirmed && deleteStyle(id))
.then(resolveMe);
}
function onKey(event) {
if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
&& (event.keyCode == 13 || event.keyCode == 27)) {
event.preventDefault();
doDelete(event.keyCode == 13);
}
}
function preventScroll() {
window.scrollTo(stopScroll.x, stopScroll.y);
}
}

View File

@ -1,4 +1,17 @@
#message-box { #message-box {
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
position: fixed;
box-shadow: 5px 5px 50px rgba(0, 0, 0, 0.35);
background-color: rgba(0, 0, 0, .25);
animation: fadein .25s ease-in-out;
z-index: 9999990;
}
#message-box > div {
top: 3rem; top: 3rem;
right: 3rem; right: 3rem;
min-width: 10rem; min-width: 10rem;
@ -7,41 +20,36 @@
max-height: 90vh; max-height: 90vh;
position: fixed; position: fixed;
display: flex; display: flex;
box-shadow: 5px 5px 50px rgba(0, 0, 0, 0.35);
animation: fadein .25s ease-in-out;
flex-direction: column; flex-direction: column;
z-index: 9999990;
}
#message-box > * {
z-index: 9999991;
background-color: white; background-color: white;
box-shadow: 5px 5px 50px rgba(0, 0, 0, 0.35);
z-index: 9999991;
} }
#message-box.fadeout { #message-box.fadeout {
animation: fadeout .5s ease-in-out; animation: fadeout .5s ease-in-out;
} }
#message-box::before { #message-box.center {
position: fixed; align-items: center;
content: ""; justify-content: center;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .25);
} }
#message-box.big { #message-box.center #message-box-contents {
max-width: none; text-align: center;
left: 3rem; }
#message-box.center > div {
top: unset;
right: unset;
} }
#message-box-title { #message-box-title {
font-weight: bold; font-weight: bold;
background-color: rgb(145, 208, 198); background-color: rgb(145, 208, 198);
padding: .75rem 50px .75rem .75rem; padding: .75rem 50px .75rem 52px;
font-size: 1rem; font-size: 1rem;
position: relative;
} }
#message-box-title::before { #message-box-title::before {
@ -49,10 +57,23 @@
width: 0; width: 0;
height: 0; height: 0;
padding: 0 32px 32px 0; padding: 0 32px 32px 0;
background: url('/images/icon/32.png'); background: url(/images/icon/32.png);
display: inline-block; position: absolute;
vertical-align: middle; left: 11px;
margin-right: .5rem; top: 8px;
}
#message-box.danger #message-box-title {
background-color: firebrick;
color: white;
}
#message-box.danger #message-box-title::before {
background: url('/images/icon/32x.png');
}
#message-box.danger #message-box-contents {
font-weight: bold;
} }
#message-box-close-icon { #message-box-close-icon {
@ -68,7 +89,7 @@
#message-box-contents { #message-box-contents {
overflow: auto; overflow: auto;
padding: .75rem; padding: 1.5rem .75rem;
position: relative; position: relative;
flex-grow: 9; flex-grow: 9;
} }
@ -76,6 +97,7 @@
#message-box-buttons { #message-box-buttons {
padding: .75rem; padding: .75rem;
background-color: #f0f0f0; background-color: #f0f0f0;
text-align: center;
} }
#message-box-buttons button:not(:last-child) { #message-box-buttons button:not(:last-child) {

View File

@ -1,51 +1,90 @@
'use strict'; 'use strict';
function messageBox({title, contents, buttons, onclick}) { function messageBox({
// keep the same reference to be able to remove the listener later title, // [mandatory] the title string for innerHTML
messageBox.close = messageBox.close || close; contents, // [mandatory] 1) DOM element 2) string for innerHTML
if (messageBox.element) { className = '', // string, CSS class name of the message box element
messageBox.element.remove(); buttons = [], // array of strings used as labels
onshow, // function(messageboxElement) invoked after the messagebox is shown
blockScroll, // boolean, blocks the page scroll
}) { // RETURNS: Promise resolved to {button[number], enter[boolean], esc[boolean]}
initOwnListeners();
bindGlobalListeners();
createElement();
document.body.appendChild(messageBox.element);
if (onshow) {
onshow(messageBox.element);
} }
const id = 'message-box'; return new Promise(_resolve => {
const putAs = typeof contents == 'string' ? 'innerHTML' : 'appendChild'; messageBox.resolve = _resolve;
messageBox.element = $element({id, appendChild: [ });
$element({id: `${id}-title`, innerHTML: title}),
$element({id: `${id}-close-icon`, onclick: messageBox.close}),
$element({id: `${id}-contents`, [putAs]: contents}),
$element({id: `${id}-buttons`,
onclick: relayButtonClick,
appendChild: (buttons || []).map(textContent =>
textContent && $element({tag: 'button', textContent}))
}),
]});
show();
return messageBox.element;
function show() { function initOwnListeners() {
document.body.appendChild(messageBox.element); messageBox.listeners = messageBox.listeners || {
document.addEventListener('keydown', messageBox.close); closeIcon() {
} resolveWith({button: -1});
},
function close(event) { button() {
if ((!event resolveWith({button: this.buttonIndex});
|| event.type == 'click' },
|| event.keyCode == 27 && !event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) key(event) {
&& messageBox.element) { if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
animateElement(messageBox.element, {className: 'fadeout', remove: true}); && (event.keyCode == 13 || event.keyCode == 27)) {
document.removeEventListener('keydown', messageBox.close); event.preventDefault();
$(`#${id}-buttons`).onclick = null; resolveWith(event.keyCode == 13 ? {enter: true} : {esc: true});
messageBox.element = null; }
} },
} scroll() {
scrollTo(blockScroll.x, blockScroll.y);
function relayButtonClick(event) {
const button = event.target.closest('button');
if (button) {
close();
if (onclick) {
onclick([...this.children].indexOf(button));
} }
};
}
function resolveWith(value) {
setTimeout(messageBox.resolve, 0, value);
animateElement(messageBox.element, {className: 'fadeout', remove: true})
.then(unbindAndRemoveSelf);
}
function createElement() {
if (messageBox.element) {
unbindAndRemoveSelf();
} }
const id = 'message-box';
const putAs = typeof contents == 'string' ? 'innerHTML' : 'appendChild';
messageBox.element = $element({id, className, appendChild: [
$element({appendChild: [
$element({id: `${id}-title`, innerHTML: title}),
$element({id: `${id}-close-icon`, onclick: messageBox.listeners.closeIcon}),
$element({id: `${id}-contents`, [putAs]: contents}),
$element({id: `${id}-buttons`, appendChild:
buttons.map((textContent, buttonIndex) => textContent &&
$element({
tag: 'button',
buttonIndex,
textContent,
onclick: messageBox.listeners.button,
})
)
}),
]}),
]});
}
function bindGlobalListeners() {
blockScroll = blockScroll && {x: scrollX, y: scrollY};
if (blockScroll) {
window.addEventListener('scroll', messageBox.listeners.scroll);
}
window.addEventListener('keydown', messageBox.listeners.key);
}
function unbindAndRemoveSelf() {
document.removeEventListener('keydown', messageBox.listeners.key);
window.removeEventListener('scroll', messageBox.listeners.scroll);
messageBox.element.remove();
messageBox.element = null;
messageBox.resolve = null;
} }
function $element(opt) { function $element(opt) {

View File

@ -212,3 +212,75 @@ body>div:not(#installed) {
white-space: nowrap; white-space: nowrap;
padding-right: 5px; padding-right: 5px;
} }
/* confirm */
#confirm,
#confirm>div>span {
align-items: center;
justify-content: center;
}
#confirm {
z-index: 2147483647;
display: none; /* flex */
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
margin: 0!important;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.4);
animation: lights-off .5s cubic-bezier(.03, .67, .08, .94);
animation-fill-mode: both;
}
#confirm.lights-on {
animation: lights-on .25s ease-in-out;
animation-fill-mode: both;
}
#confirm.lights-on > div{
display: none;
}
#confirm[data-display=true] {
display: flex;
}
#confirm>div {
width: 80%;
height: 100px;
max-height: 80%;
min-height: 8em;
background-color: #fff;
display: flex;
flex-direction: column;
border: solid 2px rgba(0, 0, 0, 0.5);
}
#confirm>div>span {
display: flex;
flex: 1;
padding: 0 10px;
}
#confirm>div>b {
padding: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#confirm>div>div {
padding: 10px;
direction: rtl;
}
@keyframes lights-off {
from {
background-color: transparent;
}
to {
background-color: rgba(0, 0, 0, 0.4);
}
}
@keyframes lights-on {
from {
background-color: rgba(0, 0, 0, 0.4);
}
to {
background-color: transparent;
}
}

View File

@ -3,7 +3,6 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<link rel="stylesheet" href="popup.css"> <link rel="stylesheet" href="popup.css">
<link rel="stylesheet" href="msgbox/confirm.css">
<template data-id="style"> <template data-id="style">
<div class="entry"> <div class="entry">
@ -44,7 +43,6 @@
<script src="messaging.js"></script> <script src="messaging.js"></script>
<script src="apply.js"></script> <script src="apply.js"></script>
<script src="dom.js"></script> <script src="dom.js"></script>
<script src="msgbox/confirm.js"></script>
<script src="popup.js"></script> <script src="popup.js"></script>
</head> </head>

View File

@ -188,12 +188,33 @@ class EntryOnClick {
} }
static delete(event) { static delete(event) {
confirmDelete(event).then(() => { const id = getClickedStyleId(event);
// update view with 'No styles installed for this site' message const box = $('#confirm');
if (!installed.children.length) { box.dataset.display = true;
showStyles([]); box.style.cssText = '';
$('b', box).textContent = ((cachedStyles.byId.get(id) || {}).style || {}).name;
$('[data-cmd="ok"]', box).onclick = () => confirm(true);
$('[data-cmd="cancel"]', box).onclick = () => confirm(false);
window.onkeydown = event => {
if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
&& (event.keyCode == 13 || event.keyCode == 27)) {
event.preventDefault();
confirm(event.keyCode == 13);
} }
}); };
function confirm(ok) {
window.onkeydown = null;
animateElement(box, {className: 'lights-on'})
.then(() => box.dataset.display = false);
if (ok) {
deleteStyle(id).then(() => {
// update view with 'No styles installed for this site' message
if (!installed.children.length) {
showStyles([]);
}
});
}
}
} }
} }