Dancer18

Custom.js

Mar 29th, 2022 (edited)
412
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 37.57 KB | None | 0 0
  1. // Tab Scroll
  2. // https://forum.vivaldi.net/topic/27856/tab-scroll
  3. // Clicking on an active tab scrolls page to top, clicking it again returns to previous scroll position.
  4. // Credits to tam710562 from Vivaldi Forum for coming up with the sessionStorage solution, which made this possible.
  5.  
  6. {
  7.     function tabScrollExit(tab) {
  8.         tab.removeEventListener('mousemove', tabScrollExit);
  9.         tab.removeEventListener('click', tabScrollTrigger);
  10.     }
  11.  
  12.     function tabScrollTrigger(tab) {
  13.         chrome.tabs.executeScript({code: tabScrollScript});
  14.         tabScrollExit(tab);
  15.     }
  16.  
  17.     function tabScroll(e, tab) {
  18.         if (tab.parentNode.classList.contains('active') && e.which === 1 && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
  19.             tab.addEventListener('mousemove', tabScrollExit(tab));
  20.             tab.addEventListener('click', tabScrollTrigger(tab));
  21.         }
  22.     }
  23.  
  24.     const tabScrollScript = '!' + function () {
  25.         var offset = window.pageYOffset;
  26.         if (offset > 0) {
  27.             window.sessionStorage.setItem('tabOffset',offset);
  28.             window.scrollTo(0,0);
  29.         }
  30.         else {
  31.             window.scrollTo(0,window.sessionStorage.getItem('tabOffset')||0);
  32.         }
  33.     } + '();';
  34.  
  35.     var appendChild = Element.prototype.appendChild;
  36.     Element.prototype.appendChild = function () {
  37.         if (arguments[0].tagName === 'DIV' && arguments[0].classList.contains('tab-header')) {
  38.             setTimeout(function() {
  39.                 const trigger = (event) => tabScroll(event, arguments[0]);
  40.                 arguments[0].addEventListener('mousedown', trigger);
  41.             }.bind(this, arguments[0]));
  42.         }
  43.         return appendChild.apply(this, arguments);
  44.     }
  45. }
  46.  
  47.  
  48.  
  49. /*
  50.  * Restore Methods for chrome.tabs
  51.  * Written by Tam710562
  52.  */
  53.  
  54. window.gnoh = Object.assign(window.gnoh || {}, {
  55.   tabs: {
  56.     getAllInWindow: function () {
  57.       let windowId;
  58.       let callback;
  59.  
  60.       Array.from(arguments).forEach(function (argument) {
  61.         switch (typeof argument) {
  62.           case 'number':
  63.             windowId = argument;
  64.             break;
  65.           default:
  66.             callback = argument;
  67.             break;
  68.         }
  69.       });
  70.  
  71.       chrome.tabs.query({
  72.         windowId: windowId || vivaldiWindowId
  73.       }, function (tabs) {
  74.         callback(tabs);
  75.       });
  76.     },
  77.     getSelected: function () {
  78.       let windowId;
  79.       let callback;
  80.  
  81.       Array.from(arguments).forEach(function (argument) {
  82.         switch (typeof argument) {
  83.           case 'number':
  84.             windowId = argument;
  85.             break;
  86.           default:
  87.             callback = argument;
  88.             break;
  89.         }
  90.       });
  91.  
  92.       chrome.tabs.query({
  93.         active: true,
  94.         windowId: windowId || vivaldiWindowId
  95.       }, function (tabs) {
  96.         const tab = tabs[0];
  97.         if (tab) {
  98.           callback(tab);
  99.         }
  100.       });
  101.     },
  102.     executeScript: function () {
  103.       let tabId;
  104.       let details;
  105.       let callback;
  106.  
  107.       Array.from(arguments).forEach(function (argument) {
  108.         switch (typeof argument) {
  109.           case 'number':
  110.             tabId = argument;
  111.             break;
  112.           case 'object':
  113.             details = argument;
  114.             break;
  115.           default:
  116.             callback = argument;
  117.             break;
  118.         }
  119.       });
  120.  
  121.       if (tabId) {
  122.         gnoh.webPageView.callMethod(tabId, 'executeScript', [details, callback]);
  123.       } else {
  124.         gnoh.webPageView.callMethod('executeScript', [details, callback]);
  125.       }
  126.     },
  127.     insertCSS: function () {
  128.       let tabId;
  129.       let details;
  130.       let callback;
  131.  
  132.       Array.from(arguments).forEach(function (argument) {
  133.         switch (typeof argument) {
  134.           case 'number':
  135.             tabId = argument;
  136.             break;
  137.           case 'object':
  138.             details = argument;
  139.             break;
  140.           default:
  141.             callback = argument;
  142.             break;
  143.         }
  144.       });
  145.  
  146.       if (tabId) {
  147.         gnoh.webPageView.callMethod(tabId, 'insertCSS', [details, callback]);
  148.       } else {
  149.         gnoh.webPageView.callMethod('insertCSS', [details, callback]);
  150.       }
  151.     }
  152.   },
  153.   webPageView: {
  154.     getSelected(callback) {
  155.       gnoh.tabs.getSelected(function (tab) {
  156.         callback(this.get(tab.id));
  157.       }.bind(this));
  158.     },
  159.     get: function (tabId) {
  160.       return document.getElementById(tabId);
  161.     },
  162.     callMethod: function () {
  163.       let tabId;
  164.       let methodName;
  165.       let args;
  166.  
  167.       Array.from(arguments).forEach(function (argument) {
  168.         switch (typeof argument) {
  169.           case 'number':
  170.             tabId = argument;
  171.             break;
  172.           case 'string':
  173.             methodName = argument;
  174.             break;
  175.           default:
  176.             args = argument;
  177.             break;
  178.         }
  179.       });
  180.  
  181.       if (tabId) {
  182.         const wpw = this.get(tabId);
  183.         wpw[methodName].apply(wpw, args);
  184.       } else {
  185.         this.getSelected(function (wpw) {
  186.           wpw[methodName].apply(wpw, args);
  187.         });
  188.       }
  189.     }
  190.   }
  191. });
  192.  
  193. if (!chrome.tabs.getAllInWindow) {
  194.   chrome.tabs.getAllInWindow = gnoh.tabs.getAllInWindow;
  195. }
  196.  
  197. if (!chrome.tabs.getSelected) {
  198.   chrome.tabs.getSelected = gnoh.tabs.getSelected;
  199. }
  200.  
  201. if (!chrome.tabs.executeScript) {
  202.   chrome.tabs.executeScript = gnoh.tabs.executeScript;
  203. }
  204.  
  205. if (!chrome.tabs.insertCSS) {
  206.   chrome.tabs.insertCSS = gnoh.tabs.insertCSS;
  207. }
  208.  
  209.  
  210. /*
  211.  * Choose Search engine in Address bar
  212.  * Written by Tam710562
  213.  */
  214.  
  215. window.gnoh = Object.assign(window.gnoh || {}, {
  216.   generateUUID: function (ids) {
  217.     let d = Date.now() + performance.now();
  218.     let r;
  219.     const id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  220.       r = (d + Math.random() * 16) % 16 | 0;
  221.       d = Math.floor(d / 16);
  222.       return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
  223.     });
  224.  
  225.     if (Array.isArray(ids) && ids.includes(id)) {
  226.       return this.generateUUID(ids);
  227.     }
  228.     return id;
  229.   },
  230.   addStyle: function (css, id, isNotMin) {
  231.     this.styles = this.styles || {};
  232.     if (Array.isArray(css)) {
  233.       css = css.join(isNotMin === true ? '\n' : '');
  234.     }
  235.     id = id || this.generateUUID(Object.keys(this.styles));
  236.     this.styles[id] = this.createElement('style', {
  237.       html: css || '',
  238.       'data-id': id
  239.     }, document.head);
  240.     return this.styles[id];
  241.   },
  242.   encode: {
  243.     regex: function (str) {
  244.       return !str ? str : str.replace(/[-/\\^$*+?.()|[]{}]/g, '\\$&');
  245.     }
  246.   },
  247.   createElement: function (tagName, attribute, parent, inner, options) {
  248.     if (typeof tagName === 'undefined') {
  249.       return;
  250.     }
  251.     if (typeof options === 'undefined') {
  252.       options = {};
  253.     }
  254.     if (typeof options.isPrepend === 'undefined') {
  255.       options.isPrepend = false;
  256.     }
  257.     const el = document.createElement(tagName);
  258.     if (!!attribute && typeof attribute === 'object') {
  259.       for (const key in attribute) {
  260.         if (key === 'text') {
  261.           el.textContent = attribute[key];
  262.         } else if (key === 'html') {
  263.           el.innerHTML = attribute[key];
  264.         } else if (key === 'style' && typeof attribute[key] === 'object') {
  265.           for (const css in attribute.style) {
  266.             el.style[css] = attribute.style[css];
  267.           }
  268.         } else if (key === 'events' && typeof attribute[key] === 'object') {
  269.           for (const event in attribute.events) {
  270.             if (typeof attribute.events[event] === 'function') {
  271.               el.addEventListener(event, attribute.events[event]);
  272.             }
  273.           }
  274.         } else if (typeof el[key] !== 'undefined') {
  275.           el[key] = attribute[key];
  276.         } else {
  277.           if (typeof attribute[key] === 'object') {
  278.             attribute[key] = JSON.stringify(attribute[key]);
  279.           }
  280.           el.setAttribute(key, attribute[key]);
  281.         }
  282.       }
  283.     }
  284.     if (!!inner) {
  285.       if (!Array.isArray(inner)) {
  286.         inner = [inner];
  287.       }
  288.       for (let i = 0; i < inner.length; i++) {
  289.         if (inner[i].nodeName) {
  290.           el.append(inner[i]);
  291.         } else {
  292.           el.append(this.createElementFromHTML(inner[i]));
  293.         }
  294.       }
  295.     }
  296.     if (typeof parent === 'string') {
  297.       parent = document.querySelector(parent);
  298.     }
  299.     if (!!parent) {
  300.       if (options.isPrepend) {
  301.         parent.prepend(el);
  302.       } else {
  303.         parent.append(el);
  304.       }
  305.     }
  306.     return el;
  307.   },
  308.   createElementFromHTML: function (html) {
  309.     return this.createElement('template', {
  310.       html: (html || '').trim()
  311.     }).content;
  312.   },
  313.   override: function (obj, functionName, callback, conditon, runbefore) {
  314.     this._overrides = this._overrides || {};
  315.     let subKey = '';
  316.     try {
  317.       if (obj.ownerDocument === document) {
  318.         this._overrides._elements = this._overrides._elements || [];
  319.         const element = this._overrides._elements.find(function (item) {
  320.           return item.element === obj;
  321.         });
  322.         let id;
  323.         if (element) {
  324.           id = element.id;
  325.         } else {
  326.           id = this.generateUUID(this._overrides._elements.map(function (item) {
  327.             return item.id;
  328.           }));
  329.           this._overrides._elements.push({
  330.             element: obj,
  331.             id: id
  332.           });
  333.         }
  334.         subKey = '_' + id;
  335.       }
  336.     } catch (e) { }
  337.     const key = functionName + '_' + obj.constructor.name + subKey;
  338.     if (!this._overrides[key]) {
  339.       this._overrides[key] = [];
  340.       obj[functionName] = (function (_super) {
  341.         return function () {
  342.           let result;
  343.           let conditon = true;
  344.           for (let i = 0; i < gnoh._overrides[key].length; i++) {
  345.             conditon = conditon && (typeof gnoh._overrides[key][i].conditon !== 'function' && gnoh._overrides[key][i].conditon !== false || typeof gnoh._overrides[key][i].conditon === 'function' && !!gnoh._overrides[key][i].conditon.apply(this, arguments));
  346.             if (conditon === false) {
  347.               continue;
  348.             }
  349.             if (gnoh._overrides[key][i].runbefore === true) {
  350.               gnoh._overrides[key][i].callback.apply(this, arguments);
  351.             }
  352.           }
  353.           if (conditon) {
  354.             result = _super.apply(this, arguments);
  355.           }
  356.           for (let i = 0; i < gnoh._overrides[key].length; i++) {
  357.             if (gnoh._overrides[key][i].runbefore !== true) {
  358.               gnoh._overrides[key][i].callback.apply(this, arguments);
  359.             }
  360.           }
  361.           return result;
  362.         };
  363.       })(obj[functionName]);
  364.     }
  365.  
  366.     this._overrides[key].push({
  367.       callback: callback,
  368.       conditon: conditon,
  369.       runbefore: runbefore
  370.     });
  371.     return key;
  372.   },
  373.   getReactPropsKey: function (element) {
  374.     if (!this.reactPropsKey) {
  375.       if (!element) {
  376.         element = document.getElementById('browser');
  377.       } else if (typeof element === 'string') {
  378.         element = document.querySelector(element);
  379.       }
  380.       if (!element || element.ownerDocument !== document) {
  381.         return;
  382.       }
  383.       this.reactPropsKey = Object.keys(element).find(function (key) {
  384.         return key.startsWith('__reactProps');
  385.       });
  386.     }
  387.     return this.reactPropsKey;
  388.   }
  389. });
  390.  
  391. (function () {
  392.   'use strict';
  393.  
  394.   gnoh.addStyle([
  395.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar { position: sticky; top: 0; right: 0; left: 0; background: var(--colorBg); height: 32px; box-shadow: 0px -1px var(--colorBorder) inset; z-index: 1; }',
  396.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar button { background: transparent; border: 0; width: 32px; height: 32px; border-radius: 0; display: inline-flex; align-items: center; justify-content: center; border: 1px solid transparent; }',
  397.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar button:hover { background-color: var(--colorFgAlpha); }',
  398.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar button.active { background: var(--colorBgIntense); border-left-color: var(--colorBorder); border-right-color: var(--colorBorder); border-top-color: var(--colorBorder); }',
  399.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar button.disabled { pointer-events: none; }',
  400.     '.UrlBar-AddressField .OmniDropdown .search-engines-in-address-bar button:first-child { border-left-color: transparent; }'
  401.   ], 'search-engines-in-address-bar');
  402.  
  403.   const settings = {
  404.     oneClick: true,
  405.     searchEngines: {
  406.       default: undefined,
  407.       defaultPrivate: undefined,
  408.       engines: {}
  409.     },
  410.   };
  411.  
  412.   const pattern = {
  413.     searchEngines: undefined
  414.   };
  415.  
  416.   let searchEngineButtons;
  417.  
  418.   let reactPropsKey;
  419.  
  420.   function createPatternSearchEngines(searchEngineCollection) {
  421.     settings.searchEngines = {
  422.       default: undefined,
  423.       defaultPrivate: undefined,
  424.       engines: {}
  425.     };
  426.     pattern.searchEngines = undefined;
  427.     const engines = searchEngineCollection.engines.filter(e => e.removed !== true);
  428.     if (engines.length > 0) {
  429.       const regKeywords = [];
  430.       engines.forEach(function (engine) {
  431.         settings.searchEngines.engines[engine.keyword] = engine;
  432.         regKeywords.push(gnoh.encode.regex(engine.keyword));
  433.       });
  434.  
  435.       pattern.searchEngines = new RegExp('^(' + regKeywords.join('|') + ')\\s(.*)', 'i');
  436.     }
  437.   }
  438.  
  439.   chrome.storage.local.get({
  440.     'SEARCH_ENGINE_COLLECTION': {
  441.       engines: []
  442.     }
  443.   }, function (res) {
  444.     createPatternSearchEngines(res.SEARCH_ENGINE_COLLECTION);
  445.   });
  446.  
  447.   chrome.storage.local.onChanged.addListener(function (changes, namespace) {
  448.     if (changes.SEARCH_ENGINE_COLLECTION) {
  449.       createPatternSearchEngines(changes.SEARCH_ENGINE_COLLECTION.newValue);
  450.     }
  451.   });
  452.  
  453.   function createSearchEnginesInAddressBar(omniDropdown) {
  454.     const searchEnginesInAddressBar = gnoh.createElement('div', {
  455.       class: 'search-engines-in-address-bar'
  456.     }, omniDropdown, null, {
  457.       isPrepend: true
  458.     });
  459.  
  460.     const addressfieldEl = document.querySelector('input[type="text"].url.vivaldi-addressfield');
  461.  
  462.     searchEngineButtons = [];
  463.  
  464.     Object.values(settings.searchEngines.engines).forEach(function (engine) {
  465.       const searchEngineButton = gnoh.createElement('button', {
  466.         class: 'search-engine-button',
  467.         title: engine.keyword + ' : ' + engine.name,
  468.         events: {
  469.           mousedown: function (event) {
  470.             event.preventDefault();
  471.             event.stopPropagation();
  472.             if (!addressfieldEl) {
  473.               return;
  474.             }
  475.             const match = addressfieldEl.value.match(pattern.searchEngines);
  476.             let value = '';
  477.             if (match) {
  478.               if (match[1] === engine.keyword && !settings.oneClick) {
  479.                 return;
  480.               }
  481.               value = engine.keyword + ' ' + match[2];
  482.             } else {
  483.               value = engine.keyword + ' ' + addressfieldEl.value;
  484.             }
  485.             if (settings.oneClick) {
  486.               addressfieldEl[reactPropsKey].onChange({ currentTarget: { value: value } });
  487.               addressfieldEl[reactPropsKey].onKeyDown(new KeyboardEvent('keydown', { key: 'Enter', metaKey: true }));
  488.             } else {
  489.               addressfieldEl[reactPropsKey].onChange({ currentTarget: { value: value } });
  490.               setActiveSearchEngineButton(engine.keyword);
  491.             }
  492.           }
  493.         }
  494.       }, searchEnginesInAddressBar);
  495.       const searchEngineIcon = gnoh.createElement('img', {
  496.         class: 'search-engine-icon',
  497.         src: engine.faviconUrl,
  498.         width: 16,
  499.         height: 16
  500.       }, searchEngineButton);
  501.       searchEngineButtons.push({
  502.         keyword: engine.keyword,
  503.         element: searchEngineButton
  504.       });
  505.     });
  506.  
  507.     const removeSearchEngineButton = gnoh.createElement('button', {
  508.       class: 'remove-search-engine-button',
  509.       events: {
  510.         mousedown: function (event) {
  511.           event.preventDefault();
  512.           event.stopPropagation();
  513.           if (!addressfieldEl) {
  514.             return;
  515.           }
  516.           const match = addressfieldEl.value.match(pattern.searchEngines);
  517.           let value = '';
  518.           if (match) {
  519.             value = match[2];
  520.             addressfieldEl[reactPropsKey].onChange({ currentTarget: { value: value } });
  521.             setActiveSearchEngineButton('');
  522.           }
  523.         }
  524.       }
  525.     }, searchEnginesInAddressBar, '<svg style="width:16px; height:16px" viewBox="0 0 24 24"><path fill="currentColor" d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"/></svg>');
  526.  
  527.     searchEngineButtons.push({
  528.       keyword: '',
  529.       element: removeSearchEngineButton
  530.     });
  531.  
  532.     const match = addressfieldEl.value.match(pattern.searchEngines);
  533.     setActiveSearchEngineButton(match ? match[1] : '');
  534.  
  535.     if (!addressfieldEl.dataset.searchEnginesInAddressBar) {
  536.       addressfieldEl.dataset.searchEnginesInAddressBar = '';
  537.       addressfieldEl.addEventListener('input', function (e) {
  538.         const match = e.target.value.match(pattern.searchEngines);
  539.         setActiveSearchEngineButton(match ? match[1] : '');
  540.       });
  541.     }
  542.   }
  543.  
  544.   function setActiveSearchEngineButton(keyword) {
  545.     searchEngineButtons.forEach(function (seb) {
  546.       if (seb.keyword === keyword) {
  547.         seb.element.classList.add('active');
  548.         if (!settings.oneClick) {
  549.           seb.element.classList.add('disabled');
  550.         }
  551.       } else {
  552.         seb.element.classList.remove('active');
  553.         if (!settings.oneClick) {
  554.           seb.element.classList.remove('disabled');
  555.         }
  556.       }
  557.     });
  558.   }
  559.  
  560.   gnoh.override(HTMLDivElement.prototype, 'appendChild', function (element) {
  561.     reactPropsKey = gnoh.getReactPropsKey(this);
  562.     if (this[reactPropsKey] && this[reactPropsKey].className === 'observer' && element[reactPropsKey] && element[reactPropsKey].className.indexOf('OmniDropdown') > -1) {
  563.       createSearchEnginesInAddressBar(element)
  564.     }
  565.   });
  566. })();
  567.  
  568.  
  569.  
  570. // Backup Search Engines
  571. // https://forum.vivaldi.net/topic/35443/backup-search-engines
  572. // Adds functionality to backup and restore search engines in vivaldi://settings/search.
  573.  
  574. {
  575.     function _msgSearch(pnt) {
  576.         clearTimeout(_msgTimeout);
  577.         if (pnt === 'backup') {
  578.             _infoSearch.innerText = 'Search engines backup copied to clipboard.';
  579.         }
  580.         else if (pnt === 'restore') {
  581.             _infoSearch.innerText = 'Search engines restored.';
  582.         }
  583.         else {
  584.             _infoSearch.innerText = 'Search engines code error.'
  585.         }
  586.         _msgTimeout = setTimeout(function() {
  587.             _infoSearch.innerText = '';
  588.         }, 5000)
  589.     }
  590.  
  591.     function _restoreSearch() {
  592.         event.preventDefault();
  593.         event.stopPropagation();
  594.         if (_eventSearch === 'paste') {
  595.             var clipboardData = event.clipboardData || window.clipboardData;
  596.             var engineCode = clipboardData.getData('text');
  597.         }
  598.         else {
  599.             var engineCode = event.dataTransfer.getData('text');
  600.         }
  601.         try {
  602.             var engines = JSON.parse(engineCode);
  603.         }
  604.         catch(err) {
  605.             _msgSearch('error');
  606.             return;
  607.         }
  608.         if ('engines' in engines && 'default' in engines && 'defaultPrivate' in engines) {
  609.             chrome.storage.local.set({'SEARCH_ENGINE_COLLECTION': engines}, function() {
  610.                 _msgSearch('restore');
  611.             })
  612.         }
  613.         else {
  614.             _msgSearch('error');
  615.         }
  616.     }
  617.  
  618.     function _backupSearch() {
  619.         chrome.storage.local.get({'SEARCH_ENGINE_COLLECTION': ''}, function(back) {
  620.             const engines = back.SEARCH_ENGINE_COLLECTION;
  621.             const engineCode = JSON.stringify(engines);
  622.             navigator.clipboard.writeText(engineCode);
  623.             _msgSearch('backup');
  624.         })
  625.     }
  626.  
  627.     function searchEngines() {
  628.         const styleCheck = document.getElementById('searchEngines');
  629.         if (!styleCheck) {
  630.             const style = document.createElement('style');
  631.             style.type = 'text/css';
  632.             style.id = 'searchEngines';
  633.             style.innerHTML = '#backupSearch, #restoreSearch {margin-left: 6px;}#restoreSearch{width: 130px;margin-top: 6px;}#restoreSearch::-webkit-input-placeholder {opacity: 1;color: var(--colorHighlightBg);text-align: center;}#msgConfirm{margin-left: 12px}';
  634.             document.getElementsByTagName('head')[0].appendChild(style);
  635.         }
  636.         const modCheck = document.getElementById('backupSearch');
  637.         if (!modCheck) {
  638.             const place = document.querySelector('.setting-section > div > .setting-group.unlimited > .setting-single');
  639.             const backupBtn = document.createElement('input');
  640.             backupBtn.setAttribute('type', 'button');
  641.             backupBtn.setAttribute('value', 'Backup');
  642.             backupBtn.id = 'backupSearch';
  643.             place.insertBefore(backupBtn, place.lastChild);
  644.             const restoreInput = document.createElement('input');
  645.             restoreInput.setAttribute('type', 'text');
  646.             restoreInput.setAttribute('placeholder', 'Restore Backup');
  647.             restoreInput.id = 'restoreSearch';
  648.             place.insertBefore(restoreInput, place.lastChild);
  649.             _infoSearch = document.createElement('span');
  650.             _infoSearch.id = 'msgConfirm';
  651.             place.insertBefore(_infoSearch, place.lastChild);
  652.             document.getElementById('backupSearch').addEventListener('click', _backupSearch);
  653.             const restoreSearch = document.getElementById('restoreSearch');
  654.             restoreSearch.addEventListener('paste', function() {
  655.                 _eventSearch = 'paste';
  656.                 _restoreSearch(event);
  657.             })
  658.             restoreSearch.addEventListener('drop', function() {
  659.                 _eventSearch = 'drop';
  660.                 _restoreSearch(event);
  661.             })
  662.             _msgTimeout = {};
  663.         }
  664.     }
  665.  
  666.     const settingsUrl = 'chrome-extension://mpognobbkildjkofajifpdfhcoklimli/components/settings/settings.html?path=';
  667.     chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  668.         if (changeInfo.url === `${settingsUrl}search`) {
  669.             setTimeout(searchEngines, 100);
  670.         }
  671.     })
  672. }
  673.  
  674.  
  675.  
  676. /*
  677.  * Markdown Editor for Notes
  678.  * Written by Tam710562 and sjudenim
  679.  * GNU General Public License v3.0
  680.  *
  681.  * Adds a markdwon toolbar to the notes editor
  682.  */
  683. (function () {
  684.  
  685.     const buttons = [
  686.         {
  687.             name: 'Bold',
  688.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 384 512"><path d="M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z"></path></svg>',
  689.             markdown: '**',
  690.             wrap: true,
  691.             textDefault: 'bold text',
  692.         },
  693.         {
  694.             name: 'Italic',
  695.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 320 512"><path d="M204.758 416h-33.849l62.092-320h40.725a16 16 0 0 0 15.704-12.937l6.242-32C297.599 41.184 290.034 32 279.968 32H120.235a16 16 0 0 0-15.704 12.937l-6.242 32C96.362 86.816 103.927 96 113.993 96h33.846l-62.09 320H46.278a16 16 0 0 0-15.704 12.935l-6.245 32C22.402 470.815 29.967 480 40.034 480h158.479a16 16 0 0 0 15.704-12.935l6.245-32c1.927-9.88-5.638-19.065-15.704-19.065z"></path></svg>',
  696.             markdown: '*',
  697.             wrap: true,
  698.             textDefault: 'italicized text',
  699.         },
  700.         {
  701.             name: 'Strikethrough',
  702.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 512 512"><path d="M496 288H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h480c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16zm-214.666 16c27.258 12.937 46.524 28.683 46.524 56.243 0 33.108-28.977 53.676-75.621 53.676-32.325 0-76.874-12.08-76.874-44.271V368c0-8.837-7.164-16-16-16H113.75c-8.836 0-16 7.163-16 16v19.204c0 66.845 77.717 101.82 154.487 101.82 88.578 0 162.013-45.438 162.013-134.424 0-19.815-3.618-36.417-10.143-50.6H281.334zm-30.952-96c-32.422-13.505-56.836-28.946-56.836-59.683 0-33.92 30.901-47.406 64.962-47.406 42.647 0 64.962 16.593 64.962 32.985V136c0 8.837 7.164 16 16 16h45.613c8.836 0 16-7.163 16-16v-30.318c0-52.438-71.725-79.875-142.575-79.875-85.203 0-150.726 40.972-150.726 125.646 0 22.71 4.665 41.176 12.777 56.547h129.823z"></path></svg>',
  703.             markdown: '~~',
  704.             wrap: true,
  705.             textDefault: 'strikethrough text',
  706.         },
  707.         {
  708.             name: 'Underline',
  709.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 16 16"><path d="M.5.5v2h1.25v6c0 2.758 2.805 5 6.25 5s6.25-2.242 6.25-5v-6h1.25v-2h-5v2h1.25v6c0 1.656-1.682 3.002-3.75 3.002S4.25 10.156 4.25 8.5v-6H5.5v-2h-5zM.5 14v2h15v-2H.5z"></path></svg>',
  710.             markdown: '++',
  711.             wrap: true,
  712.             textDefault: 'underline text',
  713.         },
  714.         {
  715.             name: 'Highlight',
  716.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 544 512"><path d="M0 479.98L99.92 512l35.45-35.45-67.04-67.04L0 479.98zm124.61-240.01a36.592 36.592 0 0 0-10.79 38.1l13.05 42.83-50.93 50.94 96.23 96.23 50.86-50.86 42.74 13.08c13.73 4.2 28.65-.01 38.15-10.78l35.55-41.64-173.34-173.34-41.52 35.44zm403.31-160.7l-63.2-63.2c-20.49-20.49-53.38-21.52-75.12-2.35L190.55 183.68l169.77 169.78L530.27 154.4c19.18-21.74 18.15-54.63-2.35-75.13z"></path></svg>',
  717.             markdown: '==',
  718.             wrap: true,
  719.             textDefault: 'highlight text',
  720.         },
  721.         {
  722.             name: 'Heading',
  723.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 512 512"><path d="M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z"></path></svg>',
  724.             markdown: '# ',
  725.             newline: true,
  726.             textDefault: 'heading text',
  727.         },
  728.         {
  729.             name: 'Heading 2',
  730.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" viewBox="0 0 512 512"><path d="M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z"></path></svg>',
  731.             markdown: '## ',
  732.             newline: true,
  733.             textDefault: 'heading 2 text',
  734.         },
  735.         {
  736.             name: 'Heading 3',
  737.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="11" height="7" viewBox="0 0 512 512"><path d="M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z"></path></svg>',
  738.             markdown: '### ',
  739.             newline: true,
  740.             textDefault: 'heading 3 text',
  741.         },
  742.         {
  743.             name: 'Blockquote',
  744.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 24 24"><path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z"></path></svg>',
  745.             markdown: '> ',
  746.             newline: true,
  747.             textDefault: 'blockquote',
  748.         },
  749.         {
  750.             name: 'Ordered List',
  751.             icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" version="1.0" height="16" width="16"><path d="M5.97 3l-.314.344S4.9 4 4.406 4v2c.68 0 1.15-.276 1.594-.53V10h2V3H5.97zM11 6v2h17V6H11zm-4.5 6C5.117 12 4 13.117 4 14.5v.5h2v-.5c0-.217.283-.5.5-.5.217 0 .5.283.5.5l-.03.03-.064.064-2.593 2.5-.313.28V19h5v-2H7.28l.876-.875.125-.094-.03-.03c.502-.41.75-1.02.75-1.5C9 13.117 7.883 12 6.5 12zm4.5 3v2h17v-2H11zm-7 6v2h1.375l-.25.406-.125.22V25h1.5c.217 0 .5.283.5.5 0 .217-.283.5-.5.5H4v2h2.5C7.883 28 9 26.883 9 25.5c0-1.005-.678-1.696-1.53-2.094l.405-.687.125-.25V21H4zm7 3v2h17v-2H11z"></path></svg>',
  752.             markdown: '1. ',
  753.             newline: true,
  754.             textDefault: 'item',
  755.         },
  756.         {
  757.             name: 'Unordered List',
  758.             icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" version="1.1" height="16" width="16"><path d="M 6 5 C 4.894531 5 4 5.894531 4 7 C 4 8.105469 4.894531 9 6 9 C 7.105469 9 8 8.105469 8 7 C 8 5.894531 7.105469 5 6 5 Z M 11 6 L 11 8 L 28 8 L 28 6 Z M 6 14 C 4.894531 14 4 14.894531 4 16 C 4 17.105469 4.894531 18 6 18 C 7.105469 18 8 17.105469 8 16 C 8 14.894531 7.105469 14 6 14 Z M 11 15 L 11 17 L 28 17 L 28 15 Z M 6 23 C 4.894531 23 4 23.894531 4 25 C 4 26.105469 4.894531 27 6 27 C 7.105469 27 8 26.105469 8 25 C 8 23.894531 7.105469 23 6 23 Z M 11 24 L 11 26 L 28 26 L 28 24 Z "></path></svg>',
  759.             markdown: '- ',
  760.             newline: true,
  761.             textDefault: 'item',
  762.         },
  763.         {
  764.             name: 'Code',
  765.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"><path d="M24 10.935v2.131l-8 3.947v-2.23l5.64-2.783-5.64-2.79v-2.223l8 3.948zm-16 3.848l-5.64-2.783 5.64-2.79v-2.223l-8 3.948v2.131l8 3.947v-2.23zm7.047-10.783h-2.078l-4.011 16h2.073l4.016-16z"></path></svg>',
  766.             markdown: '`',
  767.             wrap: true,
  768.             textDefault: 'code',
  769.         },
  770.         {
  771.             name: 'Link',
  772.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 24 24"><path d="M13.723 18.654l-3.61 3.609c-2.316 2.315-6.063 2.315-8.378 0-1.12-1.118-1.735-2.606-1.735-4.188 0-1.582.615-3.07 1.734-4.189l4.866-4.865c2.355-2.355 6.114-2.262 8.377 0 .453.453.81.973 1.089 1.527l-1.593 1.592c-.18-.613-.5-1.189-.964-1.652-1.448-1.448-3.93-1.51-5.439-.001l-.001.002-4.867 4.865c-1.5 1.499-1.5 3.941 0 5.44 1.517 1.517 3.958 1.488 5.442 0l2.425-2.424c.993.284 1.791.335 2.654.284zm.161-16.918l-3.574 3.576c.847-.05 1.655 0 2.653.283l2.393-2.389c1.498-1.502 3.94-1.5 5.44-.001 1.517 1.518 1.486 3.959 0 5.442l-4.831 4.831-.003.002c-1.438 1.437-3.886 1.552-5.439-.002-.473-.474-.785-1.042-.956-1.643l-.084.068-1.517 1.515c.28.556.635 1.075 1.088 1.528 2.245 2.245 6.004 2.374 8.378 0l4.832-4.831c2.314-2.316 2.316-6.062-.001-8.377-2.317-2.321-6.067-2.313-8.379-.002z"></path></svg>',
  773.             markdown: ['[', '](https://www.example.com)'],
  774.             textDefault: 'title',
  775.         },
  776.         {
  777.             name: 'Image',
  778.             icon: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="15" viewBox="0 0 512 512"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>',
  779.             markdown: ['![', '](image.jpg)'],
  780.             textDefault: 'alt text',
  781.         },
  782.  
  783.         /* Custom buttons */
  784.     ];
  785.  
  786.     function addStyle(css) {
  787.         const style = document.createElement('style');
  788.         style.id = 'markdown-editor'
  789.         style.innerHTML = css;
  790.         document.head.appendChild(style);
  791.     }
  792.  
  793.     function insertAtCursor (input, textToInsert, info) {
  794.         input.focus();
  795.         let sel1 = input.selectionStart;
  796.         let sel2 = input.selectionEnd;
  797.         const text = input.value;
  798.         const breakLine = (info.newline === true && sel1 !== 0) ? '\n' : '';
  799.         let sel = text.substring(sel1, sel2);
  800.         if (sel.length === 0 && info.textDefault) {
  801.             sel = info.textDefault;
  802.         }
  803.         document.execCommand('insertText', false, breakLine + textToInsert + sel);
  804.         sel1 = sel1 + breakLine.length + textToInsert.length;
  805.         sel2 = sel1 + sel.length;
  806.         input.setSelectionRange(sel1, sel2);
  807.     }
  808.    
  809.     function insertWrapAtCursor(input, tag1, tag2, info) {
  810.         input.focus();
  811.         let sel1 = input.selectionStart;
  812.         let sel2 = input.selectionEnd;
  813.         const text = input.value;
  814.         const breakLine = (info.newline === true && sel1 !== 0) ? '\n' : '';
  815.         let sel = text.substring(sel1, sel2);
  816.         if (sel.length === 0 && info.textDefault) {
  817.             sel = info.textDefault;
  818.         }
  819.         document.execCommand('insertText', false, breakLine + tag1 + sel + tag2);
  820.         sel1 = sel1 + breakLine.length + tag1.length;
  821.         sel2 = sel1 + sel.length;
  822.         input.setSelectionRange(sel1, sel2);
  823.     }
  824.  
  825.     function createButton(info) {
  826.         const button = document.createElement('button');
  827.         button.className = 'notes-custom';
  828.         button.title = info.name;
  829.         button.innerHTML = info.icon;
  830.         button.tabIndex = -1;
  831.         button.addEventListener('click', function (event) {
  832.             event.stopPropagation();
  833.             const noteEditor = document.querySelector('.cardview .NotesEditor-Editor');
  834.             if (noteEditor) {
  835.                 if (Array.isArray(info.markdown)) {
  836.                     insertWrapAtCursor(noteEditor, info.markdown[0], info.markdown[1], info);
  837.                 } else if (info.wrap && typeof info.markdown === 'string') {
  838.                     insertWrapAtCursor(noteEditor, info.markdown, info.markdown, info);
  839.                 } else if (typeof info.markdown === 'function') {
  840.                     insertAtCursor(noteEditor, info.markdown(), info);
  841.                 } else {
  842.                     insertAtCursor(noteEditor, info.markdown, info);
  843.                 }
  844.             }
  845.         });
  846.         return button;
  847.     }
  848.  
  849.     function markdownEditor() {
  850.         const addAttachmentsWrapper = document.querySelector('.NotesEditor > .toolbar:not([data-markdown-editor="true"])');
  851.          if (addAttachmentsWrapper) {
  852.             addAttachmentsWrapper.dataset.markdownEditor = true;
  853.             buttons.forEach(function (buttonInfo) {
  854.                 addAttachmentsWrapper.append(createButton(buttonInfo));
  855.             });
  856.         }
  857.     }
  858.  
  859.     addStyle([
  860.         '.NotesEditor > .toolbar { flex-flow: row wrap; display: -webkit-box; }',
  861.         '.NotesEditor > .toolbar .notes-custom { width: 28px; height: 28px; margin-right: 0; padding: 5px; border: 1px solid transparent; border-radius: var(--radius); background-color: transparent; background-image: linear-gradient(var(--colorBgLight), var(--colorBg)); }',
  862.         '.NotesEditor > .toolbar .notes-custom:hover { background-color: var(--colorBgDark); }',
  863.         '.NotesEditor > .toolbar .notes-custom svg { width: 16px; height: auto; fill: var(--colorFg); }',
  864.         '.NotesEditor > .toolbar .notes-custom:hover svg { fill: var(--colorHighlightBg); }',
  865.         '.NotesEditor > .toolbar .notes-toggle-md[disabled] ~ .notes-custom { opacity: 0.5; pointer-events: none; }',
  866.         '.NotesEditor-Toolbar button.active { background-color: var(--colorFgFadedMore); }',
  867.     ].join(''));
  868.    
  869.     const observeDOM = (function () {
  870.         return function (obj, callback) {
  871.             const obs = new MutationObserver(function (mutations, observer) {
  872.                 if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
  873.                     callback(mutations, observer);
  874.                 }
  875.             });
  876.             obs.observe(obj, {
  877.                 childList: true,
  878.                 subtree: true
  879.             });
  880.         };
  881.     })();
  882.  
  883.     observeDOM(document, function (mutations, observer) {
  884.         const panels = document.querySelector('#panels');
  885.         if (panels) {
  886.             observer.disconnect();
  887.             markdownEditor();
  888.             observeDOM(panels, function () {
  889.                 markdownEditor();
  890.             });
  891.         }
  892.     });
  893. })();
  894.  
  895. /*
  896.  * bookmark-panel-at-start
  897.  * Written by luetage
  898.  * GNU General Public License v3.0
  899.  */
  900. setTimeout(function wait() {
  901.     const book = document.querySelector('.panelbtn.mail');
  902.     if (book) {
  903.         if (!book.classList.contains('active')) book.click();
  904.     }
  905.     else setTimeout(wait, 300);
  906. }, 300)
  907.  
Advertisement
Add Comment
Please, Sign In to add comment