Wire up some bulk actions
This commit is contained in:
parent
30a69f5bea
commit
a7026bdeee
58
manage.html
58
manage.html
|
@ -195,6 +195,7 @@
|
||||||
<script src="vendor/semver-bundle/semver.js"></script>
|
<script src="vendor/semver-bundle/semver.js"></script>
|
||||||
<script src="manage/manage-ui.js"></script>
|
<script src="manage/manage-ui.js"></script>
|
||||||
<script src="manage/manage-actions.js"></script>
|
<script src="manage/manage-actions.js"></script>
|
||||||
|
<script src="manage/bulk-actions.js"></script>
|
||||||
<script data-src="manage/draggable.js"></script>
|
<script data-src="manage/draggable.js"></script>
|
||||||
|
|
||||||
<script data-src="vendor-overwrites/colorpicker/colorconverter.js"></script>
|
<script data-src="vendor-overwrites/colorpicker/colorconverter.js"></script>
|
||||||
|
@ -429,21 +430,32 @@
|
||||||
</select>
|
</select>
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||||
</span>
|
</span>
|
||||||
<button id="bulk-actions-apply" i18n-text="bulkActionsApply"></button>
|
<button id="bulk-actions-apply" i18n-text="bulkActionsApply">
|
||||||
|
<span id="update-progress"></span>
|
||||||
<div class="dropdown export hidden">
|
|
||||||
<button class="dropbtn">
|
|
||||||
<span>Export</span>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</button>
|
</button>
|
||||||
|
<span id="bulk-info">
|
||||||
<div class="dropdown-content">
|
<!-- Bulk update -->
|
||||||
<a href="#" id="file-all-styles" i18n-text="bckpInstStyles"></a>
|
<span data-bulk="update">
|
||||||
<a href="#" id="sync-dropbox-export" i18n-text="syncDropboxStyles"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button id="apply-all-updates" class="hidden" i18n-text="applyAllUpdates"></button>
|
<button id="apply-all-updates" class="hidden" i18n-text="applyAllUpdates"></button>
|
||||||
|
<span id="update-all-no-updates" class="hidden" i18n-text="updateAllCheckSucceededNoUpdate"></span>
|
||||||
|
<button id="check-all-updates-force" class="hidden" i18n-text="checkAllUpdatesForce"></button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Bulk export -->
|
||||||
|
<span data-bulk="export" class="dropdown export hidden">
|
||||||
|
Export to:
|
||||||
|
<span class="select-resizer">
|
||||||
|
<select id="manage.onlyEnabled.invert">
|
||||||
|
<option id="file-all-styles" i18n-text="bckpInstStyles"></option>
|
||||||
|
<option id="sync-dropbox-export" i18n-text="syncDropboxStyles"></option>
|
||||||
|
</select>
|
||||||
|
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
<svg class="svg-icon busy hidden" viewBox="0 0 24 24">
|
<svg class="svg-icon busy hidden" viewBox="0 0 24 24">
|
||||||
<path d="M12 23h-1v-6.57A5.97 5.97 0 0 1 7 18c-3.25 0-6-2.75-6-6v-1h6.57A5.97 5.97 0 0 1 6
|
<path d="M12 23h-1v-6.57A5.97 5.97 0 0 1 7 18c-3.25 0-6-2.75-6-6v-1h6.57A5.97 5.97 0 0 1 6
|
||||||
7c0-3.25 2.75-6 6-6h1v6.57A5.97 5.97 0 0 1 17 6c3.25 0 6 2.75 6 6v1h-6.57A5.97 5.97 0 0 1
|
7c0-3.25 2.75-6 6-6h1v6.57A5.97 5.97 0 0 1 17 6c3.25 0 6 2.75 6 6v1h-6.57A5.97 5.97 0 0 1
|
||||||
|
@ -501,13 +513,6 @@
|
||||||
</header>
|
</header>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: none">
|
|
||||||
<button id="apply-all-updates"></button>
|
|
||||||
<button id="check-all-updates"></button>
|
|
||||||
<button id="check-all-updates-force"></button>
|
|
||||||
<button id="unfile-all-styles"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Applies to config, can't put this in a template because these inputs are bound to subscribed prefs -->
|
<!-- Applies to config, can't put this in a template because these inputs are bound to subscribed prefs -->
|
||||||
<div class="hidden">
|
<div class="hidden">
|
||||||
<div id="appliesToConfig">
|
<div id="appliesToConfig">
|
||||||
|
@ -543,20 +548,7 @@
|
||||||
<div class="settings-column">
|
<div class="settings-column">
|
||||||
|
|
||||||
<div id="style-actions">
|
<div id="style-actions">
|
||||||
<div id="update-check">
|
|
||||||
<button id="check-all-updates" i18n-text="checkAllUpdates"><span id="update-progress"></span></button>
|
|
||||||
<a href="#" id="update-history" i18n-title="genericHistoryLabel" tabindex="0">
|
|
||||||
<svg class="svg-icon" viewBox="0 0 20 20" i18n-alt="helpAlt">
|
|
||||||
<path d="M13,7H7V6h6Zm6,6.5A5.5,5.5,0,0,1,8.61,16H4V3H16V8.61A5.5,5.5,0,0,1,19,13.5ZM8,14c0-.16,0-.84,0-1H7V12H8.21a5.46,5.46,0,0,1,.39-1H7V10H9.26a5.55,5.55,0,0,1,1.09-1H7V8h7V5H6v9Zm10-.5A4.5,4.5,0,1,0,13.5,18,4.5,4.5,0,0,0,18,13.5ZM14,13V10H13v4h4V13Z"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="update-all">
|
|
||||||
<button id="apply-all-updates" class="hidden" i18n-text="applyAllUpdates"></button>
|
|
||||||
<span id="update-all-no-updates" class="hidden" i18n-text="updateAllCheckSucceededNoUpdate"></span>
|
|
||||||
<button id="check-all-updates-force" class="hidden" i18n-text="checkAllUpdatesForce"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="add-style-wrapper">
|
<div id="add-style-wrapper">
|
||||||
<a href="edit.html">
|
<a href="edit.html">
|
||||||
|
|
121
manage/bulk-actions.js
Normal file
121
manage/bulk-actions.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/* global $ $$ handleEvent installed exportToFile checkUpdateAll */
|
||||||
|
/* exported bulk */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const bulk = {
|
||||||
|
|
||||||
|
init: () => {
|
||||||
|
document.addEventListener('change', bulk.updateBulkFilters);
|
||||||
|
$('#bulk-actions-select').onchange = bulk.handleSelect;
|
||||||
|
$('#bulk-actions-apply').onclick = bulk.handleApply;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSelect: event => {
|
||||||
|
event.preventDefault();
|
||||||
|
$$('[data-bulk]').forEach(el => el.classList.add('hidden'));
|
||||||
|
console.log('select', this.value)
|
||||||
|
switch (event.target.value) {
|
||||||
|
case 'enable':
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
break;
|
||||||
|
case 'export':
|
||||||
|
console.log('got here')
|
||||||
|
$('[data-bulk="export"]').classList.remove('hidden');
|
||||||
|
break;
|
||||||
|
case 'update':
|
||||||
|
$('[data-bulk="update"]').classList.remove('hidden');
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleApply: event => {
|
||||||
|
event.preventDefault();
|
||||||
|
let styles;
|
||||||
|
const action = $('#bulk-actions-select').value;
|
||||||
|
const entries = $$('.entry-filter-toggle:checked').map(el => el.closest('.entry'));
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'enable':
|
||||||
|
case 'disable': {
|
||||||
|
const isEnabled = action === 'enable';
|
||||||
|
entries.forEach(entry => {
|
||||||
|
const box = $('.entry-state-toggle', entry);
|
||||||
|
entry.classList.toggle('enable', isEnabled);
|
||||||
|
box.checked = isEnabled;
|
||||||
|
handleEvent.toggle.call(box, event, entry);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'export':
|
||||||
|
styles = entries.map(entry => entry.styleMeta);
|
||||||
|
exportToFile(styles);
|
||||||
|
break;
|
||||||
|
case 'update':
|
||||||
|
checkUpdateAll(entries); // TO DO
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
styles = entries.reduce((acc, entry) => {
|
||||||
|
const style = entry.styleMeta;
|
||||||
|
acc[style.name] = style.id;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
bulk.deleteBulk(event, styles);
|
||||||
|
$('#toggle-all-filters').checked = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$('#bulk-actions-select').value = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
updateBulkFilters: ({target}) => {
|
||||||
|
// total is undefined until initialized
|
||||||
|
if (installed.dataset.total) {
|
||||||
|
// ignore filter checkboxes
|
||||||
|
if (target.type === 'checkbox' && !target.dataset.filter && target.closest('#tools-wrapper, .entry')) {
|
||||||
|
handleEvent.toggleBulkActions({hidden: false});
|
||||||
|
const bulk = $('#toggle-all-filters');
|
||||||
|
const state = target.checked;
|
||||||
|
const visibleEntries = $$('.entry-filter-toggle')
|
||||||
|
.filter(entry => !entry.closest('.entry').classList.contains('hidden'));
|
||||||
|
bulk.indeterminate = false;
|
||||||
|
if (target === bulk) {
|
||||||
|
visibleEntries.forEach(entry => {
|
||||||
|
entry.checked = state;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (visibleEntries.length === visibleEntries.filter(entry => entry.checked === state).length) {
|
||||||
|
bulk.checked = state;
|
||||||
|
} else {
|
||||||
|
bulk.checked = false;
|
||||||
|
bulk.indeterminate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const count = $$('.entry-filter-toggle').filter(entry => entry.checked).length;
|
||||||
|
$('#bulk-filter-count').textContent = count || '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteBulk: (event, styles) => {
|
||||||
|
messageBox({
|
||||||
|
title: t('deleteStyleConfirm'),
|
||||||
|
contents: Object.keys(styles).join(', '),
|
||||||
|
className: 'danger center',
|
||||||
|
buttons: [t('confirmDelete'), t('confirmCancel')],
|
||||||
|
})
|
||||||
|
.then(({button}) => {
|
||||||
|
if (button === 0) {
|
||||||
|
Object.values(styles).forEach(id => API.deleteStyle(id));
|
||||||
|
installed.dataset.total -= Object.keys(styles).length;
|
||||||
|
bulk.updateBulkFilters({target: $('#toggle-all-filters')});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -294,8 +294,7 @@ function importFromString(jsonString) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function exportToFile() {
|
function exportToFile(styles) {
|
||||||
API.getAllStyles().then(styles => {
|
|
||||||
// https://crbug.com/714373
|
// https://crbug.com/714373
|
||||||
document.documentElement.appendChild(
|
document.documentElement.appendChild(
|
||||||
$create('iframe', {
|
$create('iframe', {
|
||||||
|
@ -325,7 +324,6 @@ function exportToFile() {
|
||||||
// we don't remove the iframe or the object URL because the browser may show
|
// we don't remove the iframe or the object URL because the browser may show
|
||||||
// a download dialog and we don't know how long it'll take until the user confirms it
|
// a download dialog and we don't know how long it'll take until the user confirms it
|
||||||
// (some browsers like Vivaldi can't download if we revoke the URL)
|
// (some browsers like Vivaldi can't download if we revoke the URL)
|
||||||
});
|
|
||||||
|
|
||||||
function generateFileName() {
|
function generateFileName() {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
|
@ -89,8 +89,6 @@ function initGlobalEvents() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('change', updateBulkFilters);
|
|
||||||
|
|
||||||
$$('[data-toggle-on-click]').forEach(el => {
|
$$('[data-toggle-on-click]').forEach(el => {
|
||||||
// dataset on SVG doesn't work in Chrome 49-??, works in 57+
|
// dataset on SVG doesn't work in Chrome 49-??, works in 57+
|
||||||
const target = $(el.getAttribute('data-toggle-on-click'));
|
const target = $(el.getAttribute('data-toggle-on-click'));
|
||||||
|
@ -110,6 +108,7 @@ function initGlobalEvents() {
|
||||||
|
|
||||||
// N.B. triggers existing onchange listeners
|
// N.B. triggers existing onchange listeners
|
||||||
setupLivePrefs();
|
setupLivePrefs();
|
||||||
|
bulk.init();
|
||||||
sorter.init();
|
sorter.init();
|
||||||
|
|
||||||
prefs.subscribe([
|
prefs.subscribe([
|
||||||
|
@ -467,34 +466,6 @@ function onVisibilityChange() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBulkFilters({target}) {
|
|
||||||
// total is undefined until initialized
|
|
||||||
if (!installed.dataset.total) return;
|
|
||||||
// ignore filter checkboxes
|
|
||||||
if (target.type === 'checkbox' && !target.dataset.filter && target.closest('#tools-wrapper, .entry')) {
|
|
||||||
handleEvent.toggleBulkActions({hidden: false});
|
|
||||||
const bulk = $('#toggle-all-filters');
|
|
||||||
const state = target.checked;
|
|
||||||
const visibleEntries = $$('.entry-filter-toggle')
|
|
||||||
.filter(entry => !entry.closest('.entry').classList.contains('hidden'));
|
|
||||||
bulk.indeterminate = false;
|
|
||||||
if (target === bulk) {
|
|
||||||
visibleEntries.forEach(entry => {
|
|
||||||
entry.checked = state;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (visibleEntries.length === visibleEntries.filter(entry => entry.checked === state).length) {
|
|
||||||
bulk.checked = state;
|
|
||||||
} else {
|
|
||||||
bulk.checked = false;
|
|
||||||
bulk.indeterminate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const count = $$('.entry-filter-toggle').filter(entry => entry.checked).length;
|
|
||||||
$('#bulk-filter-count').textContent = count || '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeSelection() {
|
function removeSelection() {
|
||||||
const sel = window.getSelection ? window.getSelection() : document.selection;
|
const sel = window.getSelection ? window.getSelection() : document.selection;
|
||||||
if (sel) {
|
if (sel) {
|
||||||
|
|
|
@ -33,15 +33,12 @@ const UI = {
|
||||||
|
|
||||||
// translate CSS manually
|
// translate CSS manually
|
||||||
document.head.appendChild($create('style', `
|
document.head.appendChild($create('style', `
|
||||||
.disabled h2::after {
|
body.all-styles-hidden-by-filters #installed:after {
|
||||||
content: "${t('genericDisabledLabel')}";
|
content: "${t('filteredStylesAllHidden')}";
|
||||||
}
|
}
|
||||||
#update-all-no-updates[data-skipped-edited="true"]::after {
|
#update-all-no-updates[data-skipped-edited="true"]::after {
|
||||||
content: " ${t('updateAllCheckSucceededSomeEdited')}";
|
content: " ${t('updateAllCheckSucceededSomeEdited')}";
|
||||||
}
|
}
|
||||||
body.all-styles-hidden-by-filters::after {
|
|
||||||
content: "${t('filteredStylesAllHidden')}";
|
|
||||||
}
|
|
||||||
`));
|
`));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ a:hover {
|
||||||
.entry-actions > a,
|
.entry-actions > a,
|
||||||
.bulk-actions-select-wrapper,
|
.bulk-actions-select-wrapper,
|
||||||
#bulk-actions-apply {
|
#bulk-actions-apply {
|
||||||
|
position: relative;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +158,13 @@ a:hover {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.all-styles-hidden-by-filters #installed:after {
|
||||||
|
font-size: 20px;
|
||||||
|
position: relative;
|
||||||
|
top: 20px;
|
||||||
|
left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.entry-header {
|
.entry-header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
|
@ -451,18 +459,20 @@ a svg, .svg-icon.sort {
|
||||||
fill: red;
|
fill: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.updater-icons > :not(.check-update):after {
|
.updater-icons > .update:after {
|
||||||
content: attr(data-title);
|
content: attr(data-title);
|
||||||
border: 1px solid gold;
|
border: 1px solid gold;
|
||||||
background-color: goldenrod;
|
background-color: goldenrod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entry-actions .entry-delete:after,
|
||||||
.update-problem .check-update:after {
|
.update-problem .check-update:after {
|
||||||
background-color: red;
|
background-color: #d40000;
|
||||||
border: 1px solid #d40000;
|
border: 1px solid red;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.update-problem.showTip {
|
.update-problem.showTip {
|
||||||
animation: fadeout 10s;
|
animation: fadeout 10s;
|
||||||
animation-fill-mode: both;
|
animation-fill-mode: both;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
--tooltip-bkgd: #333;
|
--tooltip-bkgd: #333;
|
||||||
--tooltip-border: #555;
|
--tooltip-border: #555;
|
||||||
--tooltip-text: #fff;
|
--tooltip-text: #fff;
|
||||||
|
--tooltip-error: #d40000;
|
||||||
|
--tooltip-warn: goldenrod;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-title] {
|
[data-title] {
|
||||||
|
@ -150,3 +152,13 @@
|
||||||
right: -7px;
|
right: -7px;
|
||||||
top: 50%
|
top: 50%
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.can-update .updater-icons .update:before {
|
||||||
|
border-right-color: var(--tooltip-warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-actions .entry-delete:before,
|
||||||
|
.update-problem .check-update:before {
|
||||||
|
border-right-color: var(--tooltip-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
onDOMready().then(() => {
|
onDOMready().then(() => {
|
||||||
$('#check-all-updates').onclick = checkUpdateAll;
|
// $('#check-all-updates').onclick = checkUpdateAll;
|
||||||
$('#check-all-updates-force').onclick = checkUpdateAll;
|
$('#check-all-updates-force').onclick = checkUpdateAll;
|
||||||
$('#apply-all-updates').onclick = applyUpdateAll;
|
$('#apply-all-updates').onclick = applyUpdateAll;
|
||||||
$('#update-history').onclick = showUpdateHistory;
|
$('#update-history').onclick = showUpdateHistory;
|
||||||
|
@ -29,11 +29,11 @@ function applyUpdateAll() {
|
||||||
|
|
||||||
function checkUpdateAll() {
|
function checkUpdateAll() {
|
||||||
document.body.classList.add('update-in-progress');
|
document.body.classList.add('update-in-progress');
|
||||||
const btnCheck = $('#check-all-updates');
|
// const btnCheck = $('#check-all-updates');
|
||||||
const btnCheckForce = $('#check-all-updates-force');
|
const btnCheckForce = $('#check-all-updates-force');
|
||||||
const btnApply = $('#apply-all-updates');
|
const btnApply = $('#apply-all-updates');
|
||||||
const noUpdates = $('#update-all-no-updates');
|
const noUpdates = $('#update-all-no-updates');
|
||||||
btnCheck.disabled = true;
|
// btnCheck.disabled = true;
|
||||||
btnCheckForce.classList.add('hidden');
|
btnCheckForce.classList.add('hidden');
|
||||||
btnApply.classList.add('hidden');
|
btnApply.classList.add('hidden');
|
||||||
noUpdates.classList.add('hidden');
|
noUpdates.classList.add('hidden');
|
||||||
|
@ -82,7 +82,7 @@ function checkUpdateAll() {
|
||||||
|
|
||||||
port.onMessage.removeListener(observer);
|
port.onMessage.removeListener(observer);
|
||||||
document.body.classList.remove('update-in-progress');
|
document.body.classList.remove('update-in-progress');
|
||||||
btnCheck.disabled = total === 0;
|
// btnCheck.disabled = total === 0;
|
||||||
btnApply.disabled = false;
|
btnApply.disabled = false;
|
||||||
renderUpdatesOnlyFilter({check: updated + skippedEdited > 0});
|
renderUpdatesOnlyFilter({check: updated + skippedEdited > 0});
|
||||||
if (!updated) {
|
if (!updated) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user