diff --git a/content_script.js b/content_script.js new file mode 100644 index 0000000..6483c75 --- /dev/null +++ b/content_script.js @@ -0,0 +1,60 @@ +function matchRule(str, rule) { + return new RegExp(rule.split("*").join(".*")).test(str); +} + +function getColorFromUrl(url) { + var color = null + + console.log(url) + console.log(env) + env.forEach(function(env) { + if (matchRule(url, env.match)) { + color = env.color + } + }) + + return color +} + +function setColorInsideTab(color) { + + if (color == null) + return + + envify_left_div = document.createElement('div') + envify_left_div.classList.add('envify') + envify_left_div.classList.add('left') + + envify_right_div = document.createElement('div') + envify_right_div.classList.add('envify') + envify_right_div.classList.add('right') + + envify_right_div.style.backgroundColor = color + envify_left_div.style.backgroundColor = color + document.body.classList.add('envify') + document.body.appendChild(envify_left_div) + document.body.appendChild(envify_right_div) +} + +url = window.location.href + +chrome.storage.sync.get("environments", function(results){ + console.log(results); + env = [] + let { environments } = results; + + if (environments == undefined) { + return + } + + Object.keys(environments).map(function(value){ + env.push( { match: value, color: environments[value] }); + }); + + env.sort(function(a, b) { + return a.match.length - b.match.length + }) + + setColorInsideTab(getColorFromUrl(url)) +}) + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..949647c --- /dev/null +++ b/manifest.json @@ -0,0 +1,20 @@ +{ + "name": "Envify chrome", + "version": "1.0", + "description": "The same as envify firefox but for chrome", + "manifest_version": 2, + "permissions": [ + "storage" + ], + "options_ui": { + "page": "popup/manage_env.html", + "open_in_tab": true + }, + "content_scripts": [ + { + "matches": [""], + "css": ["style.css"], + "js": ["popup/browser-polyfill.min.js", "content_script.js"] + } + ] +} diff --git a/popup/browser-polyfill.min.js b/popup/browser-polyfill.min.js new file mode 100644 index 0000000..2aadfc4 --- /dev/null +++ b/popup/browser-polyfill.min.js @@ -0,0 +1,14 @@ +(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){const b=` + Returning a Promise is the preferred way to send a reply from an + onMessage/onMessageExternal listener, as the sendResponse will be + removed from the specs (See + https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessage) + `.replace(/\s+/g," ").trim();a.exports=(()=>{const d={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},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{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:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},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:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},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,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{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},setEnabled:{minArgs:2,maxArgs:2},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},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},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}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,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:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{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},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{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}},topSites:{get:{minArgs:0,maxArgs:0}},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(d).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class e extends WeakMap{constructor(s,t=void 0){super(t),this.createItem=s}get(s){return this.has(s)||this.set(s,this.createItem(s)),super.get(s)}}const f=s=>{return s&&"object"==typeof s&&"function"==typeof s.then},g=(s,t)=>{return(...u)=>{chrome.runtime.lastError?s.reject(chrome.runtime.lastError):t.singleCallbackArg||1===u.length?s.resolve(u[0]):s.resolve(u)}},h=s=>1==s?"argument":"arguments",i=(s,t)=>{return function(v,...w){if(w.lengtht.maxArgs)throw new Error(`Expected at most ${t.maxArgs} ${h(t.maxArgs)} for ${s}(), got ${w.length}`);return new Promise((x,y)=>{if(t.fallbackToNoCallback)try{v[s](...w,g({resolve:x,reject:y},t))}catch(z){console.warn(`${s} API method doesn't seem to support the callback parameter, `+"falling back to call it without a callback: ",z),v[s](...w),t.fallbackToNoCallback=!1,t.noCallback=!0,x()}else t.noCallback?(v[s](...w),x()):v[s](...w,g({resolve:x,reject:y},t))})}},j=(s,t,u)=>{return new Proxy(t,{apply(v,w,x){return u.call(w,s,...x)}})};let k=Function.call.bind(Object.prototype.hasOwnProperty);const l=(s,t={},u={})=>{let v=Object.create(null),w={has(y,z){return z in s||z in v},get(y,z){if(z in v)return v[z];if(z in s){let B=s[z];if("function"==typeof B){if("function"==typeof t[z])B=j(s,s[z],t[z]);else if(k(u,z)){let C=i(z,u[z]);B=j(s,s[z],C)}else B=B.bind(s);}else if("object"==typeof B&&null!==B&&(k(t,z)||k(u,z)))B=l(B,t[z],u[z]);else return Object.defineProperty(v,z,{configurable:!0,enumerable:!0,get(){return s[z]},set(C){s[z]=C}}),B;return v[z]=B,B}},set(y,z,A){return z in v?v[z]=A:s[z]=A,!0},defineProperty(y,z,A){return Reflect.defineProperty(v,z,A)},deleteProperty(y,z){return Reflect.deleteProperty(v,z)}},x=Object.create(s);return new Proxy(x,w)},m=s=>({addListener(t,u,...v){t.addListener(s.get(u),...v)},hasListener(t,u){return t.hasListener(s.get(u))},removeListener(t,u){t.removeListener(s.get(u))}});let n=!1;const o=new e(s=>{return"function"==typeof s?function(u,v,w){let y,A,x=!1,z=new Promise(D=>{y=function(E){n||(console.warn(b,new Error().stack),n=!0),x=!0,D(E)}});try{A=s(u,v,y)}catch(D){A=Promise.reject(D)}const B=!0!==A&&f(A);if(!0!==A&&!B&&!x)return!1;const C=D=>{D.then(E=>{w(E)},E=>{let F;F=E&&(E instanceof Error||"string"==typeof E.message)?E.message:"An unexpected error occurred",w({__mozWebExtensionPolyfillReject__:!0,message:F})}).catch(E=>{console.error("Failed to send onMessage rejected reply",E)})};return B?C(A):C(z),!0}:s}),p=({reject:s,resolve:t},u)=>{chrome.runtime.lastError?s(chrome.runtime.lastError):u&&u.__mozWebExtensionPolyfillReject__?s(new Error(u.message)):t(u)},q=(s,t,u,...v)=>{if(v.lengtht.maxArgs)throw new Error(`Expected at most ${t.maxArgs} ${h(t.maxArgs)} for ${s}(), got ${v.length}`);return new Promise((w,x)=>{const y=p.bind(null,{resolve:w,reject:x});v.push(y),u.sendMessage(...v)})},r={runtime:{onMessage:m(o),onMessageExternal:m(o),sendMessage:q.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:q.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}};return l(chrome,r,d)})()}else a.exports=browser}); +//# sourceMappingURL=browser-polyfill.min.js.map + + +// webextension-polyfill v.0.2.1 (https://github.com/mozilla/webextension-polyfill) + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ \ No newline at end of file diff --git a/popup/browser-polyfill.min.js.map b/popup/browser-polyfill.min.js.map new file mode 100644 index 0000000..5745a8e --- /dev/null +++ b/popup/browser-polyfill.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["browser-polyfill.js"],"names":["global","factory","define","amd","exports","module","mod","browser","SEND_RESPONSE_DEPRECATION_WARNING","replace","trim","apiMetadata","keys","length","Error","DefaultWeakMap","WeakMap","constructor","createItem","items","get","key","has","set","isThenable","value","then","makeCallback","promise","metadata","callbackArgs","chrome","runtime","lastError","reject","singleCallbackArg","resolve","pluralizeArguments","numArgs","wrapAsyncFunction","name","target","args","minArgs","maxArgs","Promise","fallbackToNoCallback","cbError","console","warn","noCallback","wrapMethod","method","wrapper","Proxy","apply","targetMethod","thisObj","call","hasOwnProperty","Function","bind","Object","prototype","wrapObject","wrappers","cache","create","handlers","proxyTarget","prop","defineProperty","configurable","enumerable","desc","Reflect","deleteProperty","wrapEvent","wrapperMap","addListener","listener","hasListener","removeListener","loggedSendResponseDeprecationWarning","onMessageWrappers","message","sender","sendResponse","wrappedSendResponse","result","didCallSendResponse","sendResponsePromise","response","stack","err","isResultThenable","sendPromisedResult","msg","error","__mozWebExtensionPolyfillReject__","catch","wrappedSendMessageCallback","reply","wrappedSendMessage","apiNamespaceObj","wrappedCb","push","sendMessage","staticWrappers","onMessage","onMessageExternal","tabs"],"mappings":"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","file":"browser-polyfill.min.js","sourcesContent":["(function (global, factory) {\n if (typeof define === \"function\" && define.amd) {\n define(\"webextension-polyfill\", [\"module\"], factory);\n } else if (typeof exports !== \"undefined\") {\n factory(module);\n } else {\n var mod = {\n exports: {}\n };\n factory(mod);\n global.browser = mod.exports;\n }\n})(this, function (module) {\n /* webextension-polyfill - v0.2.1 - Thu Jun 28 2018 21:16:58 */\n /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */\n /* vim: set sts=2 sw=2 et tw=80: */\n /* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/. */\n \"use strict\";\n\n if (typeof browser === \"undefined\") {\n const SEND_RESPONSE_DEPRECATION_WARNING = `\n Returning a Promise is the preferred way to send a reply from an\n onMessage/onMessageExternal listener, as the sendResponse will be\n removed from the specs (See\n https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessage)\n `.replace(/\\s+/g, \" \").trim();\n\n // Wrapping the bulk of this polyfill in a one-time-use function is a minor\n // optimization for Firefox. Since Spidermonkey does not fully parse the\n // contents of a function until the first time it's called, and since it will\n // never actually need to be called, this allows the polyfill to be included\n // in Firefox nearly for free.\n const wrapAPIs = () => {\n // NOTE: apiMetadata is associated to the content of the api-metadata.json file\n // at build time by replacing the following \"include\" with the content of the\n // JSON file.\n const apiMetadata = {\n \"alarms\": {\n \"clear\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"clearAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"get\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"bookmarks\": {\n \"create\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"get\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getChildren\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getRecent\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getSubTree\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getTree\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"move\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeTree\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"search\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"update\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n }\n },\n \"browserAction\": {\n \"disable\": {\n \"minArgs\": 0,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"enable\": {\n \"minArgs\": 0,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"getBadgeBackgroundColor\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getBadgeText\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getPopup\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getTitle\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"openPopup\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"setBadgeBackgroundColor\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"setBadgeText\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"setIcon\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"setPopup\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"setTitle\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n }\n },\n \"browsingData\": {\n \"remove\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n },\n \"removeCache\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeCookies\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeDownloads\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeFormData\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeHistory\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeLocalStorage\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removePasswords\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removePluginData\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"settings\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"commands\": {\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"contextMenus\": {\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"update\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n }\n },\n \"cookies\": {\n \"get\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getAll\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getAllCookieStores\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"set\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"devtools\": {\n \"inspectedWindow\": {\n \"eval\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n }\n },\n \"panels\": {\n \"create\": {\n \"minArgs\": 3,\n \"maxArgs\": 3,\n \"singleCallbackArg\": true\n }\n }\n },\n \"downloads\": {\n \"cancel\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"download\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"erase\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getFileIcon\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"open\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"pause\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeFile\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"resume\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"search\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"show\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n }\n },\n \"extension\": {\n \"isAllowedFileSchemeAccess\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"isAllowedIncognitoAccess\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"history\": {\n \"addUrl\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"deleteAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"deleteRange\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"deleteUrl\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getVisits\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"search\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"i18n\": {\n \"detectLanguage\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getAcceptLanguages\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"identity\": {\n \"launchWebAuthFlow\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"idle\": {\n \"queryState\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"management\": {\n \"get\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"getSelf\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"setEnabled\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n },\n \"uninstallSelf\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n }\n },\n \"notifications\": {\n \"clear\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"create\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"getPermissionLevel\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"update\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n }\n },\n \"pageAction\": {\n \"getPopup\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getTitle\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"hide\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"setIcon\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"setPopup\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"setTitle\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n },\n \"show\": {\n \"minArgs\": 1,\n \"maxArgs\": 1,\n \"fallbackToNoCallback\": true\n }\n },\n \"permissions\": {\n \"contains\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"request\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"runtime\": {\n \"getBackgroundPage\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"getBrowserInfo\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"getPlatformInfo\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"openOptionsPage\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"requestUpdateCheck\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"sendMessage\": {\n \"minArgs\": 1,\n \"maxArgs\": 3\n },\n \"sendNativeMessage\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n },\n \"setUninstallURL\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"sessions\": {\n \"getDevices\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getRecentlyClosed\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"restore\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n }\n },\n \"storage\": {\n \"local\": {\n \"clear\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"get\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getBytesInUse\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"set\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"managed\": {\n \"get\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getBytesInUse\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n }\n },\n \"sync\": {\n \"clear\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"get\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getBytesInUse\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"set\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n }\n },\n \"tabs\": {\n \"captureVisibleTab\": {\n \"minArgs\": 0,\n \"maxArgs\": 2\n },\n \"create\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"detectLanguage\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"discard\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"duplicate\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"executeScript\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"get\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getCurrent\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n },\n \"getZoom\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getZoomSettings\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"highlight\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"insertCSS\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"move\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n },\n \"query\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"reload\": {\n \"minArgs\": 0,\n \"maxArgs\": 2\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"removeCSS\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"sendMessage\": {\n \"minArgs\": 2,\n \"maxArgs\": 3\n },\n \"setZoom\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"setZoomSettings\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"update\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n }\n },\n \"topSites\": {\n \"get\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"webNavigation\": {\n \"getAllFrames\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"getFrame\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n }\n },\n \"webRequest\": {\n \"handlerBehaviorChanged\": {\n \"minArgs\": 0,\n \"maxArgs\": 0\n }\n },\n \"windows\": {\n \"create\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"get\": {\n \"minArgs\": 1,\n \"maxArgs\": 2\n },\n \"getAll\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getCurrent\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"getLastFocused\": {\n \"minArgs\": 0,\n \"maxArgs\": 1\n },\n \"remove\": {\n \"minArgs\": 1,\n \"maxArgs\": 1\n },\n \"update\": {\n \"minArgs\": 2,\n \"maxArgs\": 2\n }\n }\n };\n\n if (Object.keys(apiMetadata).length === 0) {\n throw new Error(\"api-metadata.json has not been included in browser-polyfill\");\n }\n\n /**\n * A WeakMap subclass which creates and stores a value for any key which does\n * not exist when accessed, but behaves exactly as an ordinary WeakMap\n * otherwise.\n *\n * @param {function} createItem\n * A function which will be called in order to create the value for any\n * key which does not exist, the first time it is accessed. The\n * function receives, as its only argument, the key being created.\n */\n class DefaultWeakMap extends WeakMap {\n constructor(createItem, items = undefined) {\n super(items);\n this.createItem = createItem;\n }\n\n get(key) {\n if (!this.has(key)) {\n this.set(key, this.createItem(key));\n }\n\n return super.get(key);\n }\n }\n\n /**\n * Returns true if the given object is an object with a `then` method, and can\n * therefore be assumed to behave as a Promise.\n *\n * @param {*} value The value to test.\n * @returns {boolean} True if the value is thenable.\n */\n const isThenable = value => {\n return value && typeof value === \"object\" && typeof value.then === \"function\";\n };\n\n /**\n * Creates and returns a function which, when called, will resolve or reject\n * the given promise based on how it is called:\n *\n * - If, when called, `chrome.runtime.lastError` contains a non-null object,\n * the promise is rejected with that value.\n * - If the function is called with exactly one argument, the promise is\n * resolved to that value.\n * - Otherwise, the promise is resolved to an array containing all of the\n * function's arguments.\n *\n * @param {object} promise\n * An object containing the resolution and rejection functions of a\n * promise.\n * @param {function} promise.resolve\n * The promise's resolution function.\n * @param {function} promise.rejection\n * The promise's rejection function.\n * @param {object} metadata\n * Metadata about the wrapped method which has created the callback.\n * @param {integer} metadata.maxResolvedArgs\n * The maximum number of arguments which may be passed to the\n * callback created by the wrapped async function.\n *\n * @returns {function}\n * The generated callback function.\n */\n const makeCallback = (promise, metadata) => {\n return (...callbackArgs) => {\n if (chrome.runtime.lastError) {\n promise.reject(chrome.runtime.lastError);\n } else if (metadata.singleCallbackArg || callbackArgs.length === 1) {\n promise.resolve(callbackArgs[0]);\n } else {\n promise.resolve(callbackArgs);\n }\n };\n };\n\n const pluralizeArguments = numArgs => numArgs == 1 ? \"argument\" : \"arguments\";\n\n /**\n * Creates a wrapper function for a method with the given name and metadata.\n *\n * @param {string} name\n * The name of the method which is being wrapped.\n * @param {object} metadata\n * Metadata about the method being wrapped.\n * @param {integer} metadata.minArgs\n * The minimum number of arguments which must be passed to the\n * function. If called with fewer than this number of arguments, the\n * wrapper will raise an exception.\n * @param {integer} metadata.maxArgs\n * The maximum number of arguments which may be passed to the\n * function. If called with more than this number of arguments, the\n * wrapper will raise an exception.\n * @param {integer} metadata.maxResolvedArgs\n * The maximum number of arguments which may be passed to the\n * callback created by the wrapped async function.\n *\n * @returns {function(object, ...*)}\n * The generated wrapper function.\n */\n const wrapAsyncFunction = (name, metadata) => {\n return function asyncFunctionWrapper(target, ...args) {\n if (args.length < metadata.minArgs) {\n throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);\n }\n\n if (args.length > metadata.maxArgs) {\n throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);\n }\n\n return new Promise((resolve, reject) => {\n if (metadata.fallbackToNoCallback) {\n // This API method has currently no callback on Chrome, but it return a promise on Firefox,\n // and so the polyfill will try to call it with a callback first, and it will fallback\n // to not passing the callback if the first call fails.\n try {\n target[name](...args, makeCallback({ resolve, reject }, metadata));\n } catch (cbError) {\n console.warn(`${name} API method doesn't seem to support the callback parameter, ` + \"falling back to call it without a callback: \", cbError);\n\n target[name](...args);\n\n // Update the API method metadata, so that the next API calls will not try to\n // use the unsupported callback anymore.\n metadata.fallbackToNoCallback = false;\n metadata.noCallback = true;\n\n resolve();\n }\n } else if (metadata.noCallback) {\n target[name](...args);\n resolve();\n } else {\n target[name](...args, makeCallback({ resolve, reject }, metadata));\n }\n });\n };\n };\n\n /**\n * Wraps an existing method of the target object, so that calls to it are\n * intercepted by the given wrapper function. The wrapper function receives,\n * as its first argument, the original `target` object, followed by each of\n * the arguments passed to the orginal method.\n *\n * @param {object} target\n * The original target object that the wrapped method belongs to.\n * @param {function} method\n * The method being wrapped. This is used as the target of the Proxy\n * object which is created to wrap the method.\n * @param {function} wrapper\n * The wrapper function which is called in place of a direct invocation\n * of the wrapped method.\n *\n * @returns {Proxy}\n * A Proxy object for the given method, which invokes the given wrapper\n * method in its place.\n */\n const wrapMethod = (target, method, wrapper) => {\n return new Proxy(method, {\n apply(targetMethod, thisObj, args) {\n return wrapper.call(thisObj, target, ...args);\n }\n });\n };\n\n let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);\n\n /**\n * Wraps an object in a Proxy which intercepts and wraps certain methods\n * based on the given `wrappers` and `metadata` objects.\n *\n * @param {object} target\n * The target object to wrap.\n *\n * @param {object} [wrappers = {}]\n * An object tree containing wrapper functions for special cases. Any\n * function present in this object tree is called in place of the\n * method in the same location in the `target` object tree. These\n * wrapper methods are invoked as described in {@see wrapMethod}.\n *\n * @param {object} [metadata = {}]\n * An object tree containing metadata used to automatically generate\n * Promise-based wrapper functions for asynchronous. Any function in\n * the `target` object tree which has a corresponding metadata object\n * in the same location in the `metadata` tree is replaced with an\n * automatically-generated wrapper function, as described in\n * {@see wrapAsyncFunction}\n *\n * @returns {Proxy}\n */\n const wrapObject = (target, wrappers = {}, metadata = {}) => {\n let cache = Object.create(null);\n let handlers = {\n has(proxyTarget, prop) {\n return prop in target || prop in cache;\n },\n\n get(proxyTarget, prop, receiver) {\n if (prop in cache) {\n return cache[prop];\n }\n\n if (!(prop in target)) {\n return undefined;\n }\n\n let value = target[prop];\n\n if (typeof value === \"function\") {\n // This is a method on the underlying object. Check if we need to do\n // any wrapping.\n\n if (typeof wrappers[prop] === \"function\") {\n // We have a special-case wrapper for this method.\n value = wrapMethod(target, target[prop], wrappers[prop]);\n } else if (hasOwnProperty(metadata, prop)) {\n // This is an async method that we have metadata for. Create a\n // Promise wrapper for it.\n let wrapper = wrapAsyncFunction(prop, metadata[prop]);\n value = wrapMethod(target, target[prop], wrapper);\n } else {\n // This is a method that we don't know or care about. Return the\n // original method, bound to the underlying object.\n value = value.bind(target);\n }\n } else if (typeof value === \"object\" && value !== null && (hasOwnProperty(wrappers, prop) || hasOwnProperty(metadata, prop))) {\n // This is an object that we need to do some wrapping for the children\n // of. Create a sub-object wrapper for it with the appropriate child\n // metadata.\n value = wrapObject(value, wrappers[prop], metadata[prop]);\n } else {\n // We don't need to do any wrapping for this property,\n // so just forward all access to the underlying object.\n Object.defineProperty(cache, prop, {\n configurable: true,\n enumerable: true,\n get() {\n return target[prop];\n },\n set(value) {\n target[prop] = value;\n }\n });\n\n return value;\n }\n\n cache[prop] = value;\n return value;\n },\n\n set(proxyTarget, prop, value, receiver) {\n if (prop in cache) {\n cache[prop] = value;\n } else {\n target[prop] = value;\n }\n return true;\n },\n\n defineProperty(proxyTarget, prop, desc) {\n return Reflect.defineProperty(cache, prop, desc);\n },\n\n deleteProperty(proxyTarget, prop) {\n return Reflect.deleteProperty(cache, prop);\n }\n };\n\n // Per contract of the Proxy API, the \"get\" proxy handler must return the\n // original value of the target if that value is declared read-only and\n // non-configurable. For this reason, we create an object with the\n // prototype set to `target` instead of using `target` directly.\n // Otherwise we cannot return a custom object for APIs that\n // are declared read-only and non-configurable, such as `chrome.devtools`.\n //\n // The proxy handlers themselves will still use the original `target`\n // instead of the `proxyTarget`, so that the methods and properties are\n // dereferenced via the original targets.\n let proxyTarget = Object.create(target);\n return new Proxy(proxyTarget, handlers);\n };\n\n /**\n * Creates a set of wrapper functions for an event object, which handles\n * wrapping of listener functions that those messages are passed.\n *\n * A single wrapper is created for each listener function, and stored in a\n * map. Subsequent calls to `addListener`, `hasListener`, or `removeListener`\n * retrieve the original wrapper, so that attempts to remove a\n * previously-added listener work as expected.\n *\n * @param {DefaultWeakMap} wrapperMap\n * A DefaultWeakMap object which will create the appropriate wrapper\n * for a given listener function when one does not exist, and retrieve\n * an existing one when it does.\n *\n * @returns {object}\n */\n const wrapEvent = wrapperMap => ({\n addListener(target, listener, ...args) {\n target.addListener(wrapperMap.get(listener), ...args);\n },\n\n hasListener(target, listener) {\n return target.hasListener(wrapperMap.get(listener));\n },\n\n removeListener(target, listener) {\n target.removeListener(wrapperMap.get(listener));\n }\n });\n\n // Keep track if the deprecation warning has been logged at least once.\n let loggedSendResponseDeprecationWarning = false;\n\n const onMessageWrappers = new DefaultWeakMap(listener => {\n if (typeof listener !== \"function\") {\n return listener;\n }\n\n /**\n * Wraps a message listener function so that it may send responses based on\n * its return value, rather than by returning a sentinel value and calling a\n * callback. If the listener function returns a Promise, the response is\n * sent when the promise either resolves or rejects.\n *\n * @param {*} message\n * The message sent by the other end of the channel.\n * @param {object} sender\n * Details about the sender of the message.\n * @param {function(*)} sendResponse\n * A callback which, when called with an arbitrary argument, sends\n * that value as a response.\n * @returns {boolean}\n * True if the wrapped listener returned a Promise, which will later\n * yield a response. False otherwise.\n */\n return function onMessage(message, sender, sendResponse) {\n let didCallSendResponse = false;\n\n let wrappedSendResponse;\n let sendResponsePromise = new Promise(resolve => {\n wrappedSendResponse = function (response) {\n if (!loggedSendResponseDeprecationWarning) {\n console.warn(SEND_RESPONSE_DEPRECATION_WARNING, new Error().stack);\n loggedSendResponseDeprecationWarning = true;\n }\n didCallSendResponse = true;\n resolve(response);\n };\n });\n\n let result;\n try {\n result = listener(message, sender, wrappedSendResponse);\n } catch (err) {\n result = Promise.reject(err);\n }\n\n const isResultThenable = result !== true && isThenable(result);\n\n // If the listener didn't returned true or a Promise, or called\n // wrappedSendResponse synchronously, we can exit earlier\n // because there will be no response sent from this listener.\n if (result !== true && !isResultThenable && !didCallSendResponse) {\n return false;\n }\n\n // A small helper to send the message if the promise resolves\n // and an error if the promise rejects (a wrapped sendMessage has\n // to translate the message into a resolved promise or a rejected\n // promise).\n const sendPromisedResult = promise => {\n promise.then(msg => {\n // send the message value.\n sendResponse(msg);\n }, error => {\n // Send a JSON representation of the error if the rejected value\n // is an instance of error, or the object itself otherwise.\n let message;\n if (error && (error instanceof Error || typeof error.message === \"string\")) {\n message = error.message;\n } else {\n message = \"An unexpected error occurred\";\n }\n\n sendResponse({\n __mozWebExtensionPolyfillReject__: true,\n message\n });\n }).catch(err => {\n // Print an error on the console if unable to send the response.\n console.error(\"Failed to send onMessage rejected reply\", err);\n });\n };\n\n // If the listener returned a Promise, send the resolved value as a\n // result, otherwise wait the promise related to the wrappedSendResponse\n // callback to resolve and send it as a response.\n if (isResultThenable) {\n sendPromisedResult(result);\n } else {\n sendPromisedResult(sendResponsePromise);\n }\n\n // Let Chrome know that the listener is replying.\n return true;\n };\n });\n\n const wrappedSendMessageCallback = ({ reject, resolve }, reply) => {\n if (chrome.runtime.lastError) {\n reject(chrome.runtime.lastError);\n } else if (reply && reply.__mozWebExtensionPolyfillReject__) {\n // Convert back the JSON representation of the error into\n // an Error instance.\n reject(new Error(reply.message));\n } else {\n resolve(reply);\n }\n };\n\n const wrappedSendMessage = (name, metadata, apiNamespaceObj, ...args) => {\n if (args.length < metadata.minArgs) {\n throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);\n }\n\n if (args.length > metadata.maxArgs) {\n throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);\n }\n\n return new Promise((resolve, reject) => {\n const wrappedCb = wrappedSendMessageCallback.bind(null, { resolve, reject });\n args.push(wrappedCb);\n apiNamespaceObj.sendMessage(...args);\n });\n };\n\n const staticWrappers = {\n runtime: {\n onMessage: wrapEvent(onMessageWrappers),\n onMessageExternal: wrapEvent(onMessageWrappers),\n sendMessage: wrappedSendMessage.bind(null, \"sendMessage\", { minArgs: 1, maxArgs: 3 })\n },\n tabs: {\n sendMessage: wrappedSendMessage.bind(null, \"sendMessage\", { minArgs: 2, maxArgs: 3 })\n }\n };\n\n return wrapObject(chrome, staticWrappers, apiMetadata);\n };\n\n // The build process adds a UMD wrapper around this file, which makes the\n // `module` variable available.\n module.exports = wrapAPIs(); // eslint-disable-line no-undef\n } else {\n module.exports = browser; // eslint-disable-line no-undef\n }\n});\n//# sourceMappingURL=browser-polyfill.js.map\n"]} \ No newline at end of file diff --git a/popup/main.js b/popup/main.js new file mode 100644 index 0000000..fd96aa0 --- /dev/null +++ b/popup/main.js @@ -0,0 +1,68 @@ +let listEnvironments = document.querySelector(".list-environments") +let btnAddEnv = document.getElementById("btn-add-env"); +let btnSaveEnv = document.getElementById("btn-save-env"); + +let addEnvironment = function(url, color){ + let environmentNode = document.createElement("section"); + environmentNode.classList.add("environment"); + + let envColor = document.createElement("input"); + envColor.type = "color"; + envColor.value = color || randomDefaultColor(); + environmentNode.appendChild(envColor); + + let envDomain = document.createElement("input"); + envDomain.type = "text"; + envDomain.placeholder = "*.dev.example.com"; + envDomain.value = url || ""; + environmentNode.appendChild(envDomain); + + let envRemove = document.createElement("button"); + envRemove.className = "btn-remove"; + envRemove.textContent = "Remove"; + envRemove.addEventListener("click", () => removeEnvironment(environmentNode), false); + environmentNode.appendChild(envRemove); + + listEnvironments.appendChild(environmentNode); +} + +let randomDefaultColor = function(){ + let flatColors = [ "#0a84ff", "#00feff", "#ff1ad9", "#30e60b", "#ffe900", "#ff0039", "#9400ff", "#ff9400", "#363959", "#737373"]; + return flatColors[ Math.floor(Math.random() * flatColors.length)]; +} + +let removeEnvironment = function(section){ + section.remove(); +} + +let updateEnvironments = function(){ + let environments = {}; + for (let el of listEnvironments.children){ + let url = el.querySelector("input[type=text]").value; + if(!url){ + continue; + } + environments[url] = el.querySelector("input[type=color]").value; + } + browser.storage.sync.set({"environments": environments}).catch(function(err){ + btnAddEnv.setCustomValidity("Could not save your environments"); + btnAddEnv.reportValidity(); + }); +} + +btnAddEnv.addEventListener("click", function() { addEnvironment() }, false) +btnSaveEnv.addEventListener("click", updateEnvironments, false) + +document.addEventListener("DOMContentLoaded", function(){ + browser.storage.sync.get("environments") + .then(function(results){ + let { environments } = results; + Object.keys(environments).map(function(value){ + addEnvironment(value, environments[value]); + }); + }) + .catch(function(err){ + btnAddEnv.setCustomValidity("Could not load your environments"); + btnAddEnv.reportValidity(); + }) +}, false) diff --git a/popup/manage_env.html b/popup/manage_env.html new file mode 100644 index 0000000..92500fb --- /dev/null +++ b/popup/manage_env.html @@ -0,0 +1,23 @@ + + + + + + + Envify + + + +

