| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /* global $ $create messageBoxProxy onDOMready */// dom.js
- /* global installed */// manage.js
- /* global prefs */
- /* global t */// localization.js
- 'use strict';
- const sorter = (() => {
- const sorterType = {
- alpha: (a, b) => a < b ? -1 : a === b ? 0 : 1,
- number: (a, b) => (a || 0) - (b || 0),
- };
- const tagData = {
- title: {
- text: t('genericTitle'),
- parse: ({name}) => name,
- sorter: sorterType.alpha,
- },
- usercss: {
- text: 'Usercss',
- parse: ({style}) => style.usercssData ? 0 : 1,
- sorter: sorterType.number,
- },
- disabled: {
- text: '', // added as either "enabled" or "disabled" by the addOptions function
- parse: ({style}) => style.enabled ? 1 : 0,
- sorter: sorterType.number,
- },
- dateInstalled: {
- text: t('dateInstalled'),
- parse: ({style}) => style.installDate,
- sorter: sorterType.number,
- },
- dateUpdated: {
- text: t('dateUpdated'),
- parse: ({style}) => style.updateDate || style.installDate,
- sorter: sorterType.number,
- },
- };
- // Adding (assumed) most commonly used ('title,asc' should always be first)
- // whitespace before & after the comma is ignored
- const selectOptions = [
- '{groupAsc}',
- 'title,asc',
- 'dateInstalled,desc, title,asc',
- 'dateInstalled,asc, title,asc',
- 'dateUpdated,desc, title,asc',
- 'dateUpdated,asc, title,asc',
- 'usercss,asc, title,asc',
- 'usercss,desc, title,asc',
- 'disabled,asc, title,asc',
- 'disabled,desc, title,asc',
- 'disabled,desc, usercss,asc, title,asc',
- '{groupDesc}',
- 'title,desc',
- 'usercss,asc, title,desc',
- 'usercss,desc, title,desc',
- 'disabled,desc, title,desc',
- 'disabled,desc, usercss,asc, title,desc',
- ];
- const splitRegex = /\s*,\s*/;
- let columns = 1;
- onDOMready().then(() => {
- prefs.subscribe('manage.newUI.sort', sorter.update);
- $('#sorter-help').onclick = showHelp;
- addOptions();
- updateColumnCount();
- });
- function addOptions() {
- let container;
- const select = $('#manage.newUI.sort');
- const renderBin = document.createDocumentFragment();
- const option = $create('option');
- const optgroup = $create('optgroup');
- const meta = {
- desc: ' \u21E9',
- enabled: t('genericEnabledLabel'),
- disabled: t('genericDisabledLabel'),
- dateNew: ` (${t('sortDateNewestFirst')})`,
- dateOld: ` (${t('sortDateOldestFirst')})`,
- groupAsc: t('sortLabelTitleAsc'),
- groupDesc: t('sortLabelTitleDesc'),
- };
- selectOptions.forEach(sort => {
- if (/{\w+}/.test(sort)) {
- if (container) {
- renderBin.appendChild(container);
- }
- container = optgroup.cloneNode();
- container.label = meta[sort.substring(1, sort.length - 1)];
- return;
- }
- let lastTag = '';
- const opt = option.cloneNode();
- opt.textContent = sort.split(splitRegex).reduce((acc, val) => {
- if (tagData[val]) {
- lastTag = val;
- return acc + (acc !== '' ? ' + ' : '') + tagData[val].text;
- }
- if (lastTag.indexOf('date') > -1) return acc + meta[val === 'desc' ? 'dateNew' : 'dateOld'];
- if (lastTag === 'disabled') return acc + meta[val === 'desc' ? 'enabled' : 'disabled'];
- return acc + (meta[val] || '');
- }, '');
- opt.value = sort;
- container.appendChild(opt);
- });
- renderBin.appendChild(container);
- select.appendChild(renderBin);
- select.value = prefs.get('manage.newUI.sort');
- }
- return {
- sort({styles}) {
- const sortBy = prefs.get('manage.newUI.sort').split(splitRegex);
- const len = sortBy.length;
- return styles.sort((a, b) => {
- let types, direction;
- let result = 0;
- let index = 0;
- // multi-sort
- while (result === 0 && index < len) {
- types = tagData[sortBy[index++]];
- direction = sortBy[index++] === 'asc' ? 1 : -1;
- result = types.sorter(types.parse(a), types.parse(b)) * direction;
- }
- return result;
- });
- },
- update() {
- if (!installed) return;
- const current = [...installed.children];
- const sorted = sorter.sort({
- styles: current.map(entry => ({
- entry,
- name: entry.styleNameLowerCase,
- style: entry.styleMeta,
- })),
- });
- if (current.some((entry, index) => entry !== sorted[index].entry)) {
- const renderBin = document.createDocumentFragment();
- sorted.forEach(({entry}) => renderBin.appendChild(entry));
- installed.appendChild(renderBin);
- }
- sorter.updateStripes();
- },
- updateStripes({onlyWhenColumnsChanged} = {}) {
- if (onlyWhenColumnsChanged && !updateColumnCount()) return;
- let index = 0;
- let isOdd = false;
- const flipRows = columns % 2 === 0;
- for (const {classList} of installed.children) {
- if (classList.contains('hidden')) continue;
- classList.toggle('odd', isOdd);
- classList.toggle('even', !isOdd);
- if (flipRows && ++index >= columns) {
- index = 0;
- } else {
- isOdd = !isOdd;
- }
- }
- },
- };
- function updateColumnCount() {
- let newValue = 1;
- for (let el = document.documentElement.lastElementChild;
- el.localName === 'style';
- el = el.previousElementSibling) {
- if (el.textContent.includes('--columns:')) {
- newValue = Math.max(1, getComputedStyle(document.documentElement).getPropertyValue('--columns') | 0);
- break;
- }
- }
- if (columns !== newValue) {
- columns = newValue;
- return true;
- }
- }
- async function showHelp(event) {
- event.preventDefault();
- messageBoxProxy.show({
- className: 'help-text center-dialog',
- title: t('sortStylesHelpTitle'),
- contents:
- $create('div',
- t('sortStylesHelp').split('\n').map(line =>
- $create('p', line))),
- buttons: [t('confirmOK')],
- });
- }
- })();
|