Switch to filter text/buttons
This commit is contained in:
parent
2fd08cb041
commit
5047ceb1fa
|
@ -1253,8 +1253,8 @@
|
||||||
"description": "Text for button to apply the selected action"
|
"description": "Text for button to apply the selected action"
|
||||||
},
|
},
|
||||||
"bulkActionsTooltip": {
|
"bulkActionsTooltip": {
|
||||||
"message": "Click to open the filter, search and bulk actions panel",
|
"message": "Bulk actions can be applied to selected styles in this column",
|
||||||
"description": "Text for button to apply the selected action"
|
"description": "Select style for bulk action header tooltip"
|
||||||
},
|
},
|
||||||
"bulkActionsError": {
|
"bulkActionsError": {
|
||||||
"message": "Choose at least one style",
|
"message": "Choose at least one style",
|
||||||
|
|
|
@ -4,13 +4,108 @@
|
||||||
(() => {
|
(() => {
|
||||||
// toLocaleLowerCase cache, autocleared after 1 minute
|
// toLocaleLowerCase cache, autocleared after 1 minute
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
// top-level style properties to be searched
|
|
||||||
const PARTS = {
|
// Creates an array of intermediate words (2 letter minimum)
|
||||||
name: searchText,
|
// 'usercss' => ["us", "use", "user", "userc", "usercs", "usercss"]
|
||||||
url: searchText,
|
// this makes it so the user can type partial queries and not have the search
|
||||||
sourceCode: searchText,
|
// constantly switching between using & ignoring the filter
|
||||||
sections: searchSections,
|
const createPartials = id => id.split('').reduce((acc, _, index) => {
|
||||||
};
|
if (index > 0) {
|
||||||
|
acc.push(id.substring(0, index + 1));
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const searchWithin = [{
|
||||||
|
id: 'code',
|
||||||
|
labels: createPartials('code'),
|
||||||
|
get: style => style.sections.map(section => section.code).join(' ')
|
||||||
|
}, {
|
||||||
|
id: 'usercss',
|
||||||
|
labels: [...createPartials('usercss'), ...createPartials('meta')],
|
||||||
|
get: style => JSON.stringify(style.usercssData || {})
|
||||||
|
// remove JSON structure; restore urls
|
||||||
|
.replace(/[[\]{},":]/g, ' ').replace(/\s\/\//g, '://')
|
||||||
|
}, {
|
||||||
|
id: 'name', // default
|
||||||
|
labels: createPartials('name'),
|
||||||
|
get: style => style.name
|
||||||
|
}];
|
||||||
|
|
||||||
|
const styleProps = [{
|
||||||
|
id: 'enabled',
|
||||||
|
labels: ['on', ...createPartials('enabled')],
|
||||||
|
check: style => style.enabled
|
||||||
|
}, {
|
||||||
|
id: 'disabled',
|
||||||
|
labels: ['off', ...createPartials('disabled')],
|
||||||
|
check: style => !style.enabled
|
||||||
|
}, {
|
||||||
|
id: 'local',
|
||||||
|
labels: createPartials('local'),
|
||||||
|
check: style => !style.updateUrl
|
||||||
|
}, {
|
||||||
|
id: 'external',
|
||||||
|
labels: createPartials('external'),
|
||||||
|
check: style => style.updateUrl
|
||||||
|
}, {
|
||||||
|
id: 'usercss',
|
||||||
|
labels: createPartials('usercss'),
|
||||||
|
check: style => style.usercssData
|
||||||
|
}, {
|
||||||
|
id: 'non usercss',
|
||||||
|
labels: ['original', ...createPartials('nonusercss')],
|
||||||
|
check: style => !style.usercssData
|
||||||
|
}];
|
||||||
|
|
||||||
|
const matchers = [{
|
||||||
|
id: 'url',
|
||||||
|
test: query => /url:\w+/i.test(query),
|
||||||
|
matches: query => {
|
||||||
|
const matchUrl = query.match(/url:([/.-_\w]+)/);
|
||||||
|
const result = matchUrl && matchUrl[1]
|
||||||
|
? styleManager.getStylesByUrl(matchUrl[1])
|
||||||
|
.then(result => result.map(r => r.data.id))
|
||||||
|
: [];
|
||||||
|
return {result};
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'regex',
|
||||||
|
test: query => {
|
||||||
|
const x = query.includes('/') && !query.includes('//') &&
|
||||||
|
/^\/(.+?)\/([gimsuy]*)$/.test(query);
|
||||||
|
// console.log('regex match?', query, x);
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
matches: () => ({regex: tryRegExp(RegExp.$1, RegExp.$2)})
|
||||||
|
}, {
|
||||||
|
id: 'props',
|
||||||
|
test: query => /is:/.test(query),
|
||||||
|
matches: query => {
|
||||||
|
const label = /is:(\w+)/g.exec(query);
|
||||||
|
return label && label[1]
|
||||||
|
? {prop: styleProps.find(p => p.labels.includes(label[1]))}
|
||||||
|
: {};
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: 'within',
|
||||||
|
test: query => /in:/.test(query),
|
||||||
|
matches: query => {
|
||||||
|
const label = /in:(\w+)/g.exec(query);
|
||||||
|
return label && label[1]
|
||||||
|
? {within: searchWithin.find(s => s.labels.includes(label[1]))}
|
||||||
|
: {};
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: 'default',
|
||||||
|
test: () => true,
|
||||||
|
matches: query => {
|
||||||
|
const word = query.startsWith('"') && query.endsWith('"')
|
||||||
|
? query.slice(1, -1)
|
||||||
|
: query;
|
||||||
|
return {word: word || query};
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param params
|
* @param params
|
||||||
|
@ -19,77 +114,94 @@
|
||||||
* @returns {number[]} - array of matched styles ids
|
* @returns {number[]} - array of matched styles ids
|
||||||
*/
|
*/
|
||||||
API_METHODS.searchDB = ({query, ids}) => {
|
API_METHODS.searchDB = ({query, ids}) => {
|
||||||
let rx, words, icase, matchUrl;
|
const parts = query.trim().split(/(".*?")|\s+/).filter(Boolean);
|
||||||
query = query.trim();
|
|
||||||
|
|
||||||
if (/^url:/i.test(query)) {
|
const searchFilters = {
|
||||||
matchUrl = query.slice(query.indexOf(':') + 1).trim();
|
words: [],
|
||||||
if (matchUrl) {
|
regex: null, // only last regex expression is used
|
||||||
return styleManager.getStylesByUrl(matchUrl)
|
results: [],
|
||||||
.then(results => results.map(r => r.data.id));
|
props: [],
|
||||||
|
within: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchText = (text, searchFilters) => {
|
||||||
|
if (searchFilters.regex) return searchFilters.regex.test(text);
|
||||||
|
for (let pass = 1; pass <= (searchFilters.icase ? 2 : 1); pass++) {
|
||||||
|
if (searchFilters.words.every(w => text.includes(w))) return true;
|
||||||
|
text = lower(text);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchProps = (style, searchFilters) => {
|
||||||
|
const x = searchFilters.props.every(prop => {
|
||||||
|
const y = prop.check(style)
|
||||||
|
// if (y) console.log('found prop', prop.id, style.id)
|
||||||
|
return y;
|
||||||
|
});
|
||||||
|
// if (x) console.log('found prop', style.id)
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
parts.forEach(part => {
|
||||||
|
matchers.some(matcher => {
|
||||||
|
if (matcher.test(part)) {
|
||||||
|
const {result, regex, word, prop, within} = matcher.matches(part || '');
|
||||||
|
if (result) searchFilters.results.push(result);
|
||||||
|
if (regex) searchFilters.regex = regex; // limited to a single regexp
|
||||||
|
if (word) searchFilters.words.push(word);
|
||||||
|
if (prop) searchFilters.props.push(prop);
|
||||||
|
if (within) searchFilters.within.push(within);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (query.startsWith('/') && /^\/(.+?)\/([gimsuy]*)$/.test(query)) {
|
});
|
||||||
rx = tryRegExp(RegExp.$1, RegExp.$2);
|
});
|
||||||
|
if (!searchFilters.within.length) {
|
||||||
|
searchFilters.within.push(...searchWithin.slice(-1));
|
||||||
}
|
}
|
||||||
if (!rx) {
|
|
||||||
words = query
|
// console.log('matchers', searchFilters);
|
||||||
.split(/(".*?")|\s+/)
|
// url matches
|
||||||
.filter(Boolean)
|
if (searchFilters.results.length) {
|
||||||
.map(w => w.startsWith('"') && w.endsWith('"')
|
return searchFilters.results;
|
||||||
? w.slice(1, -1)
|
|
||||||
: w)
|
|
||||||
.filter(w => w.length > 1);
|
|
||||||
words = words.length ? words : [query];
|
|
||||||
icase = words.some(w => w === lower(w));
|
|
||||||
}
|
}
|
||||||
|
searchFilters.icase = searchFilters.words.some(w => w === lower(w));
|
||||||
|
query = parts.join(' ').trim();
|
||||||
|
|
||||||
return styleManager.getAllStyles().then(styles => {
|
return styleManager.getAllStyles().then(styles => {
|
||||||
if (ids) {
|
if (ids) {
|
||||||
const idSet = new Set(ids);
|
const idSet = new Set(ids);
|
||||||
styles = styles.filter(s => idSet.has(s.id));
|
styles = styles.filter(s => idSet.has(s.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
|
const propResults = [];
|
||||||
|
const hasProps = searchFilters.props.length > 0;
|
||||||
|
const noWords = searchFilters.words.length === 0;
|
||||||
for (const style of styles) {
|
for (const style of styles) {
|
||||||
const id = style.id;
|
const id = style.id;
|
||||||
if (!query || words && !words.length) {
|
if (noWords) {
|
||||||
|
// no query or only filters are matching -> show all styles
|
||||||
results.push(id);
|
results.push(id);
|
||||||
continue;
|
} else {
|
||||||
}
|
const text = searchFilters.within.map(within => within.get(style)).join(' ');
|
||||||
for (const part in PARTS) {
|
if (searchText(text, searchFilters)) {
|
||||||
const text = style[part];
|
|
||||||
if (text && PARTS[part](text, rx, words, icase)) {
|
|
||||||
results.push(id);
|
results.push(id);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hasProps && searchProps(style, searchFilters) && results.includes(id)) {
|
||||||
|
propResults.push(id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// results AND propResults
|
||||||
|
const finalResults = hasProps
|
||||||
|
? propResults.filter(id => results.includes(id))
|
||||||
|
: results;
|
||||||
if (cache.size) debounce(clearCache, 60e3);
|
if (cache.size) debounce(clearCache, 60e3);
|
||||||
return results;
|
// console.log('final', finalResults)
|
||||||
|
return finalResults;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function searchText(text, rx, words, icase) {
|
|
||||||
if (rx) return rx.test(text);
|
|
||||||
for (let pass = 1; pass <= (icase ? 2 : 1); pass++) {
|
|
||||||
if (words.every(w => text.includes(w))) return true;
|
|
||||||
text = lower(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchSections(sections, rx, words, icase) {
|
|
||||||
for (const section of sections) {
|
|
||||||
for (const prop in section) {
|
|
||||||
const value = section[prop];
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
if (searchText(value, rx, words, icase)) return true;
|
|
||||||
} else if (Array.isArray(value)) {
|
|
||||||
if (value.some(str => searchText(str, rx, words, icase))) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function lower(text) {
|
function lower(text) {
|
||||||
let result = cache.get(text);
|
let result = cache.get(text);
|
||||||
if (result) return result;
|
if (result) return result;
|
||||||
|
|
321
manage.html
321
manage.html
|
@ -221,10 +221,7 @@
|
||||||
<span class="filter-stats-wrapper">
|
<span class="filter-stats-wrapper">
|
||||||
<span id="filters-stats"></span>
|
<span id="filters-stats"></span>
|
||||||
<a id="reset-filters" class="tt-e" href="#" tabindex="0" i18n-data-title="genericResetLabel">
|
<a id="reset-filters" class="tt-e" href="#" tabindex="0" i18n-data-title="genericResetLabel">
|
||||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
<svg class="svg-icon" viewBox="0 0 20 20"><use xlink:href="#svg-icon-x"/></svg>
|
||||||
<polygon points="16.2,5.5 14.5,3.8 10,8.3 5.5,3.8 3.8,5.5 8.3,10 3.8,14.5
|
|
||||||
5.5,16.2 10,11.7 14.5,16.2 16.2,14.5 11.7,10 "/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -256,12 +253,6 @@
|
||||||
|
|
||||||
<span class="spacer"></span>
|
<span class="spacer"></span>
|
||||||
|
|
||||||
<a href="#" id="update-all" class="tt-w" i18n-data-title="checkAllUpdates">
|
|
||||||
<svg class="svg-icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M11 8v5l4.25 2.52.77-1.28-3.52-2.09V8zm10 2V3l-2.64 2.64A9 9 0 1 0 21 12h-2a7 7 0 1 1-2.05-4.95L14 10h7z"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="manage-backups tt-w" i18n-data-title="backupImport">
|
<div class="manage-backups tt-w" i18n-data-title="backupImport">
|
||||||
<svg class="svg-icon" viewBox="0 0 24 24">
|
<svg class="svg-icon" viewBox="0 0 24 24">
|
||||||
<path d="M20.54 5.23l-1.39-1.68A1.45 1.45 0 0 0 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V6.5c0-.48-.17-.93-.46-1.27zM6.24 5h11.52l.81.97H5.44l.8-.97zM5 19V8h14v11H5zm8.45-9h-2.9v3H8l4 4 4-4h-2.55z"/>
|
<path d="M20.54 5.23l-1.39-1.68A1.45 1.45 0 0 0 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V6.5c0-.48-.17-.93-.46-1.27zM6.24 5h11.52l.81.97H5.44l.8-.97zM5 19V8h14v11H5zm8.45-9h-2.9v3H8l4 4 4-4h-2.55z"/>
|
||||||
|
@ -329,98 +320,7 @@
|
||||||
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div id="tools-wrapper" class="hidden">
|
<div id="tools-wrapper">
|
||||||
|
|
||||||
<div class="manage-row">
|
|
||||||
<span id="search-wrapper">
|
|
||||||
<input id="search" type="search" i18n-placeholder="searchStyles" spellcheck="false"
|
|
||||||
data-filter=":not(.not-matching)"
|
|
||||||
data-filter-hide=".not-matching">
|
|
||||||
<a href="#" id="search-help" tabindex="0">
|
|
||||||
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span id="filters-wrapper">
|
|
||||||
<strong i18n-text="manageFilters"></strong>
|
|
||||||
<span class="filter-selection">
|
|
||||||
<label class="checkmate" tabindex="0">
|
|
||||||
<input id="manage.onlyEnabled" type="checkbox"
|
|
||||||
data-filter=".enabled"
|
|
||||||
data-filter-hide=".disabled">
|
|
||||||
<svg class="svg-icon checkbox"viewBox="0 0 10 10">
|
|
||||||
<path class="filled-circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86z"/>
|
|
||||||
<path class="circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86zm0 7.5a3.36 3.36 0 1 1 0-6.72 3.36 3.36 0 0 1 0 6.72z"/>
|
|
||||||
<path class="checkmark" d="M6.86 3.21L4.14 5.93 3.07 4.86l-.57.57 1.64 1.71L7.5 3.8l-.64-.58z"/>
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
<span class="select-resizer">
|
|
||||||
<select id="manage.onlyEnabled.invert">
|
|
||||||
<option i18n-text="manageOnlyEnabled" value="false"></option>
|
|
||||||
<option i18n-text="manageOnlyDisabled" value="true"></option>
|
|
||||||
</select>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="filter-selection">
|
|
||||||
<label class="checkmate" tabindex="0">
|
|
||||||
<input id="manage.onlyLocal" type="checkbox"
|
|
||||||
data-filter=":not(.updatable):not(.update-done)"
|
|
||||||
data-filter-hide=".updatable, .update-done">
|
|
||||||
<svg class="svg-icon checkbox"viewBox="0 0 10 10">
|
|
||||||
<path class="filled-circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86z"/>
|
|
||||||
<path class="circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86zm0 7.5a3.36 3.36 0 1 1 0-6.72 3.36 3.36 0 0 1 0 6.72z"/>
|
|
||||||
<path class="checkmark" d="M6.86 3.21L4.14 5.93 3.07 4.86l-.57.57 1.64 1.71L7.5 3.8l-.64-.58z"/>
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
<span class="select-resizer">
|
|
||||||
<select id="manage.onlyLocal.invert" class="tt-s" i18n-data-title="manageOnlyLocalTooltip">
|
|
||||||
<option i18n-text="manageOnlyLocal" value="false"></option>
|
|
||||||
<option i18n-text="manageOnlyExternal" value="true"></option>
|
|
||||||
</select>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="filter-selection">
|
|
||||||
<label class="checkmate" tabindex="0">
|
|
||||||
<input id="manage.onlyUsercss" type="checkbox"
|
|
||||||
data-filter=".usercss"
|
|
||||||
data-filter-hide=":not(.usercss)">
|
|
||||||
<svg class="svg-icon checkbox"viewBox="0 0 10 10">
|
|
||||||
<path class="filled-circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86z"/>
|
|
||||||
<path class="circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86zm0 7.5a3.36 3.36 0 1 1 0-6.72 3.36 3.36 0 0 1 0 6.72z"/>
|
|
||||||
<path class="checkmark" d="M6.86 3.21L4.14 5.93 3.07 4.86l-.57.57 1.64 1.71L7.5 3.8l-.64-.58z"/>
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
<span class="select-resizer">
|
|
||||||
<select id="manage.onlyUsercss.invert">
|
|
||||||
<option i18n-text="manageOnlyUsercss" value="false"></option>
|
|
||||||
<option i18n-text="manageOnlyNonUsercss" value="true"></option>
|
|
||||||
</select>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="filter-selection">
|
|
||||||
<label id="only-updates" class="hidden checkmate" tabindex="0">
|
|
||||||
<input type="checkbox"
|
|
||||||
data-filter=".can-update, .update-problem, .update-done"
|
|
||||||
data-filter-hide=":not(.updatable):not(.update-done),
|
|
||||||
.no-update:not(.update-problem),
|
|
||||||
.updatable:not(.can-update):not(.update-problem):not(.update-done)">
|
|
||||||
<svg class="svg-icon checkbox"viewBox="0 0 10 10">
|
|
||||||
<path class="filled-circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86z"/>
|
|
||||||
<path class="circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86zm0 7.5a3.36 3.36 0 1 1 0-6.72 3.36 3.36 0 0 1 0 6.72z"/>
|
|
||||||
<path class="checkmark" d="M6.86 3.21L4.14 5.93 3.07 4.86l-.57.57 1.64 1.71L7.5 3.8l-.64-.58z"/>
|
|
||||||
</svg>
|
|
||||||
<span i18n-text="manageOnlyUpdates"></span>
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="bulk-actions" class="manage-row">
|
<div id="bulk-actions" class="manage-row">
|
||||||
<label class="checkmate toggle-all" tabindex="0">
|
<label class="checkmate toggle-all" tabindex="0">
|
||||||
|
@ -450,6 +350,13 @@
|
||||||
<button id="bulk-actions-apply" i18n-text="bulkActionsApply" class="tt-e" disabled>
|
<button id="bulk-actions-apply" i18n-text="bulkActionsApply" class="tt-e" disabled>
|
||||||
<span id="update-progress"></span>
|
<span id="update-progress"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button href="#" id="update-all" class="tt-w" i18n-data-title="checkAllUpdates" type="button">
|
||||||
|
<svg class="svg-icon" viewBox="0 0 24 24">
|
||||||
|
<path d="M11 8v5l4.25 2.52.77-1.28-3.52-2.09V8zm10 2V3l-2.64 2.64A9 9 0 1 0 21 12h-2a7 7 0 1 1-2.05-4.95L14 10h7z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
<span id="bulk-info">
|
<span id="bulk-info">
|
||||||
<!-- Bulk update -->
|
<!-- Bulk update -->
|
||||||
<span data-bulk="update">
|
<span data-bulk="update">
|
||||||
|
@ -485,13 +392,96 @@
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="manage-row">
|
||||||
|
<div id="search-wrapper">
|
||||||
|
<input id="search" type="search" i18n-placeholder="searchStyles" spellcheck="false"
|
||||||
|
data-filter=":not(.not-matching)"
|
||||||
|
data-filter-hide=".not-matching">
|
||||||
|
</div>
|
||||||
|
<div id="filters-wrapper">
|
||||||
|
<button
|
||||||
|
class="reset-filters search-filter tt-w"
|
||||||
|
type="button"
|
||||||
|
i18n-data-title="genericResetLabel"
|
||||||
|
data-filter=".entry"
|
||||||
|
data-filter-hide=".disabled"
|
||||||
|
>
|
||||||
|
<svg class="svg-icon"><use xlink:href="#svg-icon-x"/></svg>
|
||||||
|
</button>
|
||||||
|
<span class="button-group">
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyEnabled">
|
||||||
|
<input
|
||||||
|
id="manage.onlyEnabled"
|
||||||
|
name="enabled"
|
||||||
|
type="radio"
|
||||||
|
data-filter=".enabled"
|
||||||
|
data-filter-hide=".disabled"
|
||||||
|
/>
|
||||||
|
<svg class="svg-icon checkbox-enabled" viewBox="0 0 10 10">
|
||||||
|
<path d="M6.86 3.21L4.14 5.93 3.07 4.86l-.57.57 1.64 1.71L7.5 3.8l-.64-.58z"/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyDisabled">
|
||||||
|
<input id="manage.onlyEnabled.invert" name="enabled" type="radio" />
|
||||||
|
<svg class="svg-icon checkbox"viewBox="0 0 10 10">
|
||||||
|
<path class="circle" d="M5 .86a4.14 4.14 0 0 0 0 8.28A4.14 4.14 0 1 0 5 .86zm0 7.5a3.36 3.36 0 1 1 0-6.72 3.36 3.36 0 0 1 0 6.72z"/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="button-group">
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyUsercss">
|
||||||
|
<input
|
||||||
|
id="manage.onlyUsercss"
|
||||||
|
name="usercss"
|
||||||
|
type="radio"
|
||||||
|
data-filter=".usercss"
|
||||||
|
data-filter-hide=":not(.usercss)"
|
||||||
|
/>
|
||||||
|
<span>usercss</span> <!-- TODO: localize -->
|
||||||
|
</label>
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyNonUsercss">
|
||||||
|
<input type="radio" id="manage.onlyUsercss.invert" name="usercss" />
|
||||||
|
<span>non-usercss</span> <!-- TODO: localize -->
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="button-group">
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyLocal">
|
||||||
|
<input
|
||||||
|
id="manage.onlyLocal"
|
||||||
|
name="local"
|
||||||
|
type="radio"
|
||||||
|
data-filter=":not(.updatable):not(.update-done)"
|
||||||
|
data-filter-hide=".updatable, .update-done"
|
||||||
|
/>
|
||||||
|
<span>local</span> <!-- TODO: localize -->
|
||||||
|
</label>
|
||||||
|
<label class="search-filter tt-w" i18n-data-title="manageOnlyExternal">
|
||||||
|
<input id="manage.onlyLocal.invert" name="local" type="radio" />
|
||||||
|
<span>external</span> <!-- TODO: localize -->
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<label class="search-filter hidden">
|
||||||
|
<input
|
||||||
|
id="only-updates"
|
||||||
|
type="checkbox"
|
||||||
|
data-filter=".can-update, .update-problem, .update-done"
|
||||||
|
data-filter-hide=":not(.updatable):not(.update-done),
|
||||||
|
.no-update:not(.update-problem),
|
||||||
|
.updatable:not(.can-update):not(.update-problem):not(.update-done)"
|
||||||
|
/>
|
||||||
|
<span i18n-text="manageOnlyUpdates"></span>
|
||||||
|
</label>
|
||||||
|
<a href="#" id="search-help">
|
||||||
|
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="installed" class="manage-col-entries">
|
<div id="installed" class="manage-col-entries">
|
||||||
<header class="entry-header">
|
<header class="entry-header">
|
||||||
<div class="entry-col header-filter center-text tt-se" i18n-data-title="bulkActionsTooltip">
|
<div class="entry-col header-filter center-text tt-se" i18n-data-title="bulkActionsTooltip">
|
||||||
<span></span>
|
<svg class="svg-icon no-pointer" width="20" height="20" viewBox="0 0 14 14">
|
||||||
<svg class="svg-icon" width="20" height="20" viewBox="0 0 14 14">
|
|
||||||
<path d="M6.42 7.58L2.92 3.5h8.75l-3.5 4.08v4.09c-1 0-1.75-.76-1.75-1.75V7.58z"/>
|
<path d="M6.42 7.58L2.92 3.5h8.75l-3.5 4.08v4.09c-1 0-1.75-.76-1.75-1.75V7.58z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
@ -563,125 +553,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div id="manage-settings">
|
|
||||||
<div class="settings-column">
|
|
||||||
|
|
||||||
<div id="style-actions">
|
|
||||||
|
|
||||||
|
|
||||||
<div id="add-style-wrapper">
|
|
||||||
<a href="edit.html">
|
|
||||||
<button id="add-style-label" i18n-text="addStyleLabel" tabindex="-1"></button>
|
|
||||||
</a>
|
|
||||||
<label id="add-style-as-usercss-wrapper">
|
|
||||||
<input type="checkbox" id="newStyleAsUsercss">
|
|
||||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
|
||||||
<span i18n-text="manageNewStyleAsUsercss" i18n-title="optionsAdvancedNewStyleAsUsercss"></span>
|
|
||||||
<a id="usercss-wiki"
|
|
||||||
href="https://github.com/openstyles/stylus/wiki/Usercss"
|
|
||||||
i18n-title="externalUsercssDocument"
|
|
||||||
tabindex="0">
|
|
||||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
|
||||||
<path d="M4,4h5v2H6v8h8v-3h2v5H4V4z M11,3h6v6l-2-2l-4,4L9,9l4-4L11,3z"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="settings-column">
|
|
||||||
<details id="options" data-pref="manage.options.expanded">
|
|
||||||
|
|
||||||
<summary><h2 id="options-heading" i18n-text="optionsHeading"></h2></summary>
|
|
||||||
|
|
||||||
<label>
|
|
||||||
<input id="manage.newUI" type="checkbox">
|
|
||||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
|
||||||
<span i18n-text="manageNewUI"></span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div id="newUIoptions">
|
|
||||||
<div>
|
|
||||||
<label for="manage.newUI.favicons" i18n-text="manageFavicons">
|
|
||||||
<input id="manage.newUI.favicons" type="checkbox">
|
|
||||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
|
||||||
<a href="#" data-toggle-on-click="#faviconsHelp" tabindex="0">
|
|
||||||
<svg class="svg-icon select-arrow">
|
|
||||||
<title i18n-text="optionsSubheading"></title>
|
|
||||||
<use xlink:href="#svg-icon-select-arrow"/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</label>
|
|
||||||
<div id="faviconsHelp" class="hidden" i18n-text="manageFaviconsHelp">
|
|
||||||
<div>
|
|
||||||
<label for="manage.newUI.faviconsGray" i18n-text="manageFaviconsGray">
|
|
||||||
<input id="manage.newUI.faviconsGray" type="checkbox">
|
|
||||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<label><input id="manage.newUI.targets" type="number" min="1" max="99"><span i18n-text="manageMaxTargets"></span></label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="options-buttons">
|
|
||||||
<button id="manage-options-button" i18n-text="openOptions"></button>
|
|
||||||
<button id="manage-shortcuts-button" class="chromium-only"
|
|
||||||
i18n-text="shortcuts"
|
|
||||||
i18n-title="shortcutsNote"></button>
|
|
||||||
<a id="find-editor-styles"
|
|
||||||
href="https://userstyles.org/styles/browse/chrome-extension"
|
|
||||||
i18n-title="editorStylesButton"
|
|
||||||
target="_blank"><button i18n-text="cm_theme" tabindex="-1"></button></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="backup" data-pref="manage.backup.expanded">
|
|
||||||
<summary><h2 id="backup-title" i18n-text="backupButtons"></h2></summary>
|
|
||||||
<span id="backup-message" i18n-text="backupMessage"></span>
|
|
||||||
<div id="backup-buttons">
|
|
||||||
<div class="dropdown">
|
|
||||||
<button class="dropbtn">
|
|
||||||
<span>Export</span>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="dropdown-content">
|
|
||||||
<a href="#" id="file-all-styles" i18n-text="bckpInstStyles"></a>
|
|
||||||
<a id="sync-dropbox-export" i18n-text="syncDropboxStyles" i18n-title="syncDropboxDeprecated"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dropdown">
|
|
||||||
<button class="dropbtn">
|
|
||||||
<span>Import</span>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="dropdown-content">
|
|
||||||
<a href="#" id="unfile-all-styles" i18n-text="retrieveBckp"></a>
|
|
||||||
<a id="sync-dropbox-import" i18n-text="retrieveDropboxSync" i18n-title="syncDropboxDeprecated"></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<div id="manage-text">
|
|
||||||
<span><a href="https://userstyles.org" target="_blank" i18n-text="linkGetStyles"></a></span>
|
|
||||||
<span><a href="https://add0n.com/stylus.html#features" target="_blank" i18n-text="linkGetHelp"></a></span>
|
|
||||||
<span><a href="https://github.com/openstyles/stylus/wiki" target="_blank" i18n-text="linkStylusWiki"></a></span>
|
|
||||||
<span><a href="https://www.transifex.com/github-7/Stylus" target="_blank" i18n-text="linkTranslate"></a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="installed"></div> -->
|
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">
|
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">
|
||||||
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
|
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
|
||||||
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,
|
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,
|
||||||
|
@ -723,6 +594,10 @@
|
||||||
1.13zM12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/>
|
1.13zM12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
||||||
|
<symbol id="svg-icon-x" viewBox="0 0 20 20">
|
||||||
|
<polygon points="16.2,5.5 14.5,3.8 10,8.3 5.5,3.8 3.8,5.5 8.3,10 3.8,14.5
|
||||||
|
5.5,16.2 10,11.7 14.5,16.2 16.2,14.5 11.7,10 "/>
|
||||||
|
</symbol>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -104,7 +104,6 @@ const bulk = {
|
||||||
if (installed.dataset.total) {
|
if (installed.dataset.total) {
|
||||||
// ignore filter checkboxes
|
// ignore filter checkboxes
|
||||||
if (target.type === 'checkbox' && target.closest('.toggle-all, .entry-filter')) {
|
if (target.type === 'checkbox' && target.closest('.toggle-all, .entry-filter')) {
|
||||||
handleEvent.toggleBulkActions({hidden: false});
|
|
||||||
const bulk = $('#toggle-all-filters');
|
const bulk = $('#toggle-all-filters');
|
||||||
const state = target.checked;
|
const state = target.checked;
|
||||||
const visibleEntries = $$('.entry-filter-toggle')
|
const visibleEntries = $$('.entry-filter-toggle')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global installed messageBox sorter $ $$ $create t debounce prefs API router */
|
/* global installed messageBox sorter $ $$ $create t debounce prefs API UI router resetUpdates */
|
||||||
/* exported filterAndAppend */
|
/* exported filterAndAppend */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ HTMLSelectElement.prototype.adjustWidth = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$('#search').oninput = e => {
|
$('#search').oninput = event => {
|
||||||
router.updateSearch('search', e.target.value);
|
router.updateSearch('search', event.target.value);
|
||||||
|
UI.updateFilterLabels();
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#search-help').onclick = event => {
|
$('#search-help').onclick = event => {
|
||||||
|
@ -57,48 +58,13 @@ function init() {
|
||||||
} else {
|
} else {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
})))),
|
}))
|
||||||
|
)
|
||||||
|
),
|
||||||
buttons: [t('confirmOK')],
|
buttons: [t('confirmOK')],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$$('select[id$=".invert"]').forEach(el => {
|
|
||||||
const slave = $('#' + el.id.replace('.invert', ''));
|
|
||||||
const slaveData = slave.dataset;
|
|
||||||
const valueMap = new Map([
|
|
||||||
[false, slaveData.filter],
|
|
||||||
[true, slaveData.filterHide],
|
|
||||||
]);
|
|
||||||
// enable slave control when user switches the value
|
|
||||||
el.oninput = () => {
|
|
||||||
if (!slave.checked) {
|
|
||||||
// oninput occurs before onchange
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!slave.checked) {
|
|
||||||
slave.checked = true;
|
|
||||||
slave.dispatchEvent(new Event('change', {bubbles: true}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// swap slave control's filtering rules
|
|
||||||
el.onchange = event => {
|
|
||||||
const value = el.value === 'true';
|
|
||||||
const filter = valueMap.get(value);
|
|
||||||
if (slaveData.filter === filter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
slaveData.filter = filter;
|
|
||||||
slaveData.filterHide = valueMap.get(!value);
|
|
||||||
debounce(filterOnChange, 0, event);
|
|
||||||
// avoid triggering MutationObserver during page load
|
|
||||||
if (document.readyState === 'complete') {
|
|
||||||
el.adjustWidth();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
el.onchange({target: el});
|
|
||||||
});
|
|
||||||
|
|
||||||
$$('[data-filter]').forEach(el => {
|
$$('[data-filter]').forEach(el => {
|
||||||
el.onchange = filterOnChange;
|
el.onchange = filterOnChange;
|
||||||
if (el.closest('.hidden')) {
|
if (el.closest('.hidden')) {
|
||||||
|
@ -108,9 +74,9 @@ function init() {
|
||||||
|
|
||||||
$('#reset-filters').onclick = event => {
|
$('#reset-filters').onclick = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!filtersSelector.hide) {
|
// if (!filtersSelector.hide) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
for (const el of $$('#tools-wrapper [data-filter]')) {
|
for (const el of $$('#tools-wrapper [data-filter]')) {
|
||||||
let value;
|
let value;
|
||||||
if (el.type === 'checkbox' && el.checked) {
|
if (el.type === 'checkbox' && el.checked) {
|
||||||
|
@ -127,6 +93,8 @@ function init() {
|
||||||
}
|
}
|
||||||
filterOnChange({forceRefilter: true});
|
filterOnChange({forceRefilter: true});
|
||||||
router.updateSearch('search', '');
|
router.updateSearch('search', '');
|
||||||
|
resetUpdates();
|
||||||
|
UI.updateFilterLabels();
|
||||||
};
|
};
|
||||||
|
|
||||||
filterOnChange({forceRefilter: true});
|
filterOnChange({forceRefilter: true});
|
||||||
|
@ -134,7 +102,7 @@ function init() {
|
||||||
|
|
||||||
|
|
||||||
function filterOnChange({target: el, forceRefilter}) {
|
function filterOnChange({target: el, forceRefilter}) {
|
||||||
const getValue = el => (el.type === 'checkbox' ? el.checked : el.value.trim());
|
const getValue = elm => (elm.type === 'search') ? elm.value.trim() : elm.checked;
|
||||||
if (!forceRefilter) {
|
if (!forceRefilter) {
|
||||||
const value = getValue(el);
|
const value = getValue(el);
|
||||||
if (value === el.lastValue) {
|
if (value === el.lastValue) {
|
||||||
|
@ -155,6 +123,7 @@ function filterOnChange({target: el, forceRefilter}) {
|
||||||
hide: buildFilter(true),
|
hide: buildFilter(true),
|
||||||
unhide: buildFilter(false),
|
unhide: buildFilter(false),
|
||||||
});
|
});
|
||||||
|
console.log('filter on change', filtersSelector, installed)
|
||||||
if (installed) {
|
if (installed) {
|
||||||
reapplyFilter().then(sorter.updateStripes);
|
reapplyFilter().then(sorter.updateStripes);
|
||||||
}
|
}
|
||||||
|
@ -283,6 +252,7 @@ function searchStyles({immediately, container} = {}) {
|
||||||
el.lastValue = query;
|
el.lastValue = query;
|
||||||
|
|
||||||
const entries = container && container.children || container || installed.children;
|
const entries = container && container.children || container || installed.children;
|
||||||
|
console.log('search?', query)
|
||||||
return API.searchDB({
|
return API.searchDB({
|
||||||
query,
|
query,
|
||||||
ids: [...entries].map(el => el.styleId),
|
ids: [...entries].map(el => el.styleId),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* global messageBox styleSectionsEqual API onDOMready
|
/* global messageBox styleSectionsEqual API onDOMready
|
||||||
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
|
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
|
||||||
|
handleEvent
|
||||||
styleJSONseemsValid */
|
styleJSONseemsValid */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -46,8 +47,9 @@ onDOMready().then(() => {
|
||||||
this.ondragend();
|
this.ondragend();
|
||||||
if (event.dataTransfer.files.length) {
|
if (event.dataTransfer.files.length) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if ($('#only-updates input').checked) {
|
const updates = $('#only-updates');
|
||||||
$('#only-updates input').click();
|
if (updates.checked) {
|
||||||
|
handleEvent.checkFilterSelectors(updates);
|
||||||
}
|
}
|
||||||
importFromFile({file: event.dataTransfer.files[0]});
|
importFromFile({file: event.dataTransfer.files[0]});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
global messageBox getStyleWithNoCode
|
global messageBox getStyleWithNoCode
|
||||||
filterAndAppend showFiltersStats
|
filterAndAppend showFiltersStats
|
||||||
checkUpdate handleUpdateInstalled
|
checkUpdate handleUpdateInstalled resetUpdates
|
||||||
objectDiff
|
objectDiff
|
||||||
configDialog
|
configDialog
|
||||||
sorter msg prefs API onDOMready $ $$ setupLivePrefs
|
sorter msg prefs API onDOMready $ $$ setupLivePrefs
|
||||||
|
@ -80,8 +80,19 @@ function initGlobalEvents() {
|
||||||
|
|
||||||
$('#update-all').onclick = event => {
|
$('#update-all').onclick = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleEvent.toggleBulkActions({hidden: false});
|
|
||||||
bulk.updateAll();
|
bulk.updateAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#filters-wrapper').onclick = event => {
|
||||||
|
event.preventDefault();
|
||||||
|
handleEvent.toggleFilter(event.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#search').onsearch = event => {
|
||||||
|
if (event.target.value === '') {
|
||||||
|
console.log('search empty')
|
||||||
|
handleEvent.resetFilters();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$$('#header a[href^="http"]').forEach(a => (a.onclick = handleEvent.external));
|
$$('#header a[href^="http"]').forEach(a => (a.onclick = handleEvent.external));
|
||||||
|
@ -95,28 +106,12 @@ function initGlobalEvents() {
|
||||||
$$('.applies-to-extra[open]').forEach(el => {
|
$$('.applies-to-extra[open]').forEach(el => {
|
||||||
el.removeAttribute('open');
|
el.removeAttribute('open');
|
||||||
});
|
});
|
||||||
// Close bulk actions
|
|
||||||
handleEvent.toggleBulkActions({hidden: true});
|
|
||||||
} else if (event.which === 32 && event.target.classList.contains('checkmate')) {
|
} else if (event.which === 32 && event.target.classList.contains('checkmate')) {
|
||||||
// pressing space toggles the containing checkbox
|
// pressing space toggles the containing checkbox
|
||||||
$('input[type="checkbox"]', event.target).click();
|
$('input[type="checkbox"]', event.target).click();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$$('[data-toggle-on-click]').forEach(el => {
|
|
||||||
// dataset on SVG doesn't work in Chrome 49-??, works in 57+
|
|
||||||
const target = $(el.getAttribute('data-toggle-on-click'));
|
|
||||||
el.onclick = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
target.classList.toggle('hidden');
|
|
||||||
if (target.classList.contains('hidden')) {
|
|
||||||
el.removeAttribute('open');
|
|
||||||
} else {
|
|
||||||
el.setAttribute('open', '');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// triggered automatically by setupLivePrefs() below
|
// triggered automatically by setupLivePrefs() below
|
||||||
enforceInputRange($('#manage.newUI.targets'));
|
enforceInputRange($('#manage.newUI.targets'));
|
||||||
|
|
||||||
|
@ -146,7 +141,6 @@ Object.assign(handleEvent, {
|
||||||
'.update': 'update',
|
'.update': 'update',
|
||||||
'.entry-delete': 'delete',
|
'.entry-delete': 'delete',
|
||||||
'.entry-configure-usercss': 'config',
|
'.entry-configure-usercss': 'config',
|
||||||
'.header-filter': 'toggleBulkActions',
|
|
||||||
'.sortable': 'updateSort',
|
'.sortable': 'updateSort',
|
||||||
'#applies-to-config': 'appliesConfig',
|
'#applies-to-config': 'appliesConfig',
|
||||||
'.applies-to-extra-expander': 'toggleExtraAppliesTo'
|
'.applies-to-extra-expander': 'toggleExtraAppliesTo'
|
||||||
|
@ -215,12 +209,6 @@ Object.assign(handleEvent, {
|
||||||
UI.addLabels(entry);
|
UI.addLabels(entry);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleBulkActions({hidden}) {
|
|
||||||
const tools = $('#tools-wrapper');
|
|
||||||
tools.classList.toggle('hidden', hidden);
|
|
||||||
$('.header-filter').classList.toggle('active', !tools.classList.contains('hidden'));
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleExtraAppliesTo(event, entry) {
|
toggleExtraAppliesTo(event, entry) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
entry.classList.toggle('hide-extra');
|
entry.classList.toggle('hide-extra');
|
||||||
|
@ -230,6 +218,59 @@ Object.assign(handleEvent, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetFilters() {
|
||||||
|
$('#reset-filters').click();
|
||||||
|
// TODO: figure out why we need to press this twice
|
||||||
|
$('#reset-filters').click();
|
||||||
|
resetUpdates();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleFilter(el) {
|
||||||
|
if (el.classList.contains('reset-filters')) {
|
||||||
|
return handleEvent.resetFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = (el.nodeName === 'LABEL') ? $('input', el) : el;
|
||||||
|
const type = Object.values(UI.searchFilters).find(filter => filter.id === target.id);
|
||||||
|
const filterQuery = type && type.query || '';
|
||||||
|
const remove = type && type.invert ? UI.searchFilters[type.invert].query : '';
|
||||||
|
const len = filterQuery.length + 1;
|
||||||
|
const search = $('#search');
|
||||||
|
|
||||||
|
let {selectionStart, selectionEnd, value} = search;
|
||||||
|
if (value.includes(filterQuery)) {
|
||||||
|
value = ` ${value} `.replace(` ${filterQuery} `, ' ').trim();
|
||||||
|
if (selectionEnd > value.length) {
|
||||||
|
selectionStart -= len;
|
||||||
|
selectionEnd -= len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (selectionEnd === value.length) {
|
||||||
|
selectionStart += len;
|
||||||
|
selectionEnd += len;
|
||||||
|
}
|
||||||
|
value = (` ${value} ${filterQuery} `.replace(` ${remove} `, ' ')).trim();
|
||||||
|
}
|
||||||
|
search.value = value;
|
||||||
|
search.selectionStart = selectionStart;
|
||||||
|
search.selectionEnd = selectionEnd;
|
||||||
|
search.focus();
|
||||||
|
router.updateSearch('search', value);
|
||||||
|
UI.updateFilterLabels();
|
||||||
|
// updates or issues (special case)
|
||||||
|
if (target.dataset.filterSelectors) {
|
||||||
|
handleEvent.checkFilterSelectors(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkFilterSelectors(target) {
|
||||||
|
const selectors = target.dataset.filterSelectors;
|
||||||
|
const checked = target.classList.contains('checked');
|
||||||
|
$$('.entry').forEach(entry => {
|
||||||
|
entry.classList.toggle('hidden', checked && !entry.matches(selectors));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
check(event, entry) {
|
check(event, entry) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
checkUpdate(entry, {single: true});
|
checkUpdate(entry, {single: true});
|
||||||
|
|
|
@ -40,6 +40,11 @@ const UI = {
|
||||||
content: "${t('filteredStylesAllHidden')}";
|
content: "${t('filteredStylesAllHidden')}";
|
||||||
}
|
}
|
||||||
`));
|
`));
|
||||||
|
// remove update filter on init
|
||||||
|
const search = $('#search');
|
||||||
|
search.value = search.value.replace(UI.searchFilters.updatable.query, '');
|
||||||
|
// update filter labels to match location.search
|
||||||
|
UI.updateFilterLabels();
|
||||||
},
|
},
|
||||||
|
|
||||||
showStyles: (styles = [], matchUrlIds) => {
|
showStyles: (styles = [], matchUrlIds) => {
|
||||||
|
@ -178,6 +183,24 @@ const UI = {
|
||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateFilterLabels: () => {
|
||||||
|
const filterLabels = $$('#filters-wrapper .search-filter input');
|
||||||
|
filterLabels.forEach(cb => {
|
||||||
|
cb.checked = false;
|
||||||
|
cb.parentElement.classList.remove('checked');
|
||||||
|
});
|
||||||
|
const filters = Object.values(UI.searchFilters);
|
||||||
|
$('#search').value.split(' ').forEach(part => {
|
||||||
|
const filter = filters.find(entry => entry.query === part);
|
||||||
|
if (filter) {
|
||||||
|
const button = filterLabels.filter(btn => btn.id === filter.id);
|
||||||
|
if (button.length) {
|
||||||
|
button[0].checked = true;
|
||||||
|
button[0].parentElement.classList.add('checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
createStyleTargetsElement: ({entry, style}) => {
|
createStyleTargetsElement: ({entry, style}) => {
|
||||||
const parts = UI._parts;
|
const parts = UI._parts;
|
||||||
|
@ -226,6 +249,48 @@ const UI = {
|
||||||
entry.classList.toggle('global', !numTargets);
|
entry.classList.toggle('global', !numTargets);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// This order matters
|
||||||
|
searchFilters: {
|
||||||
|
enabled: {
|
||||||
|
id: 'manage.onlyEnabled',
|
||||||
|
query: 'is:enabled',
|
||||||
|
invert: 'disabled'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
id: 'manage.onlyEnabled.invert',
|
||||||
|
query: 'is:disabled',
|
||||||
|
invert: 'enabled'
|
||||||
|
},
|
||||||
|
usercss: {
|
||||||
|
id: 'manage.onlyUsercss',
|
||||||
|
query: 'is:usercss',
|
||||||
|
invert: 'original'
|
||||||
|
},
|
||||||
|
original: {
|
||||||
|
id: 'manage.onlyUsercss.invert',
|
||||||
|
query: 'is:nonusercss',
|
||||||
|
invert: 'usercss'
|
||||||
|
},
|
||||||
|
local: {
|
||||||
|
id: 'manage.onlyLocal',
|
||||||
|
query: 'is:local',
|
||||||
|
invert: 'external'
|
||||||
|
},
|
||||||
|
external: {
|
||||||
|
id: 'manage.onlyLocal.invert',
|
||||||
|
query: 'is:external',
|
||||||
|
invert: 'local'
|
||||||
|
},
|
||||||
|
// only checkbox; all others are radio buttons
|
||||||
|
updatable: {
|
||||||
|
id: 'only-updates',
|
||||||
|
query: '', // 'has:updates',
|
||||||
|
},
|
||||||
|
reset: {
|
||||||
|
id: 'reset-filters',
|
||||||
|
query: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getFaviconImgSrc: (container = installed) => {
|
getFaviconImgSrc: (container = installed) => {
|
||||||
if (!UI.favicons) return;
|
if (!UI.favicons) return;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
--favicon-size: 16px;
|
--favicon-size: 16px;
|
||||||
--narrow-column: 60px;
|
--narrow-column: 60px;
|
||||||
--header-height: 40px;
|
--header-height: 40px;
|
||||||
--toolbar-height: 60px;
|
--toolbar-height: 40px;
|
||||||
--entry-height: 30px;
|
--entry-height: 30px;
|
||||||
--onoffswitch-width: 60px;
|
--onoffswitch-width: 60px;
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
--header-icon-hover-color: #2afefe;
|
--header-icon-hover-color: #2afefe;
|
||||||
|
|
||||||
--tools-bg-color: #ccc;
|
--tools-bg-color: #ccc;
|
||||||
|
--tools-bg-hover: #eee;
|
||||||
|
|
||||||
--entry-header-bg-color: #ddd;
|
--entry-header-bg-color: #ddd;
|
||||||
--entry-header-text-color: #111;
|
--entry-header-text-color: #111;
|
||||||
|
@ -71,13 +72,17 @@ a:hover {
|
||||||
color: var(--entry-text-hover);
|
color: var(--entry-text-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body a[disabled],
|
||||||
|
body button[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.invisible {
|
.invisible {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
cursor: pointer;
|
|
||||||
width: var(--entry-icon-size);
|
width: var(--entry-icon-size);
|
||||||
height: var(--entry-icon-size);
|
height: var(--entry-icon-size);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
@ -85,6 +90,10 @@ a:hover {
|
||||||
fill: var(--entry-icon-color);
|
fill: var(--entry-icon-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.svg-icon:not(.no-pointer) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
#main-header .svg-icon {
|
#main-header .svg-icon {
|
||||||
width: var(--header-icon-size);
|
width: var(--header-icon-size);
|
||||||
height: var(--header-icon-size);
|
height: var(--header-icon-size);
|
||||||
|
@ -122,6 +131,7 @@ a:hover {
|
||||||
|
|
||||||
#bulk-actions {
|
#bulk-actions {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bulk-info > span,
|
#bulk-info > span,
|
||||||
|
@ -147,9 +157,9 @@ a:hover {
|
||||||
100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); }
|
100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-header a:hover .svg-icon,
|
.entry-header a:hover .svg-icon:not(.no-pointer),
|
||||||
.entry a:hover .svg-icon,
|
.entry a:hover .svg-icon:not(.no-pointer),
|
||||||
.svg-icon:hover {
|
.svg-icon:not(.no-pointer):hover {
|
||||||
fill: var(--entry-icon-hover-color);
|
fill: var(--entry-icon-hover-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,14 +350,6 @@ body.all-styles-hidden-by-filters #installed:after {
|
||||||
content: '▾';
|
content: '▾';
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-filter span:before {
|
|
||||||
content: '►';
|
|
||||||
color: var(--entry-icon-color);
|
|
||||||
position: relative;
|
|
||||||
left: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-filter:hover span:before,
|
|
||||||
.header-filter:hover .svg-icon,
|
.header-filter:hover .svg-icon,
|
||||||
.header-filter.active svg {
|
.header-filter.active svg {
|
||||||
transition: all .5s;
|
transition: all .5s;
|
||||||
|
@ -355,11 +357,6 @@ body.all-styles-hidden-by-filters #installed:after {
|
||||||
fill: var(--entry-text-hover);
|
fill: var(--entry-text-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-filter.active span:before {
|
|
||||||
content: '▲';
|
|
||||||
color: var(--entry-text-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.targets {
|
.targets {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
@ -473,7 +470,8 @@ a svg, .svg-icon.sort {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checkbox */
|
/* Checkbox */
|
||||||
.checkmate input:checked + svg.checkbox .filled-circle {
|
.checkmate input:checked + svg.checkbox .filled-circle,
|
||||||
|
svg.checkbox-enabled .filled-circle {
|
||||||
fill: var(--checkbox-bg-color);
|
fill: var(--checkbox-bg-color);
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +484,8 @@ a svg, .svg-icon.sort {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkmate input:checked + svg.checkbox .checkmark {
|
.checkmate input:checked + svg.checkbox .checkmark,
|
||||||
|
svg.checkbox-enabled .checkmark {
|
||||||
fill: var(--checkbox-icon-color);
|
fill: var(--checkbox-icon-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,6 +692,9 @@ a svg, .svg-icon.sort {
|
||||||
height: var(--toolbar-height);
|
height: var(--toolbar-height);
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tools-wrapper:not(.hidden) + #installed {
|
#tools-wrapper:not(.hidden) + #installed {
|
||||||
|
@ -702,20 +704,85 @@ a svg, .svg-icon.sort {
|
||||||
top: calc(var(--header-height) + var(--toolbar-height));
|
top: calc(var(--header-height) + var(--toolbar-height));
|
||||||
}
|
}
|
||||||
|
|
||||||
#tools-wrapper .select-resizer {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.manage-row {
|
.manage-row {
|
||||||
padding: 2px 18px;
|
padding: 2px 18px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: flex-end;
|
||||||
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#filters-wrapper,
|
#filters-wrapper,
|
||||||
#bulk-filter-count {
|
#bulk-filter-count {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filters-wrapper input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filters-wrapper svg {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-row label,
|
||||||
|
.manage-row button,
|
||||||
|
.manage-row select {
|
||||||
|
min-width: 2em;
|
||||||
|
height: 24px;
|
||||||
|
max-height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 0 6px;
|
||||||
|
margin: 0 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filters-wrapper label:not(.checked):hover {
|
||||||
|
background-color: var(--tools-bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-row select {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-filter .svg-icon,
|
||||||
|
.search-filter span {
|
||||||
|
pointer-events: none;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group label:first-child {
|
||||||
|
margin-right: 0;
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group label:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-row button,
|
||||||
|
.search-filter {
|
||||||
|
background: #e0e1e2;
|
||||||
|
border: 1px #9e9e9e solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-filter.checked,
|
||||||
|
.search-filter.checked:hover {
|
||||||
|
background-color: var(--label-usercss-bg-color);
|
||||||
|
color: #fff;
|
||||||
|
fill: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-wrapper {
|
#search-wrapper {
|
||||||
|
@ -723,7 +790,8 @@ a svg, .svg-icon.sort {
|
||||||
}
|
}
|
||||||
|
|
||||||
#search {
|
#search {
|
||||||
width: calc(100% - var(--entry-icon-size) * 1.4);
|
width: 100%;
|
||||||
|
height: 2.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-help {
|
#search-help {
|
||||||
|
@ -751,7 +819,7 @@ a svg, .svg-icon.sort {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active #filters-stats,
|
#filters-stats,
|
||||||
#bulk-filter-count:not(:empty) {
|
#bulk-filter-count:not(:empty) {
|
||||||
background-color: var(--checked-count-bg-color);
|
background-color: var(--checked-count-bg-color);
|
||||||
border-color: var(--checked-count-bg-color);
|
border-color: var(--checked-count-bg-color);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global messageBox UI filtersSelector filterAndAppend
|
/* global messageBox UI handleEvent filtersSelector filterAndAppend
|
||||||
sorter $ $$ $create API onDOMready scrollElementIntoView t chromeLocal */
|
sorter $ $$ $create API onDOMready scrollElementIntoView t chromeLocal */
|
||||||
/* exported handleUpdateInstalled */
|
/* exported handleUpdateInstalled resetUpdates */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let updateTimer;
|
let updateTimer;
|
||||||
|
@ -27,6 +27,15 @@ function applyUpdateAll() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetUpdates() {
|
||||||
|
$('#check-all-updates-force').classList.add('hidden');
|
||||||
|
$('#apply-all-updates').classList.add('hidden');
|
||||||
|
$('#update-history').classList.add('hidden');
|
||||||
|
const checkbox = $('#only-updates');
|
||||||
|
checkbox.checked = false;
|
||||||
|
checkbox.parentElement.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function checkUpdateBulk() {
|
function checkUpdateBulk() {
|
||||||
clearTimeout(updateTimer);
|
clearTimeout(updateTimer);
|
||||||
|
@ -120,6 +129,7 @@ function checkUpdate(entry, {single} = {}) {
|
||||||
function reportUpdateState({updated, style, error, STATES}) {
|
function reportUpdateState({updated, style, error, STATES}) {
|
||||||
const isCheckAll = document.body.classList.contains('update-in-progress');
|
const isCheckAll = document.body.classList.contains('update-in-progress');
|
||||||
const entry = $(UI.ENTRY_ID_PREFIX + style.id);
|
const entry = $(UI.ENTRY_ID_PREFIX + style.id);
|
||||||
|
if (!entry) return;
|
||||||
const newClasses = new Map([
|
const newClasses = new Map([
|
||||||
/*
|
/*
|
||||||
When a style is updated/installed, handleUpdateInstalled() clears "updatable"
|
When a style is updated/installed, handleUpdateInstalled() clears "updatable"
|
||||||
|
@ -138,7 +148,10 @@ function reportUpdateState({updated, style, error, STATES}) {
|
||||||
if (updated) {
|
if (updated) {
|
||||||
newClasses.set('can-update', true);
|
newClasses.set('can-update', true);
|
||||||
entry.updatedCode = style;
|
entry.updatedCode = style;
|
||||||
$('#only-updates').classList.remove('hidden');
|
const onlyUpdates = $('#only-updates');
|
||||||
|
onlyUpdates.parentElement.classList.remove('hidden');
|
||||||
|
onlyUpdates.checked = true;
|
||||||
|
onlyUpdates.change();
|
||||||
} else if (!entry.classList.contains('can-update')) {
|
} else if (!entry.classList.contains('can-update')) {
|
||||||
const same = (
|
const same = (
|
||||||
error === STATES.SAME_MD5 ||
|
error === STATES.SAME_MD5 ||
|
||||||
|
@ -202,16 +215,15 @@ function reportUpdateState({updated, style, error, STATES}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function renderUpdatesOnlyFilter({show, check} = {}) {
|
function renderUpdatesOnlyFilter({show, check} = {}) {
|
||||||
const numUpdatable = $$('.can-update').length;
|
const numUpdatable = $$('.can-update').length;
|
||||||
const mightUpdate = numUpdatable > 0 || $('.update-problem');
|
const mightUpdate = numUpdatable > 0 || $('.update-problem');
|
||||||
const checkbox = $('#only-updates input');
|
const checkbox = $('#only-updates');
|
||||||
show = show !== undefined ? show : mightUpdate;
|
show = show !== undefined ? show : mightUpdate;
|
||||||
check = check !== undefined ? show && check : checkbox.checked && mightUpdate;
|
check = check !== undefined ? show && check : checkbox.checked && mightUpdate;
|
||||||
|
|
||||||
$('#only-updates').classList.toggle('hidden', !show);
|
checkbox.checked = check;
|
||||||
checkbox.checked = check && show;
|
checkbox.parentElement.classList.toggle('hidden', !show);
|
||||||
checkbox.dispatchEvent(new Event('change'));
|
checkbox.dispatchEvent(new Event('change'));
|
||||||
|
|
||||||
const btnApply = $('#apply-all-updates');
|
const btnApply = $('#apply-all-updates');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user