diff options
-rw-r--r-- | readme.md | 2 | ||||
-rw-r--r-- | source/background.ts | 4 | ||||
-rw-r--r-- | source/content.ts | 1 | ||||
-rw-r--r-- | source/features/exclude-filter-shortcut.tsx | 169 |
4 files changed, 4 insertions, 172 deletions
@@ -120,7 +120,6 @@ GitHub Enterprise is also supported. More info in the options. - [Quickly visit a repository's default branch and latest version tag.](https://user-images.githubusercontent.com/1402241/38107328-ccb3fb46-33bb-11e8-9654-23a6410943cc.png) - [Open multiple issues at once in your repos.](https://user-images.githubusercontent.com/1402241/38084752-4820b0d8-3378-11e8-868c-a1582b16f915.gif) - [Swap branches in the branch compare view.](https://user-images.githubusercontent.com/857700/42854438-821096f2-8a01-11e8-8752-76f7563b5e18.png) -- [Exclude PR/issue filters from their list](https://user-images.githubusercontent.com/1402241/48470535-493cfb00-e824-11e8-863a-964f52b62553.png) with <kbd>alt/option</kbd>-<kbd>click</kbd>. - [Insert collapsible content when writing comments (via `<summary>`).](https://user-images.githubusercontent.com/1402241/53678019-0c721280-3cf4-11e9-9c24-4d11a697f67c.png) ### More info at a glance @@ -208,6 +207,7 @@ And [many more…](source/content.css) - [Implemented by GitHub](https://user-images.githubusercontent.com/36004334/52573199-ea365480-2e19-11e9-8ebf-3ea6a7a640f8.png): [Access the `Labels` `Milestones` navigation from individual milestone pages.](https://cloud.githubusercontent.com/assets/170270/25217211/37b67aea-25d0-11e7-8482-bead2b04ee74.png) - [Implemented by GitHub](https://github.blog/changelog/2019-02-13-comment-author-label/): [The comments of who opened an issue/PR are marked with `Original Poster` label.](https://cloud.githubusercontent.com/assets/4331946/25075520/d62fbbd0-2316-11e7-921f-ab736dc3522e.png) - [Implemented by GitHub](https://github.blog/changelog/2019-02-14-prompt-to-clean-up-merged-forks): [Quickly delete a forked repo after its pull request has been merged.](https://cloud.githubusercontent.com/assets/170270/13520281/b2c9335c-e211-11e5-9e36-b0f325166356.png) +- [Implemented by GitHub](https://github.blog/changelog/2019-03-05-exclude-labels-from-search/): [Exclude PR/issue filters from their list](https://user-images.githubusercontent.com/1402241/48470535-493cfb00-e824-11e8-863a-964f52b62553.png) with <kbd>alt/option</kbd>-<kbd>click</kbd>. ## Customization diff --git a/source/background.ts b/source/background.ts index 575ad538..2a23ee51 100644 --- a/source/background.ts +++ b/source/background.ts @@ -22,7 +22,9 @@ new OptionsSync().define({ .replace(/^add-/, '') // #1719 .replace('milestone-navigation', '') // #1767 .replace('op-labels', '') // #1776 - .replace('delete-fork-link', ''); // #1791 + .replace('delete-fork-link', '') // #1791 + .replace('exclude-filter-shortcut', '') // #1831 + ; // eslint-disable-line semi-style }, OptionsSync.migrations.removeUnused ] diff --git a/source/content.ts b/source/content.ts index 2cf6bcb0..7e11fea0 100644 --- a/source/content.ts +++ b/source/content.ts @@ -63,7 +63,6 @@ import './features/comments-time-machine-links'; import './features/jump-to-bottom-link'; import './features/filter-comments-by-you'; import './features/hide-issue-list-autocomplete'; -import './features/exclude-filter-shortcut'; import './features/show-recently-pushed-branches-on-more-pages'; import './features/create-release-shortcut'; import './features/patch-diff-links'; diff --git a/source/features/exclude-filter-shortcut.tsx b/source/features/exclude-filter-shortcut.tsx deleted file mode 100644 index b84b8378..00000000 --- a/source/features/exclude-filter-shortcut.tsx +++ /dev/null @@ -1,169 +0,0 @@ -/* -Exclude PR/issue filters from their list with <kbd>alt</kbd> <kbd>click</kbd>. -https://user-images.githubusercontent.com/1402241/48470535-493cfb00-e824-11e8-863a-964f52b62553.png -*/ - -import React from 'dom-chef'; -import select from 'select-dom'; -import delegate from 'delegate'; -import * as icons from '../libs/icons'; -import features from '../libs/features'; - -const getFilterName = item => { - return item - .closest('details') - .querySelector('summary') - .textContent - .trim() - .replace(/s$/, '') // 'Assignees' -> 'Assignee'; 'Milestones -> Milestone' - .toLowerCase(); -}; - -const getItemName = item => { - const itemText = select('.name', item) || select('.select-menu-item-text', item); - const text = itemText.firstChild.textContent.trim(); - return text.includes(' ') ? `"${text}"` : text; -}; - -const getLastQuery = item => { - return new URLSearchParams(item.search) - .get('q') - - // Get the last query - .split(' ') - .pop(); -}; - -const getItemQuery = item => { - const filter = getFilterName(item); - if (filter === 'sort') { - return; - } - - if (filter === 'review') { - // Review filters have the review query set even if they’re selected - return getLastQuery(item); - } - - if (filter === 'project') { - // Project filters don’t have the project query set if they’re selected - // and the query cannot be determined via getFilterName/getItemName - const query = getLastQuery(item); - if (query.startsWith('project:')) { - return query; - } - - return; // Not supported - } - - const name = getItemName(item); - if (name) { - return `${filter}:${name}`; - } - // "No label/milestone/etc" filters won't have a name here and can't be excluded -}; - -const buildSearch = item => { - const itemQuery = getItemQuery(item); - if (!itemQuery) { - return false; - } - - const search = new URLSearchParams(location.search); - const currentQuery = (search.get('q') || '').trim(); - const negatedQuery = `-${itemQuery}`; - if (currentQuery.includes(negatedQuery)) { - // If -label:bug is there, drop it (to match the regular click behavior) - search.set('q', currentQuery.replace(negatedQuery, ' ').replace(/ {2,}/, ' ').trim()); - } else if (currentQuery.includes(itemQuery)) { - // If label:bug is there, replace it with -label:bug - search.set('q', currentQuery.replace(itemQuery, negatedQuery)); - } else { - // If label:bug isn't there, add -label:bug - search.set('q', `${currentQuery} ${negatedQuery}`); - } - - return search; -}; - -const visitNegatedQuery = event => { - if (!event.altKey) { - return; - } - - // Avoid the default (downloading the link) - // even if the link isn't supported - // because we never want to download pages - event.preventDefault(); - const item = event.delegateTarget; - const search = buildSearch(item); - if (search) { - item.search = search; - } - - item.click(); -}; - -const getIcon = isNegated => { - return <span class="select-menu-item-icon">{isNegated ? icons.x() : icons.check()}</span>; -}; - -const updateFilterIcons = () => { - const search = new URLSearchParams(location.search); - const queries = (search.get('q') || '') - .trim() - .match(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g) || []; // Split by query, exclude spaces in quotes https://stackoverflow.com/a/16261693/288906 - - const links = new Map(); - for (const link of select.all('.table-list-filters .select-menu-item:not(.rgh-exclude-filter-icon)')) { - link.classList.add('rgh-exclude-filter-icon'); - - const filter = getItemQuery(link); - if (filter) { - links.set(filter, link); - } - } - - if (links.size === 0) { - return; - } - - for (const query of queries) { - const isNegated = query[0] === '-'; - const plainQuery = query.replace(/^-/, ''); - const link = links.get(plainQuery); - if (!link) { - continue; - } - - const icon = link.querySelector('.octicon-check'); - if (!icon) { - link.prepend(getIcon(isNegated)); - } else if (isNegated) { - icon.replaceWith(getIcon(isNegated)); - } - - link.setAttribute('aria-checked', 'true'); // Necessary for Assignees, but also the correct thing to do - } -}; - -function init() { - delegate('.table-list-filters', 'a.select-menu-item', 'click', visitNegatedQuery, false); - - updateFilterIcons(); - - // Some filters are loaded on demand - const observer = new MutationObserver(updateFilterIcons); - for (const dropdown of select.all('.table-list-filters details-menu')) { - observer.observe(dropdown, {childList: true}); - } -} - -features.add({ - id: 'exclude-filter-shortcut', - include: [ - features.isIssueList - ], - load: features.onAjaxedPages, - init -}); |