├── .gitignore ├── PRIVACY.md ├── README.md ├── background.js ├── browser-polyfill.js ├── content └── content.js ├── devtools ├── devtools.js └── index.html ├── docs ├── css │ └── main.css └── index.html ├── images ├── icon-white@128.png ├── icon-white@16.png ├── icon-white@48.png ├── icon-white@64.png ├── icon.svg ├── icon@128.png ├── icon@16.png ├── icon@48.png ├── icon@64.png └── reload.svg ├── manifest.json └── panel ├── css ├── highlight-github-gist.css └── main.css ├── index.html └── js ├── highlight.pack.js └── panel.js /.gitignore: -------------------------------------------------------------------------------- 1 | icons.sketch 2 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Feature Queries Manager does not collect or store any information about you. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | @ sign 2 | 3 | # Feature Queries Manager 4 | 5 | Manage and toggle CSS on a page behind a @supports Feature Query 6 | 7 | ## How does it work? 8 | 9 | It works by **negating** the feature query condition to give you the opposite result. For example, it will turn the following feature query condition... 10 | 11 | ```css 12 | @supports (display: flex) { /* styles here */ } 13 | ``` 14 | ... Into the following... 15 | 16 | ```css 17 | @supports not((display: flex)) { /* styles here */ } 18 | ``` 19 | 20 | ## How to use 21 | 22 | **1. Install the Feature Queries Manager** 23 | 24 | - Google Chrome Logo [Download on Google Chrome](https://chrome.google.com/webstore/detail/fbhgnconlfgmienbmpbeeenffagggonp/) 25 | - [Firefox Logo [Download on Firefox](https://addons.mozilla.org/en-US/firefox/addon/feature-queries-manager/) 26 | 27 | (Other browsers TBA) 28 | 29 | **2. Open DevTools and see a new panel labelled "FQM"** 30 | 31 | ![Screenshot of FQM](https://user-images.githubusercontent.com/8677283/39296534-12a99c72-4939-11e8-8416-0ef066a59eb4.png) 32 | 33 | This page will display all the feature queries on the page (on the left) and any styles within those Feature Queries (on the right). 34 | 35 | **3. Toggle Feature Queries** 36 | 37 | On the left panel, you will see the list of feature query conditions on the page, and a checkbox beside each condition. 38 | 39 | - **Uncheck** the checkbox to negate the feature query condition 40 | - **Check** the checkbox to re-instate the original feature query condition 41 | 42 | ![Example of FQM toggle on and off](https://user-images.githubusercontent.com/8677283/39296696-81c1141e-4939-11e8-9c0a-ef92783c57ae.gif) 43 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | let portToPanelScript = null; 2 | 3 | browser.runtime.onConnect.addListener((port) => { 4 | portToPanelScript = port; 5 | portToPanelScript.onMessage.addListener((request) => { 6 | 7 | if (!request.tabId) return; 8 | 9 | // Send message from panel.js -> content.js 10 | // and return response from content.js -> panel.js 11 | browser.tabs.sendMessage(request.tabId, request) 12 | .then((res) => portToPanelScript.postMessage(res)); 13 | }); 14 | }); 15 | 16 | browser.tabs.onUpdated.addListener((tabId, changeInfo, tabInfo) => { 17 | if (portToPanelScript && changeInfo.status === 'complete') { 18 | portToPanelScript.postMessage({ action: 'restart' }); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /browser-polyfill.js: -------------------------------------------------------------------------------- 1 | (function(a,b){if("function"==typeof define&&define.amd)define("webextension-polyfill",["module"],b);else if("undefined"!=typeof exports)b(module);else{var c={exports:{}};b(c),a.browser=c.exports}})(this,function(a){"use strict";if("undefined"==typeof browser){a.exports=(()=>{const c={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},export:{minArgs:0,maxArgs:0},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},getSubTree:{minArgs:1,maxArgs:1},import:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},setIcon:{minArgs:1,maxArgs:1}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{update:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0}}},downloads:{download:{minArgs:1,maxArgs:1},cancel:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},getTitle:{minArgs:1,maxArgs:1},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},getIcon:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getBrowserInfo:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{create:{minArgs:1,maxArgs:1},captureVisibleTab:{minArgs:0,maxArgs:2},detectLanguage:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},query:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(0===Object.keys(c).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class d extends WeakMap{constructor(n,o=void 0){super(o),this.createItem=n}get(n){return this.has(n)||this.set(n,this.createItem(n)),super.get(n)}}const e=n=>{return n&&"object"==typeof n&&"function"==typeof n.then},f=(n,o)=>{return(...p)=>{chrome.runtime.lastError?n.reject(chrome.runtime.lastError):o.singleCallbackArg||1===p.length?n.resolve(p[0]):n.resolve(p)}},g=(n,o)=>{const p=q=>1==q?"argument":"arguments";return function(r,...s){if(s.lengtho.maxArgs)throw new Error(`Expected at most ${o.maxArgs} ${p(o.maxArgs)} for ${n}(), got ${s.length}`);return new Promise((t,u)=>{if(o.fallbackToNoCallback)try{r[n](...s,f({resolve:t,reject:u},o))}catch(v){console.warn(`${n} API method doesn't seem to support the callback parameter, `+"falling back to call it without a callback: ",v),r[n](...s),o.fallbackToNoCallback=!1,o.noCallback=!0,t()}else o.noCallback?(r[n](...s),t()):r[n](...s,f({resolve:t,reject:u},o))})}},h=(n,o,p)=>{return new Proxy(o,{apply(q,r,s){return p.call(r,n,...s)}})};let i=Function.call.bind(Object.prototype.hasOwnProperty);const j=(n,o={},p={})=>{let q=Object.create(null),r={has(t,u){return u in n||u in q},get(t,u){if(u in q)return q[u];if(u in n){let w=n[u];if("function"==typeof w){if("function"==typeof o[u])w=h(n,n[u],o[u]);else if(i(p,u)){let x=g(u,p[u]);w=h(n,n[u],x)}else w=w.bind(n);}else if("object"==typeof w&&null!==w&&(i(o,u)||i(p,u)))w=j(w,o[u],p[u]);else return Object.defineProperty(q,u,{configurable:!0,enumerable:!0,get(){return n[u]},set(x){n[u]=x}}),w;return q[u]=w,w}},set(t,u,v){return u in q?q[u]=v:n[u]=v,!0},defineProperty(t,u,v){return Reflect.defineProperty(q,u,v)},deleteProperty(t,u){return Reflect.deleteProperty(q,u)}},s=Object.create(n);return new Proxy(s,r)},l=new d(n=>{return"function"==typeof n?function(p,q,r){let s=n(p,q);return e(s)?(s.then(r,t=>{console.error(t),r(t)}),!0):void(void 0!==s&&r(s))}:n}),m={runtime:{onMessage:(n=>({addListener(o,p,...q){o.addListener(n.get(p),...q)},hasListener(o,p){return o.hasListener(n.get(p))},removeListener(o,p){o.removeListener(n.get(p))}}))(l)}};return j(chrome,m,c)})()}else a.exports=browser}); 2 | //# sourceMappingURL=browser-polyfill.min.js.map 3 | 4 | 5 | // webextension-polyfill v.0.2.1 (https://github.com/mozilla/webextension-polyfill) 6 | 7 | /* This Source Code Form is subject to the terms of the Mozilla Public 8 | * License, v. 2.0. If a copy of the MPL was not distributed with this 9 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 10 | -------------------------------------------------------------------------------- /content/content.js: -------------------------------------------------------------------------------- 1 | 2 | let FEATURE_QUERY_DECLARATIONS = []; // [{ index: Number, stylesheet: Object, rule: Object, invertedCSSText: String }] 3 | let FEATURE_QUERY_CONDITIONS = []; // ["(display: flex)"] 4 | 5 | /* ************************************************************************ 6 | start 7 | ************************************************************************ */ 8 | 9 | function readStylesheets() { 10 | Array.from(document.styleSheets).forEach((stylesheet) => { 11 | 12 | let cssRules; 13 | 14 | try { 15 | cssRules = Array.from(stylesheet.cssRules); 16 | } catch(err) { 17 | return console.warn(`[FQM] Can't read cssRules from stylesheet: ${ stylesheet.href }`); 18 | } 19 | 20 | cssRules.forEach((rule, i) => { 21 | if (rule instanceof CSSSupportsRule) { 22 | const cssRule = rule.cssText.substring(rule.cssText.indexOf("{") + 1); 23 | const invertedCSSText = `@supports not ( ${ rule.conditionText } ) { ${ cssRule }`; 24 | FEATURE_QUERY_DECLARATIONS.push({ 25 | index: i, 26 | stylesheet: stylesheet, 27 | rule: rule, 28 | invertedCSSText: invertedCSSText 29 | }); 30 | } 31 | }); 32 | 33 | }); 34 | } 35 | 36 | function getConditionsFromStylesheets() { 37 | if (FEATURE_QUERY_DECLARATIONS.length === 0) return; 38 | 39 | FEATURE_QUERY_DECLARATIONS.forEach((declaration) => { 40 | if (!FEATURE_QUERY_CONDITIONS.includes(declaration.rule.conditionText)) { 41 | FEATURE_QUERY_CONDITIONS.push(declaration.rule.conditionText); 42 | } 43 | }); 44 | } 45 | 46 | /* ************************************************************************ 47 | toggleCondition 48 | ************************************************************************ */ 49 | 50 | function toggleCondition(condition, toggleOn) { 51 | FEATURE_QUERY_DECLARATIONS.forEach((declaration) => { 52 | if (declaration.rule.conditionText === condition) { 53 | declaration.stylesheet.deleteRule(declaration.index); 54 | const rule = toggleOn ? declaration.rule.cssText : declaration.invertedCSSText; 55 | declaration.stylesheet.insertRule(rule, declaration.index); 56 | } 57 | }); 58 | } 59 | 60 | /* ************************************************************************ 61 | getConditionRules 62 | ************************************************************************ */ 63 | 64 | function getConditionRules(condition) { 65 | const conditionRules = []; 66 | 67 | FEATURE_QUERY_DECLARATIONS.forEach((declaration) => { 68 | if (declaration.rule.conditionText === condition) { 69 | conditionRules.push({ 70 | cssText: declaration.rule.cssText, 71 | index: declaration.index, 72 | stylesheet: declaration.stylesheet.href || '<style>' 73 | }); 74 | } 75 | }); 76 | 77 | return conditionRules; 78 | } 79 | 80 | /* ************************************************************************ 81 | onMessage 82 | ************************************************************************ */ 83 | 84 | browser.runtime.onMessage.addListener((msg) => { 85 | switch(msg.action) { 86 | case 'start': 87 | FEATURE_QUERY_DECLARATIONS = []; 88 | FEATURE_QUERY_CONDITIONS = []; 89 | readStylesheets(); 90 | getConditionsFromStylesheets(); 91 | return Promise.resolve({ 92 | action: msg.action, 93 | FEATURE_QUERY_CONDITIONS: FEATURE_QUERY_CONDITIONS, 94 | FEATURE_QUERY_DECLARATIONS: FEATURE_QUERY_DECLARATIONS 95 | }); 96 | break; 97 | case 'toggleCondition': 98 | toggleCondition(msg.condition, msg.toggleOn); 99 | return Promise.resolve({ 100 | action: msg.action 101 | }); 102 | break; 103 | case 'getConditionRules': 104 | const conditionRules = getConditionRules(msg.condition); 105 | return Promise.resolve({ 106 | action: msg.action, 107 | conditionRules: conditionRules 108 | }); 109 | break; 110 | default: 111 | break; 112 | } 113 | }); 114 | -------------------------------------------------------------------------------- /devtools/devtools.js: -------------------------------------------------------------------------------- 1 | browser.devtools.panels.create("FQM", "../images/icon@64.png", "../panel/index.html"); 2 | -------------------------------------------------------------------------------- /devtools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/css/main.css: -------------------------------------------------------------------------------- 1 | /* Reset ****************************** */ 2 | 3 | html, body, div, span, applet, object, iframe, 4 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 5 | a, abbr, acronym, address, big, cite, code, 6 | del, dfn, em, img, ins, kbd, q, s, samp, 7 | small, strike, strong, sub, sup, tt, var, 8 | b, u, i, center, 9 | dl, dt, dd, ol, ul, li, 10 | fieldset, form, label, legend, 11 | table, caption, tbody, tfoot, thead, tr, th, td, 12 | article, aside, canvas, details, embed, 13 | figure, figcaption, footer, header, hgroup, 14 | menu, nav, output, ruby, section, summary, 15 | time, mark, audio, video { 16 | margin: 0; 17 | padding: 0; 18 | border: 0; 19 | font: inherit; 20 | font-size: 100%; 21 | vertical-align: baseline; 22 | } 23 | 24 | article, aside, details, figcaption, figure, 25 | footer, header, hgroup, menu, nav, section { 26 | display: block; 27 | } 28 | 29 | ul { 30 | list-style: none; 31 | } 32 | 33 | html { 34 | box-sizing: border-box; 35 | } 36 | 37 | *, *:before, *:after { 38 | box-sizing: inherit; 39 | } 40 | 41 | .sr-only { 42 | position: absolute; 43 | clip: rect(1px,1px,1px,1px); 44 | } 45 | 46 | /* Typography ****************************** */ 47 | 48 | html { 49 | font-size: 62.5%; 50 | } 51 | 52 | body { 53 | font-size: 1.5rem; 54 | line-height: 1.5; 55 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 56 | font-weight: 300; 57 | text-align: center; 58 | background-color: rgb(245, 245, 245); 59 | } 60 | 61 | h1, 62 | h2, 63 | h3 { 64 | font-weight: 700; 65 | text-transform: lowercase; 66 | } 67 | 68 | h1 { 69 | font-size: 3rem; 70 | } 71 | 72 | h2 { 73 | font-size: 2.4rem; 74 | } 75 | 76 | h3 { 77 | font-size: 1.5rem; 78 | margin-bottom: 10px; 79 | } 80 | 81 | p { 82 | display: block; 83 | margin-bottom: 10px; 84 | padding: 0 20px; 85 | } 86 | 87 | /* Layout ****************************** */ 88 | 89 | .wrapper { 90 | width: 95%; 91 | max-width: 600px; 92 | margin: 20px auto; 93 | } 94 | 95 | header { 96 | margin-bottom: 50px; 97 | text-align: center; 98 | } 99 | 100 | section { 101 | margin-bottom: 60px; 102 | } 103 | 104 | section section { 105 | margin-bottom: 40px; 106 | } 107 | 108 | /* Examples ****************************** */ 109 | 110 | .inline-style, 111 | .example { 112 | border-radius: 3px; 113 | } 114 | 115 | .inline-style { 116 | display: block; 117 | white-space: pre; 118 | background-color: #fff; 119 | text-align: left; 120 | padding: 10px; 121 | margin-bottom: 10px; 122 | } 123 | 124 | .example { 125 | padding: 5px; 126 | } 127 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FQM Demo 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | @ sign 15 |