Envify

+

Define your own environments below.

+ +
+ +
+ + + + + + + diff --git a/popup/styles.css b/popup/styles.css new file mode 100644 index 0000000..b254f85 --- /dev/null +++ b/popup/styles.css @@ -0,0 +1,62 @@ +html, body { + height: 100%; + margin: 0; +} + +body { + padding: 20px; + background: linear-gradient(#34495e, #2c3e50); + color: #ecf0f1; + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; +} + +* { + box-sizing: inherit; +} + +h1 { + font-family: 'Courier', monospace; + text-align: center; +} + +#btn-add-env { + height: 10%; + font-weight: bolder; + font-family: 'Courier', monospace; + margin-bottom: 7px; +} + +.list-environments { + width: 100%; + margin: 0 auto; + border: 2px dashed #2ecc71; + padding: 1%; +} + +.environment { + display: flex; + margin: 5px; + justify-content: left; + align-items: stretch; +} + + +input[type="color"] { + border: none; + background-color: white; + padding: 0; + min-width: 57px; +} + +input[type="color"]::-moz-color-swatch{ + border: none; +} + +input[type="text"] { + width: 100%; + height: inherit; + border: none; +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..7cef13b --- /dev/null +++ b/style.css @@ -0,0 +1,20 @@ +body.envify { + padding-left: 35px !important; + padding-right: 35px !important; +} + +body div.envify.left { + position: fixed; + top: 0px; + left: 0px; + height: 100%; + width: 35px; +} + +body div.envify.right { + position: fixed; + top: 0px; + right: 0px; + height: 100%; + width: 35px; +}