Feature Queries Manager

16 |

An extension to DevTools to turn off/on the CSS within @supports queries.

17 |
18 | 19 |
20 |

How does it work?

21 |

It works by negating the feature query condition to give you the oppposite result. For example, it will turn the following feature query condition...

22 |
@supports (display: flex) { /* styles here */ }
23 |

Into the following...

24 |
@supports not ((display: flex)) { /* styles here */ }
25 |
26 | 27 |
28 |

Demo

29 |

Note: You need to install the Feature Queries Manager in your browser for this to work. Once installed, open up the "FQM" panel in devtools and toggle on/off the following styles:

30 |
31 | 32 |
33 |

1. Positive Condition

34 | 35 | 40 |
I'm #example1
41 |
42 | 43 |
44 |

2. Negative Condition

45 | 46 | 51 |
I'm #example2
52 |
53 | 54 |
55 |

3. Conjunction (and)

56 | 57 | 62 |
I'm #example3
63 |
64 | 65 |
66 |

4. Disjunction (or)

67 | 68 | 73 |
I'm #example4
74 |
75 |
76 | 77 |

More test examples....

78 |

79 | 80 |
81 |

5. Positive Condition with failure

82 | 83 | 88 |
I'm #example5
89 |
90 | 91 |
92 | 93 | -------------------------------------------------------------------------------- /images/icon-white@128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon-white@128.png -------------------------------------------------------------------------------- /images/icon-white@16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon-white@16.png -------------------------------------------------------------------------------- /images/icon-white@48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon-white@48.png -------------------------------------------------------------------------------- /images/icon-white@64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon-white@64.png -------------------------------------------------------------------------------- /images/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon@128 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /images/icon@128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon@128.png -------------------------------------------------------------------------------- /images/icon@16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon@16.png -------------------------------------------------------------------------------- /images/icon@48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon@48.png -------------------------------------------------------------------------------- /images/icon@64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ireade/feature-queries-manager/1ea4595174ce3f6b892a85843ac73b241ea83939/images/icon@64.png -------------------------------------------------------------------------------- /images/reload.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Reload Icon 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | 4 | "name": "Feature Queries Manager", 5 | "short_name": "FQM", 6 | "description": "Manage and toggle CSS on a page behind a @supports Feature Query.", 7 | "version": "0.3", 8 | 9 | "permissions": [ 10 | "tabs", 11 | "activeTab", 12 | "" 13 | ], 14 | 15 | "background": { 16 | "scripts": ["browser-polyfill.js", "background.js"] 17 | }, 18 | 19 | "devtools_page": "devtools/index.html", 20 | 21 | "content_scripts": [{ 22 | "matches": [""], 23 | "js": ["browser-polyfill.js", "content/content.js"] 24 | }], 25 | 26 | "icons": { 27 | "128": "images/icon@128.png", 28 | "64": "images/icon@64.png", 29 | "16": "images/icon@16.png", 30 | "48": "images/icon@48.png" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /panel/css/highlight-github-gist.css: -------------------------------------------------------------------------------- 1 | /** 2 | * GitHub Gist Theme 3 | * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro 4 | */ 5 | 6 | .hljs { 7 | display: block; 8 | background: white; 9 | padding: 0.5em; 10 | color: #333333; 11 | overflow-x: auto; 12 | } 13 | 14 | .hljs-comment, 15 | .hljs-meta { 16 | color: #969896; 17 | } 18 | 19 | .hljs-string, 20 | .hljs-variable, 21 | .hljs-template-variable, 22 | .hljs-strong, 23 | .hljs-emphasis, 24 | .hljs-quote { 25 | color: #df5000; 26 | } 27 | 28 | .hljs-keyword, 29 | .hljs-selector-tag, 30 | .hljs-type { 31 | color: #a71d5d; 32 | } 33 | 34 | .hljs-literal, 35 | .hljs-symbol, 36 | .hljs-bullet, 37 | .hljs-attribute { 38 | color: #0086b3; 39 | } 40 | 41 | .hljs-section, 42 | .hljs-name { 43 | color: #63a35c; 44 | } 45 | 46 | .hljs-tag { 47 | color: #333333; 48 | } 49 | 50 | .hljs-title, 51 | .hljs-attr, 52 | .hljs-selector-id, 53 | .hljs-selector-class, 54 | .hljs-selector-attr, 55 | .hljs-selector-pseudo { 56 | color: #795da3; 57 | } 58 | 59 | .hljs-addition { 60 | color: #55a532; 61 | background-color: #eaffea; 62 | } 63 | 64 | .hljs-deletion { 65 | color: #bd2c00; 66 | background-color: #ffecec; 67 | } 68 | 69 | .hljs-link { 70 | text-decoration: underline; 71 | } 72 | -------------------------------------------------------------------------------- /panel/css/main.css: -------------------------------------------------------------------------------- 1 | /* ********************************** 2 | * 3 | * Variables 4 | * 5 | * ********************************** */ 6 | 7 | :root { 8 | --colour-sidebar: #F3F3F3; 9 | --colour-border: #CCC; 10 | } 11 | 12 | /* ********************************** 13 | * 14 | * Reset 15 | * 16 | * ********************************** */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | h1, 23 | h2, 24 | h3, 25 | pre, 26 | section { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | 31 | /* ********************************** 32 | * 33 | * Typography 34 | * 35 | * ********************************** */ 36 | 37 | html { 38 | font-size: 62.5%; 39 | } 40 | 41 | body { 42 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 43 | font-size: 1.4rem; 44 | } 45 | 46 | h1, 47 | h3 { 48 | font-size: 1.4rem; 49 | } 50 | 51 | button { 52 | font: inherit; 53 | } 54 | 55 | /* ********************************** 56 | * 57 | * Grid 58 | * 59 | * ********************************** */ 60 | 61 | header { grid-area: header; } 62 | aside { grid-area: aside; } 63 | main { grid-area: main; } 64 | 65 | body { 66 | display: grid; 67 | grid-template-areas: "header main" "aside main"; 68 | grid-template-columns: 300px 1fr; 69 | grid-template-rows: auto 1fr; 70 | margin: 0; 71 | height: 100vh; 72 | } 73 | 74 | /* ********************************** 75 | * 76 | * Header 77 | * 78 | * ********************************** */ 79 | 80 | header, 81 | aside { 82 | background-color: var(--colour-sidebar); 83 | border-right: 1px solid var(--colour-border); 84 | } 85 | 86 | header { 87 | padding: 10px 20px; 88 | border-bottom: 1px solid var(--colour-border); 89 | } 90 | 91 | header { 92 | display: flex; 93 | align-items: center; 94 | justify-content: space-between; 95 | } 96 | 97 | header h1 { 98 | display: flex; 99 | align-items: center; 100 | } 101 | 102 | header img { 103 | height: 1.5rem; 104 | } 105 | 106 | header h1 img { 107 | margin-right: 10px; 108 | } 109 | 110 | header button { 111 | background: 0; 112 | border: 0; 113 | margin: 0; 114 | padding: 0; 115 | font: inherit; 116 | line-height: 1; 117 | cursor: pointer; 118 | } 119 | 120 | /* ********************************** 121 | * 122 | * Aside 123 | * 124 | * ********************************** */ 125 | 126 | aside { 127 | height: 100%; 128 | } 129 | 130 | aside ul { 131 | list-style: none; 132 | margin: 0; 133 | padding: 0; 134 | } 135 | 136 | aside li { 137 | border-bottom: 1px solid var(--colour-border); 138 | display: flex; 139 | } 140 | 141 | aside li .toggle, 142 | aside li .details { 143 | padding: 5px 10px; 144 | background: transparent; 145 | } 146 | 147 | aside li .toggle { 148 | width: 50px; 149 | display: flex; 150 | justify-content: center; 151 | align-items: center; 152 | padding-left: 20px; 153 | } 154 | 155 | aside li .details { 156 | width: 100%; 157 | display: flex; 158 | text-align: left; 159 | justify-content: left; 160 | flex-wrap: wrap; 161 | border: none; 162 | outline: none; 163 | padding-right: 20px; 164 | } 165 | 166 | aside li.inverted .details::before, 167 | aside li.inverted .details::after { 168 | color: #c80000; 169 | font-weight: 600; 170 | } 171 | 172 | aside li.inverted .details::before { 173 | content: "not ("; 174 | margin-right: 3px; 175 | } 176 | 177 | aside li.inverted .details::after { 178 | content: ")"; 179 | margin-left: 3px; 180 | } 181 | 182 | aside li.selected, 183 | aside li:hover { 184 | background-color: #5590F7; 185 | } 186 | 187 | aside li.selected button, 188 | aside li:hover button { 189 | color: #FFF; 190 | } 191 | 192 | .notice { 193 | display: inline-block; 194 | padding: 10px 20px; 195 | font-style: italic; 196 | } 197 | 198 | /* ********************************** 199 | * 200 | * Content 201 | * 202 | * ********************************** */ 203 | 204 | main { 205 | height: 100vh; 206 | overflow: scroll; 207 | background-color: #fff; 208 | } 209 | 210 | .group { 211 | display: flex; 212 | flex-wrap: wrap; 213 | border-bottom: 1px solid var(--colour-border); 214 | } 215 | 216 | .group h3 { 217 | background-color: var(--colour-sidebar); 218 | width: 100%; 219 | font-size: 1.2rem; 220 | padding: 2px 3px; 221 | } 222 | 223 | .group pre { 224 | padding: 15px; 225 | width: 100%; 226 | line-height: 1.6; 227 | } 228 | 229 | .group pre code { 230 | font-size: 1rem; 231 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 232 | } 233 | -------------------------------------------------------------------------------- /panel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |

11 | FQM Logo 12 | Feature Queries Manager 13 |

14 | 17 |
18 | 19 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /panel/js/highlight.pack.js: -------------------------------------------------------------------------------- 1 | /*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */ 2 | !function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){s+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"
":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}}); -------------------------------------------------------------------------------- /panel/js/panel.js: -------------------------------------------------------------------------------- 1 | let FEATURE_QUERY_DECLARATIONS = []; 2 | let FEATURE_QUERY_CONDITIONS = []; 3 | const conditionsListEl = document.getElementById('feature-queries'); 4 | const mainEl = document.querySelector('main'); 5 | 6 | const portToBackgroundScript = browser.runtime.connect(); 7 | let thisEvent = null; // see onClickConditionsList() 8 | 9 | /* ************************************************************************ 10 | displayConditionRules 11 | ************************************************************************ */ 12 | 13 | function displayConditionRules(conditionRules, event) { 14 | let content = ''; 15 | 16 | conditionRules.forEach((cr) => { 17 | content += `
18 |

${cr.stylesheet} at index:${cr.index}

19 |
${cr.cssText}
20 |
`; 21 | }); 22 | 23 | mainEl.innerHTML = content; 24 | 25 | // Syntax highlighting 26 | Array.from(document.querySelectorAll('code.css')).forEach((block) => hljs.highlightBlock(block)); 27 | 28 | // Add .selected class to list item in sidebar 29 | const currentlySelected = document.querySelector('.selected'); 30 | if (currentlySelected) currentlySelected.classList.remove('selected'); 31 | event.target.closest('.details').parentElement.classList.add('selected'); 32 | } 33 | 34 | /* ************************************************************************ 35 | events 36 | ************************************************************************ */ 37 | 38 | function onClickConditionsList(event) { 39 | thisEvent = event; 40 | 41 | // If clicked the checkbox 42 | if (event.target.tagName == 'INPUT') { 43 | const index = event.target.parentElement.parentElement.dataset.index; 44 | portToBackgroundScript.postMessage({ 45 | tabId: browser.devtools.inspectedWindow.tabId, 46 | action: 'toggleCondition', 47 | condition: FEATURE_QUERY_CONDITIONS[index], 48 | toggleOn: event.target.checked 49 | }); 50 | document.querySelector(`li[data-index="${ index }"]`).classList.toggle("inverted"); 51 | } 52 | 53 | // If clicked the button 54 | else if (event.target.closest('.details')) { 55 | portToBackgroundScript.postMessage({ 56 | tabId: browser.devtools.inspectedWindow.tabId, 57 | action: 'getConditionRules', 58 | condition: FEATURE_QUERY_CONDITIONS[event.target.closest('.details').parentElement.dataset.index] 59 | }); 60 | } 61 | } 62 | 63 | /* ************************************************************************ 64 | start 65 | ************************************************************************ */ 66 | 67 | function start() { 68 | portToBackgroundScript.postMessage({ 69 | tabId: browser.devtools.inspectedWindow.tabId, 70 | action: 'start' 71 | }); 72 | } 73 | 74 | function displayFeatureQueryConditionsList() { 75 | let content = ''; 76 | 77 | FEATURE_QUERY_CONDITIONS.forEach((condition, i) => { 78 | content += `
  • 79 | 80 | 81 | 82 | 83 |
  • `; 84 | }); 85 | 86 | conditionsListEl.innerHTML = content; 87 | } 88 | 89 | function onReceiveStart(res) { 90 | FEATURE_QUERY_DECLARATIONS = res.FEATURE_QUERY_DECLARATIONS; 91 | FEATURE_QUERY_CONDITIONS = res.FEATURE_QUERY_CONDITIONS; 92 | 93 | if (FEATURE_QUERY_CONDITIONS.length == 0) { 94 | conditionsListEl.innerHTML = 'No Feature Queries found on this page.'; 95 | mainEl.innerHTML = ''; 96 | } else { 97 | displayFeatureQueryConditionsList(); 98 | conditionsListEl.addEventListener('click', onClickConditionsList); 99 | document.querySelector('li[data-index="0"] button').click(); 100 | } 101 | } 102 | 103 | start(); 104 | document.getElementById('reload').addEventListener('click', start); 105 | 106 | /* ************************************************************************ 107 | portToBackgroundScript.onMessage 108 | ************************************************************************ */ 109 | 110 | portToBackgroundScript.onMessage.addListener((msg) => { 111 | switch(msg.action) { 112 | case 'restart': 113 | start(); 114 | break; 115 | case 'start': 116 | onReceiveStart(msg); 117 | break; 118 | case 'toggleCondition': 119 | break; 120 | case 'getConditionRules': 121 | displayConditionRules(msg.conditionRules, thisEvent); 122 | break; 123 | default: 124 | break; 125 | } 126 | }); 127 | --------------------------------------------------------------------------------