├── Add_New_Buttons_After_This_Button ├── README.md ├── addNewButtonsAfterThisButton.html ├── addNewButtonsAfterThisButton.js ├── icon.png └── icon.xcf ├── Attributes_Inspector ├── README.md ├── attrsInspector-en.png ├── attrsInspector-ru.png ├── attrsInspector.html ├── attrsInspector.js ├── icon.png └── test.html ├── Back_to_Close ├── README.md └── backToClose.js ├── Bookmarks_Folder ├── README.md ├── bookmarksFolder.html ├── bookmarksFolder.js ├── icon.png └── screenshots │ ├── bookmarks_menu-en.png │ ├── bookmarks_menu-ru.png │ ├── select_bookmark_folder-en.png │ └── select_bookmark_folder-ru.png ├── CB_Disable_Initialization ├── README.md ├── cbDisableInitialization.html ├── cbDisableInitialization.js ├── icon.png └── screenshots │ ├── disabled-en.png │ ├── disabled-ru.png │ ├── enabled-en.png │ ├── enabled-ru.png │ ├── initialization_code_of_disabled_button-en.png │ └── initialization_code_of_disabled_button-ru.png ├── CB_Editor_Toggle_on_Top ├── README.md ├── cbEditorToggleOnTop-en.png ├── cbEditorToggleOnTop-ru.png ├── cbEditorToggleOnTop.html ├── cbEditorToggleOnTop.js └── icons │ ├── icon.png │ ├── pin-disabled.png │ └── pin.png ├── CB_Orion_Editor ├── README.md ├── cbOrionEditor.html └── cbOrionEditor.js ├── CB_Source_Editor ├── README.md ├── cbSourceEditor.html ├── cbSourceEditor.js └── icon.png ├── Check_for_Addons_Updates ├── README.md ├── checkForAddonsUpdates.html ├── checkForAddonsUpdates.js ├── icon.png └── icon.xcf ├── Convert_E4X ├── README.md ├── convertE4X.html ├── convertE4X.js ├── convertE4X_launcher.js ├── icon.png ├── icon.xcf └── testcase.js ├── Cookies_Permissions ├── README.md ├── cookiesPermissions-en.png ├── cookiesPermissions-ru.png ├── cookiesPermissions.html ├── cookiesPermissions.js └── icons │ ├── cookies_merged.png │ ├── cookies_merged.xcf │ └── icon.png ├── Detach_Tab ├── README.md ├── detachTab.html ├── detachTab.js ├── icon.png └── icon.xcf ├── Edit_Custom_Button_in_Tab ├── README.md ├── editCustomButtonInTab.html ├── editCustomButtonInTab.js └── icon.png ├── Extensions_Developer_Tools ├── README.md ├── extDevTools-en.png ├── extDevTools-ru.png ├── extDevTools.html ├── extDevTools.js ├── extDevToolsMouseGesturesLauncher.js └── icon.png ├── Extensions_Installer ├── README.md ├── extensionsInstaller.html ├── extensionsInstaller.js ├── icon.png ├── icon.xcf └── make.bat ├── List_All_Tabs ├── README.md ├── icon.png ├── icon.xcf ├── listAllTabs.html └── listAllTabs.js ├── Merge_Custom_Buttons ├── README.md ├── icon.png ├── mergeCustomButtons.html ├── mergeCustomButtons.js └── screenshots │ ├── menu_with_merged_custom_buttons.png │ └── temporarily_split.png ├── Open_Window ├── README.md └── window.js ├── Pin_Tabs ├── README.md └── pinTabs.js ├── Plugins_Permissions ├── README.md ├── icons │ ├── icon-alt.png │ ├── icon.png │ ├── plugins_merged-alt.png │ ├── plugins_merged-alt.xcf │ ├── plugins_merged.png │ └── plugins_merged.xcf ├── pluginsPermissions-en.png ├── pluginsPermissions-ru.png ├── pluginsPermissions.html └── pluginsPermissions.js ├── Purge_Tabs_History ├── README.md ├── icon.png ├── purgeTabsHistory.html └── purgeTabsHistory.js ├── Quick_Filter_by_Recipient ├── README.md └── tbQuickFilterByRecipient.js ├── Quick_Filter_by_Sender ├── README.md └── tbQuickFilterBySender.js ├── README.md ├── Reload_Broken_Images ├── README.md ├── icon.png ├── icon.xcf ├── reloadBrokenImages.html └── reloadBrokenImages.js ├── Session_Bookmarks ├── README.md ├── icon.png ├── icon.xcf ├── screenshots │ ├── bookmark_context_menu-en.png │ ├── bookmark_context_menu-ru.png │ ├── bookmark_properties-en.png │ ├── bookmark_properties-ru.png │ ├── bookmarks-en.png │ ├── bookmarks-ru.png │ ├── button_context_menu-en.png │ └── button_context_menu-ru.png ├── sessionBookmarks.html └── sessionBookmarks.js ├── Show_Anchors ├── README.md ├── icon.png ├── icon.xcf └── showAnchors.html ├── Switch_Keyboard_Layout ├── README.md ├── icon.png ├── switchKeybLayout.html └── switchKeybLayout.js ├── Tabbar_Doubleclick ├── README.md └── tabbarDoubleclick.js ├── Title_Bar ├── README.md ├── icon.png ├── titleBar.html └── titleBar.js ├── Toggle_Find ├── README.md └── toggleFind.js ├── Toggle_Flash ├── README.md ├── icon.png ├── toggleFlash.html └── toggleFlash.js ├── Toggle_GIF_Animation ├── README.md ├── icon.png ├── icon.xcf ├── icon_enabled.png ├── toggleGifAnimation.html └── toggleGifAnimation.js ├── Toggle_Restartless_Add-ons ├── README.md ├── icon.png ├── toggleRestartlessAddons-en.png ├── toggleRestartlessAddons-ru.png ├── toggleRestartlessAddons.html └── toggleRestartlessAddons.js ├── Toolbar_Flexible_Space ├── README.md ├── toolbarFlexibleSpace.html └── toolbarFlexibleSpace.js ├── Toolbar_Separator ├── README.md ├── toolbarSeparator.html └── toolbarSeparator.js ├── Toolbar_Space ├── README.md ├── toolbarSpace.html └── toolbarSpace.js ├── Undo_Close_Tabs ├── README.md ├── icons │ ├── icon.png │ ├── merged.png │ └── merged.xcf ├── undoCloseTabs.html └── undoCloseTabs.js ├── code_snippets ├── README.md ├── autoOpenCloseMenu.js ├── customizableUI.js ├── menuWithDelayedInitialization.html ├── menuWithDelayedInitialization.js ├── mergeInitialization.js ├── multilinePrompt.js ├── oneTimeCommand.js ├── prefNS.js └── prefs.js └── tests ├── README.md └── dndTest.js /Add_New_Buttons_After_This_Button/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Add_New_Buttons_After_This_Button/icon.png) Add New Buttons After This Button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
New custom buttons will be automatically placed after this button (button is disabled by default, click to enable) -------------------------------------------------------------------------------- /Add_New_Buttons_After_This_Button/addNewButtonsAfterThisButton.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Add New Buttons After This Button [0.1.2.1 - 2019-12-30] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Add_New_Buttons_After_This_Button/addNewButtonsAfterThisButton.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Add_New_Buttons_After_This_Button 2 | 3 | // Add New Buttons After This Button button for Custom Buttons 4 | // (code for "initialization" section) 5 | // Note: button is disabled by default, click to enable 6 | 7 | // (c) Infocatcher 2012, 2014, 2018-2019 8 | // version 0.1.2.1 - 2019-12-30 9 | 10 | var cbs = custombuttons.cbService; 11 | var windowId = cbs.getWindowId(document.documentURI); 12 | var cbInstall = cbs.getNotificationPrefix(windowId) + "installButton"; 13 | 14 | this.toggleEnabled = function() { 15 | this.checked = !this.checked; 16 | if("persist" in document) 17 | document.persist(this.id, "checked"); 18 | else // Firefox 63+ 19 | Services.xulStore.persist(this, "checked"); 20 | }; 21 | this.setAttribute("oncommand", "this.toggleEnabled();"); 22 | 23 | if(!("persist" in document) && parseFloat(Services.appinfo.platformVersion) >= 71) { 24 | var id = this.id; 25 | var attr = "checked"; 26 | if(this.hasAttribute(attr)) 27 | return; 28 | var xs = Services.xulStore; 29 | var url = location.href; 30 | if(xs.hasValue(url, id, attr)) 31 | this.setAttribute(attr, xs.getValue(url, id, attr)); 32 | } 33 | 34 | var observer = { 35 | button: this, 36 | observe: function(button, topic, data) { 37 | if(topic != cbInstall) 38 | return; 39 | if(!this.button.checked) 40 | return; 41 | var toolbar = this.button.parentNode; 42 | toolbar.insertBefore( 43 | custombuttons.cbCloneNode(button), // Prevent "The operation is insecure" in Firefox 71+ 44 | this.button.nextSibling 45 | ); 46 | custombuttons.persistCurrentSets(toolbar.id, this.button.id, button.id || button.getAttribute("id")); 47 | } 48 | }; 49 | var os = Components.classes["@mozilla.org/observer-service;1"] 50 | .getService (Components.interfaces.nsIObserverService); 51 | os.addObserver(observer, cbInstall, false); 52 | var hasObserver = true; 53 | 54 | this.onDestroy = function(reason) { 55 | if(hasObserver) { 56 | hasObserver = false; 57 | os.removeObserver(observer, cbInstall); 58 | } 59 | if(reason == "delete" && this.checked) 60 | this.toggleEnabled(); 61 | }; -------------------------------------------------------------------------------- /Add_New_Buttons_After_This_Button/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Add_New_Buttons_After_This_Button/icon.png -------------------------------------------------------------------------------- /Add_New_Buttons_After_This_Button/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Add_New_Buttons_After_This_Button/icon.xcf -------------------------------------------------------------------------------- /Attributes_Inspector/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Attributes_Inspector/icon.png) Attributes Inspector button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Shows tooltip with with all attributes and allow open [DOM Inspector](https://addons.mozilla.org/addon/dom-inspector-6622/) for current node 3 | 4 | ##### Usage: 5 | * Use middle-click or Ctrl + left-click to inspect node in DOM Inspector 6 |
(additionally hold Shift key to enable pupup locker) 7 | * Hold Shift key to show and don't hide tooltips and popups 8 | 9 | ##### Hotkeys: 10 | * Escape – cancel or disable popup locker 11 | * Ctrl+Up, Ctrl+Down – navigate to parent/child node 12 | * Ctrl+Left, Ctrl+Right – navigate to previous/next sibling node (since v. 0.6.1pre) 13 | * Ctrl+Shift+C – copy tooltip's contents 14 | * Ctrl+W – inspect node's window object in DOM Inspector (since v. 0.6.3pre) 15 | 16 | ##### Screenshot: 17 | Tooltip with all attributes -------------------------------------------------------------------------------- /Attributes_Inspector/attrsInspector-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Attributes_Inspector/attrsInspector-en.png -------------------------------------------------------------------------------- /Attributes_Inspector/attrsInspector-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Attributes_Inspector/attrsInspector-ru.png -------------------------------------------------------------------------------- /Attributes_Inspector/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Attributes_Inspector/icon.png -------------------------------------------------------------------------------- /Attributes_Inspector/test.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Test 5 | 6 | 19 | 20 | 21 | Toggle class 22 |
Toggle class + remove 23 |
Modify class 24 |
Toggle fast updates 25 |
Text nodes, nodes
26 | 27 | -------------------------------------------------------------------------------- /Back_to_Close/README.md: -------------------------------------------------------------------------------- 1 | **Back to Close** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Use “Back” command to close tab without “back history” -------------------------------------------------------------------------------- /Bookmarks_Folder/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Bookmarks_Folder/icon.png) Bookmarks Folder button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Show contents of any bookmarks folder in drop-down menu. 3 |
Use middle-click (or left-click with any modifier) on button to change folder. 4 |
In Firefox 59+: middle-click (or left-click with any modifier) on highlighted bookmarks folder in Firefox itself to select it. 5 | 6 | ##### Screenshots: 7 | Select bookmarks folder  Bookmarks menu -------------------------------------------------------------------------------- /Bookmarks_Folder/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Bookmarks_Folder/icon.png -------------------------------------------------------------------------------- /Bookmarks_Folder/screenshots/bookmarks_menu-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Bookmarks_Folder/screenshots/bookmarks_menu-en.png -------------------------------------------------------------------------------- /Bookmarks_Folder/screenshots/bookmarks_menu-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Bookmarks_Folder/screenshots/bookmarks_menu-ru.png -------------------------------------------------------------------------------- /Bookmarks_Folder/screenshots/select_bookmark_folder-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Bookmarks_Folder/screenshots/select_bookmark_folder-en.png -------------------------------------------------------------------------------- /Bookmarks_Folder/screenshots/select_bookmark_folder-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Bookmarks_Folder/screenshots/select_bookmark_folder-ru.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Disable_Initialization/icon.png) Custom Buttons: Disable Initialization button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Adds “Enable initialization” checkbox to custom button's context menu (for test purposes) 3 | 4 | ##### Screenshots: 5 | Enabled Disabled 6 |
7 |
Initialization code of disabled button -------------------------------------------------------------------------------- /CB_Disable_Initialization/cbDisableInitialization.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Disable_Initialization 2 | 3 | // Custom Buttons: Disable Initialization button for Custom Buttons 4 | // (code for "initialization" section) 5 | 6 | // (c) Infocatcher 2012-2013, 2016 7 | // version 0.1.1 - 2016-02-02 8 | 9 | // Adds "Enable initialization" checkbox to custom button's context menu. 10 | // Only for test purposes! 11 | // "Disabled" mean only "if(true) return;" before initealization code. 12 | 13 | // Note: button itself aren't needed, this is just way to execute code on window startup. 14 | // So you can place it on hidden toolbar. 15 | 16 | var toggleEnabledLabel = (function() { 17 | var locale = (function() { 18 | if("Services" in window && "locale" in Services) { 19 | var locales = Services.locale.requestedLocales // Firefox 64+ 20 | || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales(); 21 | if(locales) 22 | return locales[0]; 23 | } 24 | var prefs = "Services" in window && Services.prefs 25 | || Components.classes["@mozilla.org/preferences-service;1"] 26 | .getService(Components.interfaces.nsIPrefBranch); 27 | function pref(name, type) { 28 | return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined; 29 | } 30 | if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390 31 | var locale = pref("general.useragent.locale", "Char"); 32 | if(locale && locale.substr(0, 9) != "chrome://") 33 | return locale; 34 | } 35 | return Components.classes["@mozilla.org/chrome/chrome-registry;1"] 36 | .getService(Components.interfaces.nsIXULChromeRegistry) 37 | .getSelectedLocale("global"); 38 | })().match(/^[a-z]*/)[0]; 39 | if(locale == "ru") 40 | return "Включить инициализацию"; 41 | return "Enable initialization"; 42 | })(); 43 | 44 | const deleteId = "custombuttons-contextpopup-remove"; 45 | const toggleEnabledId = "custombuttons-contextpopup-toggleEnabled"; 46 | var toggleEnabled = document.getElementById(toggleEnabledId); 47 | if(toggleEnabled) 48 | toggleEnabled.parentNode.removeChild(toggleEnabled); 49 | var deleteItem = document.getElementById(deleteId); 50 | toggleEnabled = deleteItem.cloneNode(true); 51 | toggleEnabled.id = toggleEnabledId; 52 | toggleEnabled.setAttribute("cb_id", toggleEnabledId); 53 | toggleEnabled.setAttribute("type", "checkbox"); 54 | toggleEnabled.setAttribute("label", toggleEnabledLabel); 55 | toggleEnabled.setAttribute("oncommand", "toggleCustomButtonEnabled();"); 56 | //toggleEnabled.removeAttribute("observes"); // For Firefox 3.6 and older 57 | deleteItem.parentNode.insertBefore(toggleEnabled, deleteItem); 58 | 59 | Array.prototype.filter.call( // Process already cloned menu items 60 | document.getElementsByAttribute("observes", deleteItem.getAttribute("observes")), 61 | function(mi) { 62 | return mi != deleteItem && (mi.id || "").substr(0, deleteId.length) == deleteId; 63 | } 64 | ).forEach(function(deleteItem, i) { 65 | var clone = toggleEnabled.cloneNode(true); 66 | clone.id += "-cloned-" + i; 67 | deleteItem.parentNode.insertBefore(clone, deleteItem); 68 | }); 69 | 70 | // Process #custombuttons-contextpopup-sub 71 | const deleteIdSub = deleteId + "-sub"; 72 | var deleteItemSub = document.getElementById(deleteIdSub); 73 | if(deleteItemSub) { 74 | var clone = toggleEnabled.cloneNode(true); 75 | if(deleteItemSub.hasAttribute("observes")) 76 | clone.setAttribute("observes", deleteItemSub.getAttribute("observes")); 77 | else 78 | clone.removeAttribute("observes"); 79 | clone.id += "-sub"; 80 | deleteItemSub.parentNode.insertBefore(clone, deleteItemSub); 81 | } 82 | 83 | addEventListener("popupshowing", function(e) { 84 | var popup = e.target; 85 | if(popup.localName != "menupopup" || (popup.id || "").substr(0, 14) != "custombuttons-") 86 | return; 87 | var toggleEnabled = popup.getElementsByAttribute("cb_id", toggleEnabledId)[0]; 88 | if(!toggleEnabled) 89 | return; 90 | var btn = getBtn(); 91 | var initCode = btn && btn.cbInitCode || ""; 92 | if(/^\s*(?:if\s*\(true\)\s*)?return(?:;|\s*\n)/.test(initCode)) 93 | toggleEnabled.removeAttribute("checked"); 94 | else 95 | toggleEnabled.setAttribute("checked", "true"); 96 | if(/^\s*(?:\/\*Initialization Code\*\/\s*)?$/.test(initCode)) // Nothing to do :) 97 | toggleEnabled.setAttribute("disabled", "true"); 98 | else 99 | toggleEnabled.removeAttribute("disabled"); 100 | }, false); 101 | 102 | window.toggleCustomButtonEnabled = function() { // Should be global to work in cloned menus 103 | var btn = getBtn(); 104 | if(!btn) 105 | return; 106 | 107 | // Trick to prevent "unreachable code after return statement" warning 108 | const disablePrefix = "if(true) return; // Disabled by Disable Initialization button\n\n"; 109 | var initCode = btn.cbInitCode; 110 | //if(initCode.substr(0, disablePrefix.length) == disablePrefix) 111 | // initCode = initCode.substr(disablePrefix.length); 112 | if(/^\s*(?:if\s*\(true\)\s*)?return;?(?:\s*\/\/[^\n\r]*)?\n+/.test(initCode)) 113 | initCode = RegExp.rightContext; 114 | else 115 | initCode = disablePrefix + initCode; 116 | 117 | //btn.destroy("update"); 118 | //btn.cbInitCode = initCode; 119 | //btn.setAttribute("cb-init", initCode); 120 | 121 | var link = custombuttons.makeButtonLink("edit", btn.id); 122 | var cbService = custombuttons.cbService; 123 | var param = cbService.getButtonParameters(link); 124 | param = param.wrappedJSObject || param; 125 | param.initCode = initCode; 126 | cbService.installButton(param); 127 | 128 | //btn.init(); 129 | }; 130 | function getBtn() { 131 | var btn = custombuttons.popupNode; 132 | if(!btn || (btn.id || "").substr(0, 20) != "custombuttons-button") 133 | return null; 134 | return btn; 135 | } 136 | 137 | var style = '\ 138 | @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");\n\ 139 | toolbarbutton[id^="custombuttons-button"][cb-init^="return;"]:not([cb-edit-state]),\n\ 140 | toolbarbutton[id^="custombuttons-button"][cb-init^="if(true) return;"]:not([cb-edit-state]) {\n\ 141 | outline: 1px dotted !important;\n\ 142 | outline-offset: -1px !important;\n\ 143 | }'; 144 | var styleNode = document.insertBefore( 145 | document.createProcessingInstruction( 146 | "xml-stylesheet", 147 | 'href="' + "data:text/css," 148 | + encodeURIComponent(style) + '" type="text/css"' 149 | ), 150 | document.firstChild 151 | ); 152 | 153 | function destructor(reason) { 154 | if(reason == "update" || reason == "delete") { 155 | styleNode.parentNode.removeChild(styleNode); 156 | Array.prototype.slice.call(document.getElementsByAttribute("cb_id", toggleEnabledId)).forEach(function(btn) { 157 | btn.parentNode.removeChild(btn); 158 | }); 159 | delete window.toggleCustomButtonEnabled; 160 | } 161 | } 162 | if( 163 | typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+ 164 | && addDestructor != ("addDestructor" in window && window.addDestructor) 165 | ) 166 | addDestructor(destructor, this); 167 | else 168 | this.onDestroy = destructor; -------------------------------------------------------------------------------- /CB_Disable_Initialization/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/icon.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/disabled-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/disabled-en.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/disabled-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/disabled-ru.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/enabled-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/enabled-en.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/enabled-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/enabled-ru.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/initialization_code_of_disabled_button-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/initialization_code_of_disabled_button-en.png -------------------------------------------------------------------------------- /CB_Disable_Initialization/screenshots/initialization_code_of_disabled_button-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Disable_Initialization/screenshots/initialization_code_of_disabled_button-ru.png -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Editor_Toggle_on_Top/icons/icon.png) Custom Buttons Editor: Toggle on Top button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Add “On top” button to built-in custom button's editor (doesn't work on some platforms!) 3 | 4 | ##### Screenshot: 5 | Custom buttons editor with “On top” button -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/cbEditorToggleOnTop-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Editor_Toggle_on_Top/cbEditorToggleOnTop-en.png -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/cbEditorToggleOnTop-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Editor_Toggle_on_Top/cbEditorToggleOnTop-ru.png -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Editor_Toggle_on_Top/icons/icon.png -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/icons/pin-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Editor_Toggle_on_Top/icons/pin-disabled.png -------------------------------------------------------------------------------- /CB_Editor_Toggle_on_Top/icons/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Editor_Toggle_on_Top/icons/pin.png -------------------------------------------------------------------------------- /CB_Orion_Editor/README.md: -------------------------------------------------------------------------------- 1 | Orion Editor was renamed to Source Editor. -------------------------------------------------------------------------------- /CB_Orion_Editor/cbOrionEditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Orion Editor: moved… 4 | 5 | Orion Editor was renamed to Source Editor. 6 | -------------------------------------------------------------------------------- /CB_Orion_Editor/cbOrionEditor.js: -------------------------------------------------------------------------------- 1 | // Orion Editor was renamed to Source Editor: 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Source_Editor -------------------------------------------------------------------------------- /CB_Source_Editor/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Source_Editor/icon.png) Custom Buttons: Source Editor button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
(Formerly Orion Editor) 3 |
Allows to highlight code in Custom Buttons editor using built-in [source editor component](https://developer.mozilla.org/en-US/docs/Tools/Editor). 4 |
Beware: many things doesn't work and strange bugs may happens! -------------------------------------------------------------------------------- /CB_Source_Editor/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/CB_Source_Editor/icon.png -------------------------------------------------------------------------------- /Check_for_Addons_Updates/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Check_for_Addons_Updates/icon.png) Check for Addons Updates button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Button just open hidden tab with about:addons and trigger built-in “Check for Updates” function. 3 |
And show tab, if found updates. -------------------------------------------------------------------------------- /Check_for_Addons_Updates/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Check_for_Addons_Updates/icon.png -------------------------------------------------------------------------------- /Check_for_Addons_Updates/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Check_for_Addons_Updates/icon.xcf -------------------------------------------------------------------------------- /Convert_E4X/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Convert_E4X/icon.png) Convert E4X button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Tries convert [deprecated](http://custombuttons.sf.net/forum/viewtopic.php?f=2&t=365) [E4X](https://developer.mozilla.org/en-US/docs/E4X) to string literals. 3 |
Click on button and then click on another button with E4X in code (or click on opened page with *.js file). -------------------------------------------------------------------------------- /Convert_E4X/convertE4X.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Convert_E4X 2 | // https://forum.mozilla-russia.org/viewtopic.php?id=56442 3 | // http://custombuttons.sf.net/forum/viewtopic.php?f=2&t=365 4 | 5 | // Convert E4X button for Custom Buttons 6 | // Code for "code" section 7 | 8 | // (c) Infocatcher 2012-2013, 2016-2017 9 | // version 0.1.0b2 - 2017-03-15 10 | 11 | // Tries convert deprecated E4X to string literals. 12 | // Click on button and then click on another button with E4X in code (or click on opened page with *.js file). 13 | 14 | var btn = this; 15 | btn.checked = true; 16 | addEventListener("click", function getButton(e) { 17 | var trg = e.target; 18 | 19 | var codes; 20 | if(trg.localName == "toolbarbutton" && /^custombuttons-button\d+$/.test(trg.id)) 21 | codes = [trg.cbCommand, trg.cbInitCode]; 22 | else if( 23 | trg.ownerDocument.defaultView == content 24 | && /^(?:application\/(?:x-)?javascript|text\/plain)$/.test(trg.ownerDocument.contentType) 25 | ) 26 | codes = [trg.ownerDocument.body.textContent]; 27 | 28 | if(!codes) 29 | return; 30 | removeEventListener(e.type, getButton, true); 31 | try { 32 | e.preventDefault(); 33 | e.stopPropagation(); 34 | } 35 | catch(e) { // TypeError: 'preventDefault' called on an object that does not implement interface Event 36 | Components.utils.reportError(e); 37 | } 38 | btn.checked = false; 39 | if(trg != btn) codes.forEach(function(code) { 40 | code = convertE4XCode(code); 41 | if(!code) // Nothing to convert 42 | return; 43 | var uri = "data:text/plain;charset=utf-8," + encodeURIComponent(code); 44 | gBrowser.selectedTab = gBrowser.addTab(uri, makeURI("about:blank")); 45 | }); 46 | }, true); 47 | 48 | function convertE4XCode(s) { 49 | var _debug = false; 50 | 51 | convertE4XCode = convertCode; 52 | return convertCode(s); 53 | 54 | function _log(s) { 55 | _debug && LOG(s); 56 | }; 57 | function convertCode(s) { 58 | if(!s || s == "/*CODE*/" || s == "/*Initialization Code*/") 59 | return ""; 60 | var convertedNote = "/* Converted with https://github.com/Infocatcher/Custom_Buttons/tree/master/Convert_E4X */\n"; 61 | if(s.indexOf(convertedNote) != -1) 62 | return ""; 63 | var orig = s; 64 | 65 | // Replace old parsers 66 | // Note: declarations of old perser functions aren't removed! 67 | s = s.replace(/(?:[\w$]+\s*\.\s*)*(?:makeXML|parseFromXML)(\s*)\(/g, "e4xConv_parseXULFromString$1("); 68 | 69 | // Convert node.@attr = ... 70 | s = s.replace(/(\.\s*)@([\w$]+)\s*=\s*([^;]+)/g, '$1setAttribute("$2", $3)'); 71 | 72 | // Other node.@attr usage 73 | s = s.replace(/(\.\s*)@([\w$]+)/g, '$1getAttribute("$2")'); 74 | 75 | s = s 76 | // <> ... 77 | .replace(/<>([\s\S]+?)<\/>(?:\s*\.\s*toXMLString\s*\(\))?/g, function(s, e4x) { 78 | if(e4x.substr(0, 9) == " ... \n" + s); 81 | return convertE4X(e4x); 82 | }) 83 | // 84 | .replace(/(?:<>)?(?:<\/>)?(?:\s*\.\s*toString\s*\(\))?/g, function(s, cdata) { 85 | if(inE4X(RegExp.leftContext) || alreadyConverted(cdata)) 86 | return s; 87 | _log("\n" + s); 88 | return convertCDATA(cdata); 89 | }) 90 | // 91 | .replace(/<\w+\s([^>]+?)\/>(?:\s*\.\s*toXMLString\s*\(\))?/g, function(s) { 92 | var lc = RegExp.leftContext; 93 | var rc = RegExp.rightContext; 94 | if(inE4X(lc) || inString(lc) || alreadyConverted(s) || /^(?:\\n)?\\[\n\r]/.test(rc)) 95 | return s; 96 | _log("\n" + s); 97 | return convertE4X(s); 98 | }) 99 | // ... 100 | //.replace(/<(\w+)(?:[^>]*[^>\/])?>([\s\S]*?)<\/\1>(?:\s*\.\s*toXMLString\s*\(\))?/g, function(s) { 101 | .replace(getTagsPattern(), function(s) { 102 | var lc = RegExp.leftContext; 103 | if(inE4X(lc) || inString(lc) || alreadyConverted(s)) 104 | return s; 105 | _log(" ... \n" + s); 106 | return convertE4X(s); 107 | }) 108 | // All .toXMLString() calls are useless 109 | // Example: 110 | // window.openDialog("data:application/vnd.mozilla.xul+xml," + encodeURIComponent(dialog.toXMLString()), ... 111 | .replace(/\s*\.\s*toXMLString\s*\(\)/g, ""); 112 | 113 | if(s != orig) { 114 | var codeHeader = /^(?:\/\*(?:CODE|Initialization Code)\*\/\n?)?/; 115 | if(/\WXML\s*\.\s*\w/.test(orig)) 116 | s = s.replace(codeHeader, "$&var XML = window.XML || {};\n\n"); 117 | s = s.replace(codeHeader, "$&" + convertedNote); 118 | var addFuncs = ""; 119 | if(s.indexOf("e4xConv_parseXULFromString") != -1) 120 | addFuncs += "\n" + trimFunc(e4xConv_parseXULFromString); 121 | if(s.indexOf("e4xConv_encodeHTML") != -1) 122 | addFuncs += "\n" + trimFunc(e4xConv_encodeHTML); 123 | if(addFuncs) 124 | s += "\n" + addFuncs; 125 | return s; 126 | } 127 | return ""; 128 | } 129 | function getTagsPattern() { 130 | // I'm too lazy to write a real tags parser, sorry... 131 | const recursion = 7; 132 | const tagStart = "<(\\w+)(?:[^>]*[^>\\/])?>"; 133 | 134 | function getSub(level) { 135 | if(++level > recursion) 136 | return "[\\s\\S]*?"; 137 | return "(?:" 138 | + "<\\w+[^>]*\\/>" 139 | + "|" + tagStart + getSub(level) + "<\\/\\" + level + ">" 140 | + "|[\\s\\S]" 141 | + ")*?"; 142 | } 143 | var pattern = tagStart 144 | + getSub(1) 145 | + "<\\/\\1>" 146 | + "(?:\\s*\\.\\s*toXMLString\\s*\\(\\))?"; 147 | 148 | var re = new RegExp(pattern, "g"); 149 | getTagsPattern = function() { 150 | return re; 151 | }; 152 | return re; 153 | } 154 | function convertCDATA(s) { 155 | return "'" + escapeString(s.replace(/['\\]/g, "\\$&")) + "'"; 156 | } 157 | function inE4X(prev) { 158 | return />\s*(?:(?:\\n)?\\[\n\r]\s*)?$/.test(prev); 159 | } 160 | function inString(prev) { 161 | // Very basic check to not convert something like 162 | // node.innerHTML = '
...
'; 163 | return /['"]$/.test(prev); 164 | } 165 | function alreadyConverted(s) { 166 | return /['">][ \t]*(?:\\n)?\\[\n\r]/.test(s); 167 | } 168 | function convertE4X(s) { 169 | var cdates = []; 170 | var rndCd = rnd(); 171 | // Leave CDATA as is 172 | s = s.replace(//g, function(s) { 173 | //cdates.push("\\x3" + s.substr(1)); // Very simple way to break CDATA 174 | cdates.push(s); 175 | return rndCd; 176 | }); 177 | 178 | // Extract codes 179 | var codes = []; 180 | var rndExpr = rnd(); 181 | // { expressions } 182 | s = s.replace(/(=\s*)?\{([^\}]*)\}/g, function(s, eq, code, offset, str) { 183 | if( 184 | !eq 185 | && /\s[-:\w]+\s*=\s*(?:"[^"]*|'[^']*)$/.test(str.substr(0, offset)) // foo="something{ 186 | && /^(?:[^"]*"|[^']*')(?:\s|\/?>)/.test(str.substr(offset)) // something" 187 | ) 188 | return s; // Looks like we're inside attribute, leave as is 189 | code = "e4xConv_encodeHTML(" + code + (eq ? ", true" : "") + ")"; 190 | var q = eq ? '"' : ""; 191 | code = q + "' + " + code + " + '" + q; 192 | codes.push(code); 193 | return (eq || "") + rndExpr; 194 | }); 195 | 196 | // Restore CDATA 197 | var i = 0; 198 | s = s.replace(new RegExp(rndCd, "g"), function(s) { 199 | return cdates[i++]; 200 | }); 201 | 202 | s = escapeString(s); 203 | 204 | // Restore codes 205 | var i = 0; 206 | s = s.replace(new RegExp(rndExpr, "g"), function(s) { 207 | return codes[i++]; 208 | }); 209 | return "'" + s + "'"; 210 | } 211 | function escapeString(s) { 212 | return s 213 | .replace(/['\\]/g, "\\$&") 214 | .replace(/$/mg, "\\n\\") 215 | .replace(/^\\n(\\[\n\r])/, "$1") 216 | .slice(0, -3); 217 | } 218 | function trimFunc(fn) { 219 | var fnCode = "" + fn; 220 | var spaces = /([ \t]+)\}$/.test(fnCode) && RegExp.$1; 221 | if(!spaces) 222 | return fnCode; 223 | return fnCode.replace(new RegExp("^" + spaces, "mg"), ""); 224 | } 225 | function rnd() { 226 | return Date.now() 227 | + Math.random().toFixed(14).substr(2) 228 | + Math.random().toFixed(14).substr(2); 229 | } 230 | 231 | function e4xConv_parseXULFromString(xul) { 232 | xul = xul.replace(/>\s+<"); 233 | try { 234 | return new DOMParser().parseFromString(xul, "application/xml").documentElement; 235 | } 236 | catch(e) { 237 | // See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720 238 | // + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243 239 | var dummy = document.createElement("dummy"); 240 | dummy.innerHTML = xul.trimLeft(); 241 | return dummy.firstChild; 242 | } 243 | } 244 | function e4xConv_encodeHTML(s, isAttr) { 245 | s = String(s) 246 | .replace(/&/g, "&") 247 | .replace(//g, ">") 249 | .replace(/"/g, """); 250 | if(isAttr) { 251 | s = s 252 | .replace(/\t/g, " ") 253 | .replace(/\n/g, " ") 254 | .replace(/\r/g, " "); 255 | } 256 | return s; 257 | } 258 | } -------------------------------------------------------------------------------- /Convert_E4X/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Convert_E4X/icon.png -------------------------------------------------------------------------------- /Convert_E4X/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Convert_E4X/icon.xcf -------------------------------------------------------------------------------- /Convert_E4X/testcase.js: -------------------------------------------------------------------------------- 1 | /*Initialization Code*/ 2 | 3 | // Testcase for Convert E4X button 4 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Convert_E4X 5 | // Note: this isn't a real code... just looks like 6 | 7 | var x = "E4X"; 8 | var y = "y"; 9 | var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 10 | XML.prettyPrinting = false; 11 | var xml = 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ; 24 | this.appendChild(cbu.makeXML(xml)); 25 | 26 | var xml = 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ; 46 | this.appendChild(cbu.makeXML(xml)); 47 | 48 | var xml = 49 | 50 | 51 | ; 52 | this.appendChild(cbu.makeXML(xml)); 53 | 54 | var xml = ; 55 | this.appendChild(cbu.makeXML(xml)); 56 | 57 | var xml = ; 58 | this.appendChild(cbu.makeXML(xml)); 59 | 60 | var box = "hbox"; 61 | var ipi = XML.ignoreProcessingInstructions; 62 | XML.ignoreProcessingInstructions = false; 63 | var dialog = <> 64 | 65 | 66 | <{box}> 67 | 71 | .toXMLString(); 72 | XML.ignoreProcessingInstructions = ipi; 73 | window.openDialog( 74 | "data:application/vnd.mozilla.xul+xml," + encodeURIComponent(dialog), 75 | "_blank", 76 | "chrome,all,resizable,centerscreen" 77 | ); -------------------------------------------------------------------------------- /Cookies_Permissions/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Cookies_Permissions/icons/icon.png) Cookies Permissions button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Menage cookies permissions: block, allow for session or allow. 3 |
Also shows permissions for current site and has some cookies-related features. 4 | 5 | ##### Screenshot: 6 | Button's context menu -------------------------------------------------------------------------------- /Cookies_Permissions/cookiesPermissions-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Cookies_Permissions/cookiesPermissions-en.png -------------------------------------------------------------------------------- /Cookies_Permissions/cookiesPermissions-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Cookies_Permissions/cookiesPermissions-ru.png -------------------------------------------------------------------------------- /Cookies_Permissions/icons/cookies_merged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Cookies_Permissions/icons/cookies_merged.png -------------------------------------------------------------------------------- /Cookies_Permissions/icons/cookies_merged.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Cookies_Permissions/icons/cookies_merged.xcf -------------------------------------------------------------------------------- /Cookies_Permissions/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Cookies_Permissions/icons/icon.png -------------------------------------------------------------------------------- /Detach_Tab/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Detach_Tab/icon.png) Detach Tab button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Detach current tab to new “light weight” window without toolbars and attach back, if button pressed second time or window was closed -------------------------------------------------------------------------------- /Detach_Tab/detachTab.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Detach Tab [0.2.2 - 2017-07-04] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Detach_Tab/detachTab.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/detachTab.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Detach_Tab 3 | 4 | // Detach Tab button for Custom Buttons 5 | // (code for "code" section) 6 | 7 | // (c) Infocatcher 2012, 2016-2017 8 | // version 0.2.2 - 2017-07-04 9 | 10 | var forceHideTabBar = false; 11 | 12 | const ns = "_cbDetachTab_"; 13 | var btn = this; 14 | if(ns + "detachedWindow" in btn) 15 | attachTab(); 16 | else 17 | detachTab(); 18 | 19 | function detachTab() { 20 | btn.checked = true; 21 | var selectedTab = gBrowser.selectedTab; 22 | btn[ns + "tabPos"] = "_tPos" in selectedTab 23 | ? selectedTab._tPos 24 | : Array.prototype.indexOf.call(gBrowser.tabs || gBrowser.tabContainer.childNodes, selectedTab); 25 | if("TreeStyleTabService" in window) 26 | btn[ns + "parentTab"] = TreeStyleTabService.getParentTab(selectedTab); 27 | // See replaceTabWithWindow() in chrome://browser/content/tabbrowser.xml 28 | var opts = "chrome,dialog=no,all"; 29 | //var opts = "chrome,dialog=0,resizable=1,location=0"; 30 | var browserURL = "getBrowserURL" in window 31 | ? getBrowserURL() 32 | : window.AppConstants && AppConstants.BROWSER_CHROME_URL; // Firefox 63+ 33 | var w = btn[ns + "detachedWindow"] = window.openDialog(browserURL, "_blank", opts, selectedTab); 34 | if(forceHideTabBar) { 35 | var autoHide = cbu.getPrefs("browser.tabs.autoHide"); 36 | if(!autoHide) 37 | cbu.setPrefs("browser.tabs.autoHide", true); 38 | } 39 | var initDetachedWindow = function init(e) { 40 | w.removeEventListener(e.type, init, false); 41 | w.addEventListener("unload", destroyDetachedWindow, false); 42 | compactWindow(w); 43 | }; 44 | var destroyDetachedWindow = function destroy(e, parentDestroy) { 45 | w.removeEventListener(e.type, destroy, false); 46 | window.removeEventListener("unload", destroyParentWindow, false); 47 | if(!parentDestroy) 48 | _attachTab(); 49 | if(forceHideTabBar && !autoHide) 50 | cbu.setPrefs("browser.tabs.autoHide", false); 51 | }; 52 | var destroyParentWindow = function destroy(e) { 53 | w.removeEventListener("DOMContentLoaded", initDetachedWindow, false); 54 | destroyDetachedWindow(e, true); 55 | }; 56 | w.addEventListener("DOMContentLoaded", initDetachedWindow, false); 57 | window.addEventListener("unload", destroyParentWindow, false); 58 | } 59 | function attachTab() { 60 | if(!btn[ns + "detachedWindow"].closed) 61 | btn[ns + "detachedWindow"].close(); 62 | else 63 | delete btn[ns + "detachedWindow"]; 64 | } 65 | function _attachTab() { 66 | var tab = btn[ns + "detachedWindow"].gBrowser.selectedTab; 67 | var newTab = gBrowser.selectedTab = gBrowser.addTab(); 68 | gBrowser.moveTabTo(newTab, btn[ns + "tabPos"]); 69 | if(ns + "parentTab" in btn) { 70 | let parentTab = btn[ns + "parentTab"]; 71 | if(parentTab && parentTab.parentNode) 72 | gBrowser.treeStyleTab.attachTabTo(newTab, parentTab); 73 | } 74 | 75 | // Strange bug... 76 | // Temporary override some preferences 77 | var warnOnClose = cbu.getPrefs("browser.tabs.warnOnClose"); 78 | if(warnOnClose) 79 | cbu.setPrefs("browser.tabs.warnOnClose", false); 80 | var warnOnQuit = cbu.getPrefs("browser.warnOnQuit"); 81 | if(warnOnQuit) 82 | cbu.setPrefs("browser.warnOnQuit", false); 83 | 84 | try { 85 | gBrowser.swapBrowsersAndCloseOther(newTab, tab); 86 | } 87 | catch(e) { 88 | Components.utils.reportError(e); 89 | } 90 | 91 | if(warnOnClose) 92 | cbu.setPrefs("browser.tabs.warnOnClose", true); 93 | if(warnOnQuit) 94 | cbu.setPrefs("browser.warnOnQuit", true); 95 | 96 | window.focus(); 97 | delete btn[ns + "detachedWindow"]; 98 | delete btn[ns + "tabPos"]; 99 | delete btn[ns + "parentTab"]; 100 | btn.checked = false; 101 | } 102 | function compactWindow(win) { 103 | var document = win.document; 104 | // See styles for window[chromehidden~="*"] in chrome://global/content/xul.css 105 | // But don't use "display: none;" 106 | var style = '\ 107 | #TabsToolbar,\n\ 108 | #nav-bar, /* Just force hide, now used too complex tricks to handle "chromehidden" */\n\ 109 | .tabbrowser-strip,\n\ 110 | .treestyletab-splitter,\n\ 111 | .chromeclass-menubar,\n\ 112 | .chromeclass-directories,\n\ 113 | .chromeclass-status,\n\ 114 | .chromeclass-extrachrome,\n\ 115 | .chromeclass-location,\n\ 116 | .chromeclass-toolbar,\n\ 117 | .chromeclass-toolbar-additional {\n\ 118 | visibility: collapse !important;\n\ 119 | }'; 120 | var root = document.documentElement; 121 | document.insertBefore( 122 | document.createProcessingInstruction( 123 | "xml-stylesheet", 124 | 'href="' + "data:text/css," 125 | + encodeURIComponent(style) + '" type="text/css"' 126 | ), 127 | root 128 | ); 129 | // See #main-window[disablechrome] ... in chrome://browser/content/browser.css 130 | // User may want override this styles 131 | var origSetAttribute = root.setAttribute; 132 | root.setAttribute = function(attr, val) { 133 | if(attr == "disablechrome") 134 | return undefined; 135 | return origSetAttribute.apply(this, arguments); 136 | }; 137 | root.removeAttribute("disablechrome"); 138 | root.offsetHeight; // Force reflow 139 | try { // Mark as popup window to open new tabs in window with visible tab bar 140 | win.toolbar.visible = false; 141 | } 142 | catch(e) { 143 | } 144 | } -------------------------------------------------------------------------------- /Detach_Tab/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Detach_Tab/icon.png -------------------------------------------------------------------------------- /Detach_Tab/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Detach_Tab/icon.xcf -------------------------------------------------------------------------------- /Edit_Custom_Button_in_Tab/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Edit_Custom_Button_in_Tab/icon.png) Edit Custom Button in Tab button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Add “Edit button in tab…” to custom button's context menu -------------------------------------------------------------------------------- /Edit_Custom_Button_in_Tab/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Edit_Custom_Button_in_Tab/icon.png -------------------------------------------------------------------------------- /Extensions_Developer_Tools/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Extensions_Developer_Tools/icon.png) Extensions Developer Tools button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Some tools for extensions or custom buttons developers (includes [Attributes Inspector](../Attributes_Inspector)). 3 |
Use middle-click on any main menu item to set it as default and call with middle-click on the button (you also can use left-click with any modifier since v.0.1.2pre2). 4 |
Also with [extDevToolsMouseGesturesLauncher.js](extDevToolsMouseGesturesLauncher.js) the code can be used in mouse gestures or in hotkeys. 5 |
Button's menu -------------------------------------------------------------------------------- /Extensions_Developer_Tools/extDevTools-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Extensions_Developer_Tools/extDevTools-en.png -------------------------------------------------------------------------------- /Extensions_Developer_Tools/extDevTools-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Extensions_Developer_Tools/extDevTools-ru.png -------------------------------------------------------------------------------- /Extensions_Developer_Tools/extDevToolsMouseGesturesLauncher.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/extDevToolsMouseGesturesLauncher.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Extensions_Developer_Tools 3 | 4 | // Mouse Gestures Launcher for Extensions Developer Tools 5 | // Also the code can be used from hotkeys (using keyconfig or similar extension) 6 | // Copy all code from 7 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/Extensions_Developer_Tools/extDevTools.js 8 | // after "//=== Extensions Developer Tools begin" 9 | 10 | // (c) Infocatcher 2012-2024 11 | // version 0.1.2 - 2024-03-06 12 | 13 | (function() { 14 | 15 | const popupsetId = "mgLauncherForExtDevTools-popupset"; 16 | var ps = document.getElementById(popupsetId); 17 | ps && ps.parentNode.removeChild(ps); 18 | ps = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "popupset"); 19 | ps.id = popupsetId; 20 | document.documentElement.appendChild(ps); 21 | 22 | function LOG(s) { 23 | Components.classes["@mozilla.org/consoleservice;1"] 24 | .getService(Components.interfaces.nsIConsoleService) 25 | .logStringMessage("Mouse Gestures Launcher for Extensions Developer Tools:\n" + s); 26 | } 27 | 28 | extDevTools.call(ps); 29 | var popup = ps.firstChild; 30 | 31 | var e; 32 | if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures 33 | e = event; 34 | else if( 35 | this instanceof (Components.interfaces.nsIDOMChromeWindow || Components.interfaces.nsIDOMWindow) 36 | && "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox 37 | ) 38 | e = mgGestureState.endEvent; 39 | else { 40 | var anchor = this instanceof XULElement && this 41 | || window.gBrowser && gBrowser.selectedBrowser 42 | || document.documentElement; 43 | if("boxObject" in anchor) { 44 | var bo = anchor.boxObject; 45 | e = { 46 | screenX: bo.screenX, 47 | screenY: bo.screenY 48 | }; 49 | if(this instanceof XULElement) 50 | e.screenY += bo.height; 51 | } 52 | else { 53 | e = { 54 | screenX: anchor.screenX || 0, 55 | screenY: anchor.screenY || 0 56 | }; 57 | } 58 | } 59 | 60 | var okEvt = e && ("screenX" in e); 61 | if(!popup || !okEvt) { 62 | alert( 63 | "Mouse Gestures Launcher for Extensions Developer Tools:" 64 | + (!popup ? "\nNo popup! Missing or failed Extensions Developer Tools code." : "") 65 | + (!okEvt ? "\nCan't get event object!" : "") 66 | ); 67 | destroy(); 68 | } 69 | else { 70 | if("openPopupAtScreen" in popup) 71 | popup.openPopupAtScreen(e.screenX, e.screenY); 72 | else 73 | popup.showPopup(document.documentElement, e.screenX, e.screenY, "popup", null, null); 74 | popup.addEventListener("popuphidden", destroy, false); 75 | } 76 | 77 | function destroy(e) { 78 | if(e && e.target != popup) 79 | return; 80 | popup && popup.removeEventListener("popuphidden", destroy, false); 81 | setTimeout(function() { 82 | if("onDestroy" in ps) try { 83 | ps.onDestroy("delete"); 84 | LOG("onDestroy()"); 85 | } 86 | catch(e) { 87 | Components.utils.reportError(e); 88 | } 89 | ps.parentNode.removeChild(ps); 90 | LOG("Remove popup"); 91 | }, 0); 92 | } 93 | 94 | 95 | function extDevTools() { 96 | //=== Extensions Developer Tools begin 97 | 98 | //=== Extensions Developer Tools end 99 | } 100 | 101 | }).call(this); -------------------------------------------------------------------------------- /Extensions_Developer_Tools/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Extensions_Developer_Tools/icon.png -------------------------------------------------------------------------------- /Extensions_Installer/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Extensions_Installer/icon.png) Extensions Installer button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
For extensions developers: installs extension from given link, useful to test restartless extensions 3 |
4 |
In example configuration used make.bat script and Delayed Start utility to hide console window. -------------------------------------------------------------------------------- /Extensions_Installer/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Extensions_Installer/icon.png -------------------------------------------------------------------------------- /Extensions_Installer/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Extensions_Installer/icon.xcf -------------------------------------------------------------------------------- /Extensions_Installer/make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set _out=my_extension-latest.xpi 3 | set _out_tmp=%~d0\~%_out%.tmp 4 | if exist %_out_tmp% set _out_tmp=%_out%.tmp 5 | set _7zip="%COMMANDER_PATH%\arch\7-Zip-4.65\7z.exe" 6 | set _winRar="%COMMANDER_PATH%\arch\WinRAR\WinRAR.exe" 7 | 8 | if not exist %_7zip% set _7zip="%ProgramFiles%\7-Zip\7z.exe" 9 | if not exist %_winRar% set _winRar="%ProgramFiles%\WinRAR\WinRAR.exe" 10 | 11 | if not exist %_7zip% ( 12 | echo 7-Zip not found! 13 | if not exist %_winRar% ( 14 | echo WinRAR not found! 15 | pause 16 | exit /b 17 | ) 18 | ) 19 | 20 | cd /d "%~dp0" 21 | 22 | set _files=install.rdf *.manifest *.js *.xul *.xml license* changelog* icon*.png defaults modules components locale chrome idl 23 | if exist %_7zip% ( 24 | echo =^> %_7zip% 25 | %_7zip% a -tzip -mx9 -mfb=258 -mpass=15 -- %_out_tmp% %_files% 26 | ) else ( 27 | echo =^> %_winRar% 28 | %_winRar% a -afzip -m5 -r -- %_out_tmp% %_files% 29 | ) 30 | 31 | if not exist %_out_tmp% echo Error: %_out_tmp% not found! & pause & exit /b 32 | 33 | if not exist %_out% goto skipCompare 34 | fc /l /lb2 /t %_out% %_out_tmp% 35 | if %ErrorLevel% == 0 ( 36 | del %_out_tmp% 37 | echo =============== 38 | echo ==^> No changes! 39 | echo =============== 40 | if not "%1" == "nodelay" ping -n 3 127.0.0.1 > nul 41 | exit /b 42 | ) 43 | :skipCompare 44 | 45 | echo ==^> Changed, update... 46 | move /y %_out_tmp% %_out% -------------------------------------------------------------------------------- /List_All_Tabs/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/List_All_Tabs/icon.png) List All Tabs button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Shows built-in list of all tabs -------------------------------------------------------------------------------- /List_All_Tabs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/List_All_Tabs/icon.png -------------------------------------------------------------------------------- /List_All_Tabs/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/List_All_Tabs/icon.xcf -------------------------------------------------------------------------------- /List_All_Tabs/listAllTabs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | List All Tabs [0.1.0.2 - 2014-08-05] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /List_All_Tabs/listAllTabs.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/List_All_Tabs 2 | 3 | // List All Tabs button for Custom Buttons 4 | // (code for "code" section) 5 | 6 | // (c) Infocatcher 2013-2014 7 | // version 0.1.0.2 - 2014-08-05 8 | 9 | var allTabsBtn = document.getElementById("alltabs-button"); 10 | if(!allTabsBtn && "gNavToolbox" in window && gNavToolbox.palette) // Firefox + button in palette 11 | allTabsBtn = gNavToolbox.palette.getElementsByAttribute("id", "alltabs-button")[0]; 12 | if(!allTabsBtn) { // SeaMonkey 13 | var tabContainer = document.getAnonymousElementByAttribute(gBrowser, "anonid", "tabcontainer"); 14 | allTabsBtn = tabContainer && document.getAnonymousElementByAttribute(tabContainer, "anonid", "alltabs-button"); 15 | } 16 | if(!allTabsBtn) { 17 | alert("All tab button not found!"); 18 | return; 19 | } 20 | 21 | var btn = this; 22 | var isBtn = btn instanceof XULElement; 23 | var popup = allTabsBtn.getElementsByTagName("menupopup")[0]; 24 | if(isBtn && btn._allTabsPopup) { 25 | btn._allTabsPopup.hidePopup(); 26 | btn._allTabsPopup = null; 27 | } 28 | else if(popup) { 29 | if(isBtn) { 30 | btn._allTabsPopup = popup; 31 | btn.setAttribute("open", true); 32 | } 33 | document.documentElement.appendChild(popup); 34 | popup.addEventListener("popuphidden", function restorePopup(e) { 35 | popup.removeEventListener(e.type, restorePopup, true); 36 | if(isBtn) { 37 | btn.removeAttribute("open"); 38 | btn._allTabsPopup = null; 39 | } 40 | allTabsBtn.appendChild(popup); 41 | }, true); 42 | 43 | var e = getEvent(); 44 | if(e) 45 | popup.openPopupAtScreen(e.screenX, e.screenY); 46 | else 47 | popup.openPopup(); 48 | } 49 | else { // SeaMonkey or old Firefox? 50 | var open = !allTabsBtn.open; 51 | if(open) { 52 | var evt = getEvent(); 53 | popup = document.getAnonymousElementByAttribute(allTabsBtn, "anonid", "alltabs-popup"); 54 | if(popup) { 55 | if(evt) { 56 | popup.addEventListener("popupshowing", function movePopup(e) { 57 | popup.removeEventListener(e.type, movePopup, false); 58 | popup.moveTo(evt.screenX, evt.screenY); 59 | }, false); 60 | } 61 | if(isBtn) { 62 | btn._allTabsPopup = popup; 63 | btn.setAttribute("open", true); 64 | var markAsClosedTimer = 0; 65 | var markAsClosed = function(e) { 66 | if(e.type == "popuphidden") { 67 | popup.removeEventListener("popuphidden", markAsClosed, true); 68 | markAsClosedTimer = setTimeout(function() { 69 | btn.removeAttribute("open"); 70 | btn._allTabsPopup = null; 71 | }, 0); 72 | } 73 | else { 74 | btn.removeEventListener("mousedown", markAsClosed, true); 75 | clearTimeout(markAsClosedTimer); 76 | } 77 | }; 78 | popup.addEventListener("popuphidden", markAsClosed, true); 79 | btn.addEventListener("mousedown", markAsClosed, true); 80 | } 81 | } 82 | } 83 | allTabsBtn.open = open; 84 | } 85 | 86 | function getEvent() { 87 | var e; 88 | if(typeof event == "object" && event instanceof Event && "screenX" in event) // FireGestures 89 | e = event; 90 | else if( 91 | btn instanceof Components.interfaces.nsIDOMChromeWindow 92 | && "mgGestureState" in window && "endEvent" in mgGestureState // Mouse Gestures Redox 93 | ) 94 | e = mgGestureState.endEvent; 95 | else { 96 | var anchor = btn instanceof XULElement && btn 97 | || window.gBrowser && gBrowser.selectedBrowser 98 | || document.documentElement; 99 | if("boxObject" in anchor) { 100 | var bo = anchor.boxObject; 101 | e = { 102 | screenX: bo.screenX, 103 | screenY: bo.screenY 104 | }; 105 | if(btn instanceof XULElement) 106 | e.screenY += bo.height; 107 | } 108 | } 109 | return e; 110 | } -------------------------------------------------------------------------------- /Merge_Custom_Buttons/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Merge_Custom_Buttons/icon.png) Merge Custom Buttons button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Merge many custom buttons into one: place this button before other custom buttons and separators to move them into submenu of this button. 3 |
Use two separators as “stop” flag. 4 |
May not work for buttons with initialization code. 5 |
Middle-click or left-click with any modifier – temporary split/merge. 6 |
Known issue: “Move to Menu/Toolbar” and “Remove from Menu/Toolbar” menu items always works for button itself. 7 | 8 | ##### Screenshots: 9 | Menu with merged custom buttons Middle-click to temporarily split -------------------------------------------------------------------------------- /Merge_Custom_Buttons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Merge_Custom_Buttons/icon.png -------------------------------------------------------------------------------- /Merge_Custom_Buttons/screenshots/menu_with_merged_custom_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Merge_Custom_Buttons/screenshots/menu_with_merged_custom_buttons.png -------------------------------------------------------------------------------- /Merge_Custom_Buttons/screenshots/temporarily_split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Merge_Custom_Buttons/screenshots/temporarily_split.png -------------------------------------------------------------------------------- /Open_Window/README.md: -------------------------------------------------------------------------------- 1 | **Open Window** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Open/focus/toggle window demo -------------------------------------------------------------------------------- /Open_Window/window.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/window.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Open_Window 3 | 4 | // Open Window button for Custom Buttons 5 | // /* Code */ - code for "Code" section 6 | // /* Initialization */ - code for "Initialization" section 7 | 8 | // (c) Infocatcher 2012, 2014 9 | // version 0.1.2 - 2014-03-28 10 | 11 | 12 | /* Code */ 13 | this.linkedWindow.toggle(); 14 | // Or 15 | //this.linkedWindow.open(); 16 | // Or 17 | //this.linkedWindow.close() || anySpecialCodeToOpenWindow(); 18 | 19 | 20 | /* Initialization */ 21 | if(!("Services" in window)) 22 | Components.utils.import("resource://gre/modules/Services.jsm"); 23 | 24 | function Window(uri, type) { 25 | this.uri = uri; 26 | this.type = type; 27 | } 28 | Window.prototype = { 29 | get: function() { 30 | if(this.type) 31 | return Services.wm.getMostRecentWindow(this.type); 32 | var ws = Services.wm.getEnumerator(null); 33 | while(ws.hasMoreElements()) { 34 | var w = ws.getNext(); 35 | if(w.location.href == this.uri) 36 | return w; 37 | } 38 | return null; 39 | }, 40 | open: function(params, features) { 41 | var w = this.get(); 42 | if(w) { 43 | w.focus(); 44 | return w; 45 | } 46 | var args = [this.uri, "_blank", features || "chrome,all,dialog=0,resizable,centerscreen"]; 47 | if(params) 48 | args.push.apply(args, params); 49 | return window.openDialog.apply(window, args); 50 | }, 51 | close: function() { 52 | var w = this.get(); 53 | w && w.close(); 54 | return w; 55 | }, 56 | toggle: function() { 57 | return this.close() || this.open.apply(this, arguments); 58 | }, 59 | setObserver: function(observer) { 60 | this.observer = observer; 61 | var w = this.get(); 62 | w && this.notifyObserver(true, w); 63 | Services.ww.registerNotification(this); 64 | }, 65 | removeObserver: function() { 66 | Services.ww.unregisterNotification(this); 67 | delete this.observer; 68 | }, 69 | observe: function(subject, topic, data) { 70 | if(topic == "domwindowopened") 71 | subject.addEventListener("DOMContentLoaded", this, false); 72 | else if(topic == "domwindowclosed") { 73 | if(subject.location.href == this.uri) 74 | this.notifyObserver(false, subject); 75 | } 76 | }, 77 | handleEvent: function(e) { 78 | if(e.type != "DOMContentLoaded") 79 | return; 80 | var window = e.originalTarget.defaultView; 81 | window.removeEventListener("DOMContentLoaded", this, false); 82 | if(window.location.href == this.uri) 83 | this.notifyObserver(true, window); 84 | }, 85 | notifyObserver: function(opened, window) { 86 | var o = this.observer; 87 | "onWindowChanged" in o && o.onWindowChanged(opened, window); 88 | if(opened) 89 | "onWindowOpened" in o && o.onWindowOpened(window); 90 | else 91 | "onWindowClosed" in o && o.onWindowClosed(window); 92 | } 93 | }; 94 | 95 | //var w = this.linkedWindow = new Window("chrome://passwordmgr/content/passwordManager.xul", "Toolkit:PasswordManager"); 96 | var w = this.linkedWindow = new Window("chrome://browser/content/preferences/preferences.xul", "Browser:Preferences"); 97 | w.setObserver({ 98 | button: this, 99 | onWindowChanged: function(opened) { 100 | this.button.checked = opened; 101 | } 102 | }); 103 | this.onDestroy = function() { 104 | this.linkedWindow.removeObserver(); 105 | }; -------------------------------------------------------------------------------- /Pin_Tabs/README.md: -------------------------------------------------------------------------------- 1 | **Pin Tabs** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Left-click: pin/unpin current tab 3 |
Middle-click: toggle autopin -------------------------------------------------------------------------------- /Pin_Tabs/pinTabs.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/pinTabs.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Pin_Tabs 3 | 4 | // Pin Tabs button for Custom Buttons 5 | // (code for "initialization" section) 6 | 7 | // (c) Infocatcher 2010, 2012 8 | // version 0.1.2 - 2012-10-12 9 | 10 | // Left-click: pin/unpin current tab 11 | // Middle-click: toggle autopin 12 | 13 | //== Settings begin 14 | this.startupAutoPin = false; 15 | // See https://developer.mozilla.org/en/XUL_Tutorial/Keyboard_Shortcuts#Key_element 16 | addKey(this, "toggleTabPinned", "control q"); 17 | addKey(this, "toggleTabsPinned", "control shift q"); 18 | addKey(this, "toggleAutoPin", "control alt q"); 19 | //== Settings end 20 | 21 | this.toggleTabPinned = function(tab) { 22 | tab = tab || gBrowser.selectedTab; 23 | gBrowser[tab.pinned ? "unpinTab" : "pinTab"](tab); 24 | }; 25 | this.toggleTabsPinned = function(pin) { 26 | var tabs = Array.prototype.slice.call(gBrowser.visibleTabs || gBrowser.tabs); 27 | pin = arguments.length 28 | ? pin 29 | : tabs.some(function(tab) { return !tab.pinned; }); 30 | if(!pin) 31 | tabs = tabs.reverse(); 32 | var action = pin ? "pinTab" : "unpinTab"; 33 | tabs.forEach(function(tab) { 34 | gBrowser[action](tab); 35 | }); 36 | }; 37 | this.evtHahdler = { 38 | button: this, 39 | handleEvent: function(e) { 40 | gBrowser.pinTab(e.target); 41 | } 42 | }; 43 | this._autoPin = false; 44 | this.toggleAutoPin = function() { 45 | this._autoPin = !this._autoPin; 46 | var tc = gBrowser.tabContainer; 47 | tc[this._autoPin ? "addEventListener" : "removeEventListener"]("TabOpen", this.evtHahdler, false); 48 | this.checked = this._autoPin; 49 | }; 50 | this.onDestroy = function() { 51 | this._autoPin && this.toggleAutoPin(); 52 | }; 53 | this.onclick = function(e) { 54 | if(e.button == 1 || e.button == 0 && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) 55 | this.toggleAutoPin(); 56 | else if(e.button == 0) 57 | this.toggleTabsPinned(); 58 | }; 59 | if(this.startupAutoPin) { 60 | this.toggleTabsPinned(true); 61 | this.toggleAutoPin(); 62 | } 63 | 64 | function addKey(button, cmd, keyStr) { 65 | if(!addKey.hasOwnProperty("keyset")) { 66 | let kId = "custombuttons-keyset"; 67 | let keyset = document.getElementById(kId); 68 | if(!keyset) { 69 | keyset = document.createElement("keyset"); 70 | keyset.id = kId; 71 | document.documentElement.appendChild(keyset); 72 | } 73 | addKey.keyset = keyset; 74 | } 75 | var keyElt = document.createElement("key"); 76 | keyElt.id = "custombuttons-key-" + cmd; 77 | keyElt.__button = button; 78 | keyElt.setAttribute("oncommand", "this.__button." + cmd + "();"); 79 | var tokens = keyStr.split(" "); 80 | var key = tokens.pop() || " "; 81 | var modifiers = tokens.join(","); 82 | keyElt.setAttribute(key.indexOf("VK_") == 0 ? "keycode" : "key", key); 83 | keyElt.setAttribute("modifiers", modifiers); 84 | addKey.keyset.appendChild(keyElt); 85 | } -------------------------------------------------------------------------------- /Plugins_Permissions/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Plugins_Permissions/icons/icon.png) Plugins Permissions button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Menage plugins permissions: block or allow. 3 |
Note: *plugins.click_to_play* in about:config (“Block plugins” checkbox in button's context menu) should be enabled. 4 |
5 |
Unfortunately since Firefox 20 (Gecko 20) global exclusions doesn't work, only on per-plugin basis. 6 |
So you should change "Shockwave Flash" and "plugin:flash" in the source (and create copy of this button) to menage other plugins. 7 | 8 | ##### Screenshot: 9 | Button's context menu -------------------------------------------------------------------------------- /Plugins_Permissions/icons/icon-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/icon-alt.png -------------------------------------------------------------------------------- /Plugins_Permissions/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/icon.png -------------------------------------------------------------------------------- /Plugins_Permissions/icons/plugins_merged-alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/plugins_merged-alt.png -------------------------------------------------------------------------------- /Plugins_Permissions/icons/plugins_merged-alt.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/plugins_merged-alt.xcf -------------------------------------------------------------------------------- /Plugins_Permissions/icons/plugins_merged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/plugins_merged.png -------------------------------------------------------------------------------- /Plugins_Permissions/icons/plugins_merged.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/icons/plugins_merged.xcf -------------------------------------------------------------------------------- /Plugins_Permissions/pluginsPermissions-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/pluginsPermissions-en.png -------------------------------------------------------------------------------- /Plugins_Permissions/pluginsPermissions-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Plugins_Permissions/pluginsPermissions-ru.png -------------------------------------------------------------------------------- /Purge_Tabs_History/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Purge_Tabs_History/icon.png) Purge Tab(s) History button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Purge back/forward history for current tab (left-click) or all tabs (middle-click) -------------------------------------------------------------------------------- /Purge_Tabs_History/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Purge_Tabs_History/icon.png -------------------------------------------------------------------------------- /Purge_Tabs_History/purgeTabsHistory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Purge Tab(s) History [0.3.0.2 - 2015-04-06] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Purge_Tabs_History/purgeTabsHistory.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Purge_Tabs_History 2 | // http://infocatcher.ucoz.net/js/cb/purgeTabsHistory.js 3 | 4 | // Purge Tab(s) History 5 | // (c) Infocatcher 2009, 2011-2013, 2015 6 | // version 0.3.0.2 - 2015-04-06 7 | 8 | this.onclick = function(e) { 9 | if(e.button == 1 || e.button == 0 && (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey)) 10 | this.historyManager.purgeBrowsersHistory(this.historyManager.visibleBrowsers); 11 | else if(e.button == 0) 12 | this.historyManager.purgeBrowserHistory(); 13 | }; 14 | 15 | var dummy = function() {}; 16 | this.historyManager = { 17 | button: this, 18 | initialized: false, 19 | init: function() { 20 | if(this.initialized) 21 | return; 22 | this.initialized = true; 23 | 24 | window.addEventListener(this.ssTabRestoredEvent, this, false); 25 | window.addEventListener("TabClose", this, false); 26 | window.addEventListener("unload", this, false); 27 | gBrowser.addProgressListener(this); 28 | 29 | this.updButtonStateDelayed(); 30 | //this.updButtonStateDelayed(1000); 31 | }, 32 | destroy: function() { 33 | if(!this.initialized) 34 | return; 35 | this.initialized = false; 36 | 37 | window.removeEventListener(this.ssTabRestoredEvent, this, false); 38 | window.removeEventListener("TabClose", this, false); 39 | window.removeEventListener("unload", this, false); 40 | gBrowser.removeProgressListener(this); 41 | }, 42 | get ssTabRestoredEvent() { 43 | delete this.ssTabRestoredEvent; 44 | return this.ssTabRestoredEvent = "@mozilla.org/browser/sessionstore;1" in Components.classes 45 | ? "SSTabRestored" 46 | : "TabOpen"; 47 | }, 48 | 49 | handleEvent: function(e) { 50 | switch(e.type) { 51 | case "TabOpen": 52 | case "SSTabRestored": 53 | this.updButtonStateDelayed(250); // Slow restoring during browser startup 54 | break; 55 | case "TabClose": 56 | this.updButtonStateDelayed(); 57 | break; 58 | case "unload": 59 | this.destroy(); 60 | } 61 | }, 62 | 63 | QueryInterface: function(iid) { 64 | if( 65 | iid.equals(Components.interfaces.nsIWebProgressListener) 66 | || iid.equals(Components.interfaces.nsISupportsWeakReference) 67 | || iid.equals(Components.interfaces.nsISupports) 68 | ) 69 | return this; 70 | throw Components.results.NS_NOINTERFACE; 71 | }, 72 | onStateChange: dummy, 73 | onProgressChange: dummy, 74 | onLocationChange: function(aWebProgress, aRequest, aLocation) { 75 | this.updButtonStateDelayed(); 76 | }, 77 | onStatusChange: dummy, 78 | onSecurityChange: dummy, 79 | 80 | purgeBrowserHistory: function(browser) { 81 | if(!browser) 82 | browser = gBrowser.selectedBrowser; 83 | var sh = browser.sessionHistory 84 | .QueryInterface(Components.interfaces.nsISHistory) 85 | .QueryInterface(Components.interfaces.nsISHistoryInternal); 86 | var count = sh.count; 87 | if(!count) 88 | return; 89 | var indx = sh.index; 90 | var curEntry = indx > -1 ? sh.getEntryAtIndex(indx, false) : null; 91 | sh.PurgeHistory(count); 92 | curEntry && sh.addEntry(curEntry, true); 93 | if(arguments.length <= 1) 94 | this.upd(); 95 | }, 96 | purgeBrowsersHistory: function(browsers) { 97 | browsers.forEach(this.purgeBrowserHistory, this); 98 | this.upd(); 99 | }, 100 | 101 | upd: function() { 102 | this.forceSaveSession(); 103 | this.updButtonState(); 104 | this.updUI(); 105 | }, 106 | updUI: function() { 107 | if("UpdateBackForwardCommands" in window) // Firefox 108 | UpdateBackForwardCommands(gBrowser.webNavigation); 109 | else // SeaMonkey 110 | UpdateBackForwardButtons(); 111 | }, 112 | get visibleBrowsers() { 113 | if("visibleTabs" in gBrowser) { 114 | return gBrowser.visibleTabs.map(function(tab) { 115 | return tab.linkedBrowser; 116 | }); 117 | } 118 | return gBrowser.browsers; 119 | }, 120 | updButtonState: function() { 121 | this.button.disabled = !this.visibleBrowsers.some(function(browser) { 122 | return browser && browser.sessionHistory && browser.sessionHistory.count > 1; 123 | }); 124 | }, 125 | updButtonStateDelayed: function(delay) { 126 | setTimeout(function(_this) { 127 | _this.updButtonState(); 128 | }, delay || 0, this); 129 | }, 130 | _forceSaveSessionTimer: 0, 131 | forceSaveSession: function() { 132 | const key = "custombuttonsPurgeTabHistoryForceSaveSession"; 133 | var ss = "nsISessionStore" in Components.interfaces 134 | ? ( 135 | Components.classes["@mozilla.org/browser/sessionstore;1"] 136 | || Components.classes["@mozilla.org/suite/sessionstore;1"] 137 | ).getService(Components.interfaces.nsISessionStore) 138 | : SessionStore; // Firefox 61+ https://bugzilla.mozilla.org/show_bug.cgi?id=1450559 139 | ss[ 140 | "setWindowValue" in ss 141 | ? "setWindowValue" 142 | : "setCustomWindowValue" // Firefox 64+ 143 | ](window, key, "" + Date.now()); 144 | clearTimeout(this._forceSaveSessionTimer); 145 | this._forceSaveSessionTimer = setTimeout(function() { 146 | ss.deleteWindowValue(window, key); 147 | }, 20e3); 148 | } 149 | }; 150 | 151 | this.onDestroy = function() { 152 | this.historyManager.destroy(); 153 | }; 154 | this.historyManager.init(); -------------------------------------------------------------------------------- /Quick_Filter_by_Recipient/README.md: -------------------------------------------------------------------------------- 1 | **Quick Filter by Recipient** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
(for Thunderbird) 3 |
Uses built-in quick filter to filter all messages from any recipient of selected message -------------------------------------------------------------------------------- /Quick_Filter_by_Recipient/tbQuickFilterByRecipient.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Quick_Filter_by_Recipient 2 | 3 | // Quick Filter by Recipient button for Custom Buttons 4 | // (code for "code" section) 5 | 6 | // (c) Infocatcher 2013 7 | // version 0.1.0 - 2013-08-16 8 | 9 | function _localize(s, key) { 10 | var strings = { 11 | "Filter by recipient": { 12 | ru: "Фильтр по получателю" 13 | }, 14 | "Select email address to filter:": { 15 | ru: "Выберите email-адрес для фильтрации:" 16 | } 17 | }; 18 | var locale = (function() { 19 | if("Services" in window && "locale" in Services) { 20 | var locales = Services.locale.requestedLocales // Firefox 64+ 21 | || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales(); 22 | if(locales) 23 | return locales[0]; 24 | } 25 | var prefs = "Services" in window && Services.prefs 26 | || Components.classes["@mozilla.org/preferences-service;1"] 27 | .getService(Components.interfaces.nsIPrefBranch); 28 | function pref(name, type) { 29 | return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined; 30 | } 31 | if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390 32 | var locale = pref("general.useragent.locale", "Char"); 33 | if(locale && locale.substr(0, 9) != "chrome://") 34 | return locale; 35 | } 36 | return Components.classes["@mozilla.org/chrome/chrome-registry;1"] 37 | .getService(Components.interfaces.nsIXULChromeRegistry) 38 | .getSelectedLocale("global"); 39 | })().match(/^[a-z]*/)[0]; 40 | _localize = !locale || locale == "en" 41 | ? function(s) { 42 | return s; 43 | } 44 | : function(s) { 45 | return strings[s] && strings[s][locale] || s; 46 | }; 47 | return _localize.apply(this, arguments); 48 | } 49 | 50 | var selectedMessages = gFolderDisplay.selectedMessages; 51 | if(selectedMessages && selectedMessages.length) { 52 | var selectedMessage = selectedMessages[0]; 53 | var recipients = extractAddress(selectedMessage.recipients).split(", "); 54 | var cc = extractAddress(selectedMessage.ccList).split(", "); 55 | var bcc = extractAddress(selectedMessage.bccList).split(", "); 56 | var allRecipients = recipients.concat(cc, bcc).filter(function(eml, i, arr) { 57 | return eml && arr.indexOf(eml) == i; 58 | }); 59 | 60 | var recipient = allRecipients[0]; 61 | if(allRecipients.length > 1) { 62 | var recipientOut = { value: 0 }; 63 | var ok = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] 64 | .getService(Components.interfaces.nsIPromptService) 65 | .select( 66 | window, 67 | _localize("Filter by recipient"), 68 | _localize("Select email address to filter:"), 69 | allRecipients.length, 70 | allRecipients, 71 | recipientOut 72 | ); 73 | if(!ok) 74 | return; 75 | recipient = allRecipients[recipientOut.value]; 76 | } 77 | 78 | setFilterOptions({ 79 | sender: false, 80 | recipients: true, 81 | subject: false, 82 | body: false 83 | }); 84 | var filterField = document.getElementById("qfb-qs-textbox"); 85 | filterField.value = recipient; 86 | filterField.doCommand(); 87 | } 88 | function extractAddress(header) { 89 | return Components.classes["@mozilla.org/messenger/headerparser;1"] 90 | .getService(Components.interfaces.nsIMsgHeaderParser) 91 | .extractHeaderAddressMailboxes(header); 92 | } 93 | function setFilterOptions(opts) { 94 | for(var type in opts) if(opts.hasOwnProperty(type)) { 95 | var btn = document.getElementById("qfb-qs-" + type); 96 | if(btn.checked != opts[type]) 97 | btn.click(); 98 | } 99 | } -------------------------------------------------------------------------------- /Quick_Filter_by_Sender/README.md: -------------------------------------------------------------------------------- 1 | **Quick Filter by Sender** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
(for Thunderbird) 3 |
Uses built-in quick filter to filter all messages from sender of selected message -------------------------------------------------------------------------------- /Quick_Filter_by_Sender/tbQuickFilterBySender.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Quick_Filter_by_Sender 2 | 3 | // Quick Filter by Sender button for Custom Buttons 4 | // (code for "code" section) 5 | 6 | // (c) Infocatcher 2013 7 | // version 0.1.0 - 2013-08-16 8 | 9 | var selectedMessages = gFolderDisplay.selectedMessages; 10 | if(selectedMessages && selectedMessages.length) { 11 | var authorEmail = extractAddress(selectedMessages[0].author); 12 | setFilterOptions({ 13 | sender: true, 14 | recipients: false, 15 | subject: false, 16 | body: false 17 | }); 18 | var filterField = document.getElementById("qfb-qs-textbox"); 19 | filterField.value = authorEmail; 20 | filterField.doCommand(); 21 | } 22 | function extractAddress(header) { 23 | return Components.classes["@mozilla.org/messenger/headerparser;1"] 24 | .getService(Components.interfaces.nsIMsgHeaderParser) 25 | .extractHeaderAddressMailboxes(header); 26 | } 27 | function setFilterOptions(opts) { 28 | for(var type in opts) if(opts.hasOwnProperty(type)) { 29 | var btn = document.getElementById("qfb-qs-" + type); 30 | if(btn.checked != opts[type]) 31 | btn.click(); 32 | } 33 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Usage 2 | * Install **[Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/)** extension 3 | * Go to button directory and click on button name to install the release version (if available) 4 | * or open *.html (if exist) and click on custombutton:// link 5 | * or read instructions in *.js and copy code to the “code” or “initialization” section in custom button editor (be careful: this is development version and may contain some bugs) 6 | 7 |
8 | 9 | #### Buttons in alphabetical order 10 | 11 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Add_New_Buttons_After_This_Button/icon.png) [Add New Buttons After This Button](Add_New_Buttons_After_This_Button) 12 | New custom buttons will be automatically placed after this button (button is disabled by default, click to enable) 13 | 14 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Attributes_Inspector/icon.png) [Attributes Inspector](Attributes_Inspector) 15 | Shows tooltip with with all attributes and allow open [DOM Inspector](https://addons.mozilla.org/addon/dom-inspector-6622/) for current node 16 | 17 | ##### [Back to Close](Back_to_Close) 18 | Use “Back” command to close tab without “back history” 19 | 20 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Bookmarks_Folder/icon.png) [Bookmarks Folder](Bookmarks_Folder) 21 | Show contents of any bookmarks folder in drop-down menu 22 | 23 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Disable_Initialization/icon.png) [Custom Buttons: Disable Initialization](CB_Disable_Initialization) 24 | Adds “Enabled” checkbox to custom button's context menu (for test purposes) 25 | 26 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Source_Editor/icon.png) [Custom Buttons: Source Editor](CB_Source_Editor) 27 | (Formerly Orion Editor) 28 |
Allows to highlight code in Custom Buttons editor using built-in [source editor component](https://developer.mozilla.org/en-US/docs/Tools/Editor). 29 |
Beware: many things doesn't work and strange bugs may happens! 30 | 31 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/CB_Editor_Toggle_on_Top/icons/icon.png) [Custom Buttons Editor: Toggle on Top](CB_Editor_Toggle_on_Top) 32 | Adds “On top” button to built-in custom button's editor (doesn't work on some platforms!) 33 | 34 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Check_for_Addons_Updates/icon.png) [Check for Addons Updates](Check_for_Addons_Updates) 35 | Button just open hidden tab with about:addons and trigger built-in “Check for Updates” function. 36 |
And show tab, if found updates. 37 | 38 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Convert_E4X/icon.png) [Convert E4X](Convert_E4X) 39 | Tries convert [deprecated](http://custombuttons.sf.net/forum/viewtopic.php?f=2&t=365) [E4X](https://developer.mozilla.org/en-US/docs/E4X) to string literals 40 | 41 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Cookies_Permissions/icons/icon.png) [Cookies Permissions](Cookies_Permissions) 42 | Menage cookies permissions: block, allow for session or allow. 43 |
Also shows permissions for current site and has some cookies-related features. 44 | 45 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Detach_Tab/icon.png) [Detach Tab](Detach_Tab) 46 | Detach current tab to new “light weight” window without toolbars and attach back, if button pressed second time or window was closed 47 | 48 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Edit_Custom_Button_in_Tab/icon.png) [Edit Custom Button in Tab](Edit_Custom_Button_in_Tab) 49 | Add “Edit button in tab…” to custom button's context menu 50 | 51 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Extensions_Developer_Tools/icon.png) [Extensions Developer Tools](Extensions_Developer_Tools) 52 | Some tools for extensions or custom buttons developers 53 | 54 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Extensions_Installer/icon.png) [Extensions Installer](Extensions_Installer) 55 | For extensions developers: installs extension from given link, useful to test restartless extensions 56 | 57 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/List_All_Tabs/icon.png) [List All Tabs](List_All_Tabs) 58 | Shows built-in list of all tabs 59 | 60 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Merge_Custom_Buttons/icon.png) [Merge Custom Buttons](Merge_Custom_Buttons) 61 | Merge many custom buttons into one 62 | 63 | ##### [Open Window](Open_Window) 64 | Open/focus/toggle window demo 65 | 66 | ##### [Pin Tabs](Pin_Tabs) 67 | Left-click: pin/unpin current tab 68 |
Middle-click: toggle autopin 69 | 70 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Plugins_Permissions/icons/icon.png) [Plugins Permissions](Plugins_Permissions) 71 | Menage plugins permissions: block or allow. 72 |
Note: *plugins.click_to_play* in about:config should be enabled. 73 | 74 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Purge_Tabs_History/icon.png) [Purge Tab(s) History](Purge_Tabs_History) 75 | Purge back/forward history for current tab (left-click) or all tabs (middle-click) 76 | 77 | ##### [Quick Filter by Recipient](Quick_Filter_by_Recipient) 78 | (for Thunderbird) 79 |
Uses built-in quick filter to filter all messages from any recipient of selected message 80 | 81 | ##### [Quick Filter by Sender](Quick_Filter_by_Sender) 82 | (for Thunderbird) 83 |
Uses built-in quick filter to filter all messages from sender of selected message 84 | 85 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Reload_Broken_Images/icon.png) [Reload Broken Images](Reload_Broken_Images) 86 | Reload broken or not loaded images 87 | 88 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Session_Bookmarks/icon.png) [Session Bookmarks](Session_Bookmarks) 89 | Drop-down menu with “session” bookmarks: additionally saves session information (such as scroll position and controls state). 90 |
Use middle-click or left+click with any modifier to add current tab. 91 |
Drag and drop any tab to add new bookmark. 92 | 93 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Show_Anchors/icon.png) [Show Anchors](Show_Anchors) 94 | Show/hide all anchors on the page to easily copy link to some section of the page 95 | 96 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Switch_Keyboard_Layout/icon.png) [Switch Keyboard Layout](Switch_Keyboard_Layout) 97 | Convert text, typed in wrong keyboard layout 98 | 99 | ##### [Tabbar Doubleclick](Tabbar_Doubleclick) 100 | Makes double click on tab bar open a new tab 101 | 102 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Title_Bar/icon.png) [Title Bar](Title_Bar) 103 | Show window title (if original title was hidden by some reasons) 104 | 105 | ##### [Toggle Find](Toggle_Find) 106 | Toggle find bar and prefill it with selected text 107 | 108 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_Flash/icon.png) [Toggle Flash](Toggle_Flash) 109 | Toggle Shockwave Flash plugin (also may be easily configured to toggle any other add-on) 110 | 111 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_GIF_Animation/icon.png) [Toggle GIF Animation](Toggle_GIF_Animation) 112 | Disable or enable GIF animation on current page 113 | 114 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_Restartless_Add-ons/icon.png) [Toggle Restartless Add-ons](Toggle_Restartless_Add-ons) 115 | Drop-down menu to toggle restartless add-ons 116 | 117 | ##### [Toolbar Flexible Space](Toolbar_Flexible_Space) 118 | Just looks like toolbar flexible space, may be useful in Firefox 29+ (Australis) 119 | 120 | ##### [Toolbar Separator](Toolbar_Separator) 121 | Just looks like toolbar separator, may be useful in Firefox 29+ (Australis) 122 | 123 | ##### [Toolbar Space](Toolbar_Space) 124 | Just looks like toolbar space, may be useful in Firefox 29+ (Australis) 125 | 126 | ##### ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Undo_Close_Tabs/icons/icon.png) [Undo Close Tabs](Undo_Close_Tabs) 127 | Allows restore recently closed tabs and windows 128 | 129 |
130 | 131 | #### [Code snippets](code_snippets) 132 | Some code snippets related to Custom Buttons. 133 | 134 | #### [Tests](tests) 135 | Some buttons for test purposes. -------------------------------------------------------------------------------- /Reload_Broken_Images/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Reload_Broken_Images/icon.png) Reload Broken Images button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Reload broken or not loaded images. 3 |
This is the same as “Reload Image” from context menu, but for all images on the page. -------------------------------------------------------------------------------- /Reload_Broken_Images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Reload_Broken_Images/icon.png -------------------------------------------------------------------------------- /Reload_Broken_Images/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Reload_Broken_Images/icon.xcf -------------------------------------------------------------------------------- /Reload_Broken_Images/reloadBrokenImages.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/reloadBrokenImages.js 2 | // https://forum.mozilla-russia.org/viewtopic.php?id=57978 3 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Reload_Broken_Images 4 | 5 | // Reload Broken Images button for Custom Buttons 6 | // (code for "code" section) 7 | 8 | // (c) Infocatcher 2012-2015 9 | // version 0.3.1 - 2015-04-02 10 | 11 | var debug = false; 12 | var maxAttempts = 4; 13 | 14 | function _localize(s) { 15 | var strings = { 16 | "%label%: ": { 17 | ru: "%label%: " 18 | }, 19 | "Reloading: $1/$2": { 20 | ru: "Обновление: $1/$2" 21 | }, 22 | "Done [total: $1, failed: $2]": { 23 | ru: "Готово [всего: $1, неудачно: $2]" 24 | }, 25 | "Done [total: $1]": { 26 | ru: "Готово [всего: $1]" 27 | }, 28 | "Start reloading: $1": { 29 | ru: "Запуск обновления: $1" 30 | }, 31 | "Nothing to reload": { 32 | ru: "Обновлять нечего" 33 | } 34 | }; 35 | var locale = (function() { 36 | if("Services" in window && "locale" in Services) { 37 | var locales = Services.locale.requestedLocales // Firefox 64+ 38 | || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales(); 39 | if(locales) 40 | return locales[0]; 41 | } 42 | var prefs = "Services" in window && Services.prefs 43 | || Components.classes["@mozilla.org/preferences-service;1"] 44 | .getService(Components.interfaces.nsIPrefBranch); 45 | function pref(name, type) { 46 | return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined; 47 | } 48 | if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390 49 | var locale = pref("general.useragent.locale", "Char"); 50 | if(locale && locale.substr(0, 9) != "chrome://") 51 | return locale; 52 | } 53 | return Components.classes["@mozilla.org/chrome/chrome-registry;1"] 54 | .getService(Components.interfaces.nsIXULChromeRegistry) 55 | .getSelectedLocale("global"); 56 | })().match(/^[a-z]*/)[0]; 57 | _localize = !locale || locale == "en" 58 | ? function(s) { 59 | return s; 60 | } 61 | : function(s) { 62 | return strings[s] && strings[s][locale] || s; 63 | }; 64 | return _localize.apply(this, arguments); 65 | } 66 | 67 | var logPrefix = "reloadImage(): "; 68 | debug && Components.utils.import("resource://gre/modules/Services.jsm"); 69 | var activeAttempts = 0; 70 | var totalImages = 0; 71 | var successImages = 0; 72 | var failedImages = 0; 73 | function reloadImage(img) { 74 | // Based on code from chrome://browser/content/nsContextMenu.js (Firefox 21.0a1) 75 | if(!(img instanceof Components.interfaces.nsIImageLoadingContent) || !img.currentURI) 76 | return; 77 | var request = img.getRequest(Components.interfaces.nsIImageLoadingContent.CURRENT_REQUEST); 78 | if( 79 | request 80 | && request.imageStatus & request.STATUS_LOAD_COMPLETE 81 | && !(request.imageStatus & request.STATUS_ERROR) // We may have both flags! 82 | ) 83 | return; 84 | var uri = img.currentURI; 85 | var src = uri.spec; 86 | try { 87 | urlSecurityCheck( 88 | src, 89 | img.ownerDocument.nodePrincipal, 90 | Components.interfaces.nsIScriptSecurityManager.DISALLOW_SCRIPT 91 | ); 92 | } 93 | catch(e) { 94 | Components.utils.reportError(e); 95 | return; 96 | } 97 | debug && Services.console.logStringMessage(logPrefix + src); 98 | var errors = 0; 99 | function check(e) { 100 | var error = e.type == "error"; 101 | if(error && ++errors < maxAttempts) { 102 | try { 103 | var tools = Components.classes["@mozilla.org/image/tools;1"] 104 | .getService(Components.interfaces.imgITools); 105 | var cache = "getImgCacheForDocument" in tools // Gecko 18 106 | ? tools.getImgCacheForDocument(img.ownerDocument) 107 | : Components.classes["@mozilla.org/image/cache;1"] 108 | .getService(Components.interfaces.imgICache); 109 | if(cache.findEntryProperties(uri)) { 110 | cache.removeEntry(uri); 111 | debug && Services.console.logStringMessage(logPrefix + src + "\n=> remove this URI from cache"); 112 | } 113 | } 114 | catch(e) { 115 | debug && Services.console.logStringMessage(logPrefix + src + "\n=> cache.removeEntry() failed"); 116 | Components.utils.reportError(e); 117 | } 118 | 119 | // Workaround for "Image corrupt or truncated" error 120 | var req = new XMLHttpRequest(); 121 | req.open("GET", src, true); 122 | req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; 123 | req.onload = req.onerror = resetSrc; 124 | req.send(null); 125 | 126 | resetSrc(); 127 | } 128 | else { 129 | if(error) 130 | ++failedImages; 131 | else 132 | ++successImages; 133 | feedback("Reloading: $1/$2", [failedImages + successImages, totalImages]); 134 | destroy(); 135 | } 136 | debug && Services.console.logStringMessage(logPrefix + src + "\n=> " + e.type + (error ? "#" + errors : "")); 137 | } 138 | function resetSrc() { 139 | img.src = "about:blank"; 140 | setTimeout(function() { 141 | img.src = src; 142 | }, 0); 143 | } 144 | function destroy() { 145 | clearTimeout(stopWaitTimer); 146 | img.removeEventListener("load", check, true); 147 | img.removeEventListener("error", check, true); 148 | if(!--activeAttempts) { 149 | feedback( 150 | failedImages 151 | ? "Done [total: $1, failed: $2]" 152 | : "Done [total: $1]", 153 | [totalImages, failedImages], 154 | true 155 | ); 156 | } 157 | } 158 | img.addEventListener("load", check, true); 159 | img.addEventListener("error", check, true); 160 | var stopWaitTimer = setTimeout(destroy, 8*60e3); 161 | ++activeAttempts; 162 | ++totalImages; 163 | img.forceReload(); 164 | } 165 | function feedback(s, replacements, isLast) { 166 | if("XULBrowserWindow" in window) { 167 | s = _localize(s); 168 | if(replacements) replacements.forEach(function(replacement, i) { 169 | s = s.replace("$" + ++i, replacement); 170 | }); 171 | debug && Services.console.logStringMessage(logPrefix + "feedback():\n" + s); 172 | XULBrowserWindow.setOverLink(feedbackPrefix + s, null); 173 | if(isLast) setTimeout(function() { 174 | XULBrowserWindow.setOverLink("", null); 175 | }, 1500); 176 | } 177 | } 178 | function parseWin(win) { 179 | Array.prototype.forEach.call(win.frames, parseWin); 180 | var doc = win.document; 181 | if("images" in doc) // HTML document 182 | Array.prototype.forEach.call(doc.images, reloadImage); 183 | else { 184 | Array.prototype.forEach.call( 185 | doc.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "img"), 186 | reloadImage 187 | ); 188 | Array.prototype.forEach.call( 189 | doc.getElementsByTagNameNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "image"), 190 | reloadImage 191 | ); 192 | } 193 | } 194 | var feedbackPrefix = _localize("%label%: ") 195 | .replace( 196 | "%label%", 197 | this instanceof XULElement && this.label 198 | || "Reload Broken Images" 199 | ); 200 | parseWin(content); 201 | feedback(totalImages ? "Start reloading: $1" : "Nothing to reload", [totalImages], !totalImages); -------------------------------------------------------------------------------- /Session_Bookmarks/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Session_Bookmarks/icon.png) Session Bookmarks button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Drop-down menu with “session” bookmarks: additionally saves session information (such as scroll position and controls state). 3 |
Use middle-click or left+click with any modifier to add current tab. 4 |
Drag and drop any tab to add new bookmark. 5 |
6 | 7 | ##### Screenshots: 8 | Button context menu  Bookmarks 9 | 10 | Bookmark context menu  Bookmark properties -------------------------------------------------------------------------------- /Session_Bookmarks/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/icon.png -------------------------------------------------------------------------------- /Session_Bookmarks/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/icon.xcf -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmark_context_menu-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmark_context_menu-en.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmark_context_menu-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmark_context_menu-ru.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmark_properties-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmark_properties-en.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmark_properties-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmark_properties-ru.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmarks-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmarks-en.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/bookmarks-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/bookmarks-ru.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/button_context_menu-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/button_context_menu-en.png -------------------------------------------------------------------------------- /Session_Bookmarks/screenshots/button_context_menu-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Session_Bookmarks/screenshots/button_context_menu-ru.png -------------------------------------------------------------------------------- /Show_Anchors/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Show_Anchors/icon.png) Show Anchors button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Show/hide all anchors on the page to easily copy link to some section of the page. 3 |
See bookmarklet with the same name for source code. -------------------------------------------------------------------------------- /Show_Anchors/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Show_Anchors/icon.png -------------------------------------------------------------------------------- /Show_Anchors/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Show_Anchors/icon.xcf -------------------------------------------------------------------------------- /Switch_Keyboard_Layout/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Switch_Keyboard_Layout/icon.png) Switch Keyboard Layout button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Convert text, typed in wrong keyboard layout. 3 |
Configured for Russian ⇄ English, but you can change options inside the code: 4 | ```js 5 | var keybUtils = { 6 | //== Options 7 | ... 8 | //== End of options 9 | ``` -------------------------------------------------------------------------------- /Switch_Keyboard_Layout/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Switch_Keyboard_Layout/icon.png -------------------------------------------------------------------------------- /Switch_Keyboard_Layout/switchKeybLayout.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/switchKeybLayout.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Switch_Keyboard_Layout 3 | 4 | // Switch Keyboard Layout button for Custom Buttons 5 | // (code for "code" section) 6 | 7 | // (c) Infocatcher 2009, 2013-2014 8 | // version 0.2.0 - 2014-10-20 9 | 10 | // Convert text, typed in wrong keyboard layout. 11 | // Configured for Russian <-> English. 12 | 13 | var keybUtils = { 14 | //== Options 15 | noSelBehavior: { // Shift+Home 16 | ctrlKey: false, 17 | altKey: false, 18 | shiftKey: true, 19 | metaKey: false, 20 | keyCode: KeyEvent.DOM_VK_HOME, 21 | charCode: 0 22 | }, 23 | // 0 - do nothing 24 | // 1 - convert all text 25 | // Or use object like following to simulate "keypress" event: 26 | /* 27 | noSelBehavior: { // Ctrl+Shift+Left 28 | ctrlKey: true, 29 | altKey: false, 30 | shiftKey: true, 31 | metaKey: false, 32 | keyCode: KeyEvent.DOM_VK_LEFT, 33 | charCode: 0 34 | } 35 | */ 36 | convTableForward: { // ru -> en 37 | "\"": "@", 38 | ":": "^", 39 | ";": "$", 40 | "?": "&", 41 | ",": "?", 42 | "/": "|", 43 | ".": "/", 44 | "э": "'", 45 | "б": ",", 46 | "ю": ".", 47 | "Ж": ":", 48 | "ж": ";", 49 | "Б": "<", 50 | "Ю": ">", 51 | "Э": "\"", 52 | "х": "[", 53 | "ъ": "]", 54 | "ё": "`", 55 | "Х": "{", 56 | "Ъ": "}", 57 | "Ё": "~", 58 | "№": "#", 59 | "Ф": "A", 60 | "ф": "a", 61 | "И": "B", 62 | "и": "b", 63 | "С": "C", 64 | "с": "c", 65 | "В": "D", 66 | "в": "d", 67 | "У": "E", 68 | "у": "e", 69 | "А": "F", 70 | "а": "f", 71 | "П": "G", 72 | "п": "g", 73 | "Р": "H", 74 | "р": "h", 75 | "Ш": "I", 76 | "ш": "i", 77 | "О": "J", 78 | "о": "j", 79 | "Л": "K", 80 | "л": "k", 81 | "Д": "L", 82 | "д": "l", 83 | "Ь": "M", 84 | "ь": "m", 85 | "Т": "N", 86 | "т": "n", 87 | "Щ": "O", 88 | "щ": "o", 89 | "З": "P", 90 | "з": "p", 91 | "Й": "Q", 92 | "й": "q", 93 | "К": "R", 94 | "к": "r", 95 | "Ы": "S", 96 | "ы": "s", 97 | "Е": "T", 98 | "е": "t", 99 | "Г": "U", 100 | "г": "u", 101 | "М": "V", 102 | "м": "v", 103 | "Ц": "W", 104 | "ц": "w", 105 | "Ч": "X", 106 | "ч": "x", 107 | "Н": "Y", 108 | "н": "y", 109 | "Я": "Z", 110 | "я": "z", 111 | __proto__: null 112 | }, 113 | //== End of options 114 | button: this, 115 | get convTableBackward() { 116 | var ctb = { __proto__: null }; 117 | var ctf = this.convTableForward; 118 | for(var c in ctf) 119 | ctb[ctf[c]] = c; 120 | delete this.convTableBackward; 121 | return this.convTableBackward = ctb; 122 | }, 123 | inPrimaryLayout: function(s) { 124 | for(var i = 0, l = s.length; i < l; ++i) { 125 | var c = s.charAt(i); 126 | if(c in this.convTableForward) 127 | return true; 128 | if(c in this.convTableBackward) 129 | return false; 130 | } 131 | return false; 132 | }, 133 | switchKeybLayout: function(s, convTable) { 134 | var res = ""; 135 | for(var i = 0, l = s.length; i < l; ++i) { 136 | var c = s.charAt(i); 137 | res += c in convTable ? convTable[c] : c; 138 | } 139 | return res; 140 | }, 141 | switchSelKeybLayout: function(_subCall, _focusFixed) { 142 | if( 143 | !_focusFixed 144 | && "closeMenus" in window 145 | && document.commandDispatcher.focusedElement == this.button 146 | ) { 147 | closeMenus(this.button); 148 | setTimeout(function(_this) { 149 | _this.switchSelKeybLayout(_subCall, true); 150 | }, 0, this); 151 | return; 152 | } 153 | var fe = document.commandDispatcher.focusedElement; 154 | if(!fe) 155 | return; 156 | if(fe instanceof HTMLInputElement || fe instanceof HTMLTextAreaElement) { 157 | var ta = fe; 158 | try { 159 | var val = ta.value; 160 | var sel = val.substring(ta.selectionStart, ta.selectionEnd); 161 | } 162 | catch(e) { // Non-text HTMLInputElement 163 | return; 164 | } 165 | if(!sel && val && this.noSelBehavior && !_subCall) { 166 | if(this.noSelBehavior == 1) { 167 | ta.selectionStart = 0; 168 | ta.selectionEnd = val.length; 169 | sel = val; 170 | } 171 | else { 172 | this.handleNoSel(ta); 173 | return; 174 | } 175 | } 176 | if(!sel) 177 | return; 178 | var res = this.switchKeybLayout( 179 | sel, 180 | this.inPrimaryLayout(sel) 181 | ? this.convTableForward 182 | : this.convTableBackward 183 | ); 184 | if(res != sel) 185 | this.insertText(ta, res); 186 | } 187 | else if(fe.contentEditable == "true") { 188 | var doc = fe.ownerDocument; 189 | 190 | var docURI = doc.documentURI; 191 | if( 192 | docURI.substr(0, 5) == "data:" 193 | && docURI.indexOf("chrome://browser/skin/devtools/") != -1 194 | ) { 195 | //~ todo: seems like we only can use paste from clipboard here... 196 | return; 197 | } 198 | 199 | var sel = doc.defaultView.getSelection(); 200 | var rng = sel.rangeCount && sel.getRangeAt(0); 201 | var tmpNode; 202 | if(!rng || rng.collapsed) { 203 | if(!this.noSelBehavior || _subCall) 204 | return; 205 | if(this.noSelBehavior == 1) { 206 | var r = doc.createRange(); 207 | r.selectNodeContents(fe); 208 | sel.removeAllRanges(); 209 | sel.addRange(r); 210 | tmpNode = fe.cloneNode(true); 211 | } 212 | else { 213 | this.handleNoSel(fe); 214 | return; 215 | } 216 | } 217 | else { 218 | tmpNode = doc.createElementNS("http://www.w3.org/1999/xhtml", "div"); 219 | tmpNode.appendChild(rng.cloneContents()); 220 | } 221 | 222 | var orig = tmpNode.innerHTML; 223 | var convTable = this.inPrimaryLayout(tmpNode.textContent) 224 | ? this.convTableForward 225 | : this.convTableBackward; 226 | 227 | var _this = this; 228 | var parseChildNodes = function(node) { 229 | if(node instanceof Element) { 230 | var childNodes = node.childNodes; 231 | for(var i = childNodes.length - 1; i >= 0; --i) 232 | parseChildNodes(childNodes[i]); 233 | } 234 | else if(node.nodeType == node.TEXT_NODE) { 235 | var text = node.nodeValue; 236 | var newText = _this.switchKeybLayout(node.nodeValue, convTable); 237 | if(newText != text) 238 | node.parentNode.replaceChild(doc.createTextNode(newText), node); 239 | } 240 | } 241 | parseChildNodes(tmpNode); 242 | 243 | var res = tmpNode.innerHTML; 244 | if(res != orig) 245 | doc.execCommand("insertHTML", false, res); 246 | } 247 | }, 248 | handleNoSel: function(node) { 249 | this.select(node); 250 | this.switchSelKeybLayout(true); 251 | }, 252 | select: function(node) { 253 | var e = this.noSelBehavior; 254 | if(!e || typeof e != "object") 255 | return; 256 | var evt = document.createEvent("KeyboardEvent"); 257 | evt.initKeyEvent( 258 | "keypress", true /*bubbles*/, true /*cancelable*/, node.ownerDocument.defaultView, 259 | e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, 260 | e.keyCode, e.charCode 261 | ); 262 | node.dispatchEvent(evt); 263 | }, 264 | insertText: function(ta, text) { 265 | var editor = ta.QueryInterface(Components.interfaces.nsIDOMNSEditableElement) 266 | .editor 267 | .QueryInterface(Components.interfaces.nsIPlaintextEditor); 268 | if(editor.flags & editor.eEditorReadonlyMask) 269 | return; 270 | 271 | var sTop = ta.scrollTop; 272 | var sHeight = ta.scrollHeight; 273 | var sLeft = ta.scrollLeft; 274 | // var sWidth = ta.scrollWidth; 275 | 276 | if(text) 277 | editor.insertText(text); 278 | else 279 | editor.deleteSelection(0, 0); 280 | 281 | ta.scrollTop = sTop + (ta.scrollHeight - sHeight); 282 | ta.scrollLeft = sLeft; // + (ta.scrollWidth - sWidth); 283 | } 284 | }; 285 | 286 | var btn = this; 287 | if(btn instanceof XULElement && addEventListener.length > 3) { 288 | addEventListener("command", function(e) { 289 | if(e.target != btn) 290 | return; 291 | e.preventDefault(); 292 | e.stopPropagation(); 293 | keybUtils.switchSelKeybLayout(); 294 | }, true, this.parentNode); 295 | } 296 | keybUtils.switchSelKeybLayout(); -------------------------------------------------------------------------------- /Tabbar_Doubleclick/README.md: -------------------------------------------------------------------------------- 1 | **Tabbar Doubleclick** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Makes double click on tab bar open a new tab -------------------------------------------------------------------------------- /Tabbar_Doubleclick/tabbarDoubleclick.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/tabbarDoubleclick.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Tabbar_Doubleclick 3 | 4 | // Tabbar double click action example for Custom Buttons 5 | // (code for "initialization" section) 6 | // Opens new tab (see "BrowserOpenTab();" in code) after double click on tab bar 7 | 8 | // (c) Infocatcher 2012 9 | // version 0.1.0 - 2012-02-05 10 | 11 | var tabbarHandler = { 12 | init: function() { 13 | addEventListener("dblclick", this, true); 14 | }, 15 | handleEvent: function(e) { 16 | var tabbar = this.getTabbar(e.originalTarget); 17 | if(!tabbar) 18 | return; 19 | e.preventDefault(); 20 | e.stopPropagation(); 21 | e.stopImmediatePropagation && e.stopImmediatePropagation(); 22 | LOG("tabbarHandler => " + e.type + " => BrowserOpenTab()"); 23 | BrowserOpenTab(); 24 | }, 25 | getTabbar: function(it) { 26 | if(!it || !it.localName) 27 | return null; 28 | if(it.namespaceURI != "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") 29 | return null; 30 | var itln = it.localName.toLowerCase(); 31 | if(itln == "toolbarbutton") 32 | return null; 33 | if(itln == "toolbarspacer") { // in Firefox 4 34 | var tabsId = "tabbrowser-tabs"; 35 | for(var tabs = it.nextSibling; tabs; tabs = tabs.nextSibling) { 36 | if(tabs.id == tabsId) 37 | return tabs; 38 | if(tabs.localName != "toolbarspacer") 39 | break; 40 | } 41 | for(var tabs = it.previousSibling; tabs; tabs = tabs.previousSibling) { 42 | if(tabs.id == tabsId) 43 | return tabs; 44 | if(tabs.localName != "toolbarspacer") 45 | break; 46 | } 47 | return null; 48 | } 49 | const docNode = Node.DOCUMENT_NODE; // 9 50 | for(; it && it.nodeType != docNode; it = it.parentNode) { 51 | itln = it.localName.toLowerCase(); 52 | if(itln == "tab" || itln == "toolbarbutton") 53 | return null; 54 | if(/(?:^|\s)tabbrowser-tabs(?:\s|$)/.test(it.className)) 55 | return it; 56 | } 57 | return null; 58 | } 59 | }; 60 | tabbarHandler.init(); -------------------------------------------------------------------------------- /Title_Bar/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Title_Bar/icon.png) Title Bar button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Show window title (if original title was hidden by some reasons) -------------------------------------------------------------------------------- /Title_Bar/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Title_Bar/icon.png -------------------------------------------------------------------------------- /Title_Bar/titleBar.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Title_Bar 2 | 3 | // Title Bar button for Custom Buttons 4 | // (code for "initialization" section) 5 | 6 | // (c) Infocatcher 2010, 2012, 2014 7 | // version 0.2.3.1 - 2014-05-20 8 | 9 | var flexibleWidth = true; 10 | 11 | if( 12 | flexibleWidth 13 | && Array.prototype.some.call( 14 | this.parentNode.childNodes, 15 | function(node) { 16 | if(node == this) 17 | return false; 18 | var flex = node.getAttribute("flex") 19 | || node.ownerDocument.defaultView.getComputedStyle(node, null).MozBoxFlex; 20 | return flex > 0; 21 | }, 22 | this 23 | ) 24 | ) { 25 | LOG("Detected flexible nodes in the button level, will use fixed width"); 26 | flexibleWidth = false; 27 | } 28 | 29 | var titleWidth, titleWidthMin, titleWidthMax, titleWidthCustomize; 30 | if(flexibleWidth) { 31 | titleWidth = "auto"; 32 | titleWidthMin = "100px"; 33 | titleWidthMax = "none"; 34 | titleWidthCustomize = titleWidthMin; 35 | } 36 | else { 37 | titleWidth = titleWidthMin = titleWidthMax = titleWidthCustomize = "350px"; 38 | } 39 | 40 | var root = document.documentElement; 41 | this.__savedTitle = null; 42 | this.__defineSetter__("title", function(val) { 43 | if(val != this.__savedTitle) 44 | this.label = this.tooltipText = this.__savedTitle = val; 45 | }); 46 | 47 | var titleUpdater = { 48 | button: this, 49 | _mo: null, 50 | init: function() { 51 | if("MutationObserver" in window) { 52 | var _this = this; 53 | var mo = this._mo = new MutationObserver(function() { 54 | _this.handleMutations.apply(_this, arguments); 55 | }); 56 | // http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#mutation-observers 57 | mo.observe(root, { 58 | attributes: true, 59 | attributeFilter: ["title"] 60 | }); 61 | } 62 | else { 63 | root.addEventListener("DOMAttrModified", this, true); 64 | } 65 | }, 66 | destroy: function() { 67 | var mo = this._mo; 68 | if(mo) { 69 | this._mo = null; 70 | mo.disconnect(); 71 | } 72 | else { 73 | root.removeEventListener("DOMAttrModified", this, true); 74 | } 75 | }, 76 | handleMutations: function(mutations) { 77 | this.button.title = document.title; 78 | }, 79 | handleEvent: function(e) { 80 | if(e.attrName == "title" && e.originalTarget == root) 81 | this.button.title = e.newValue; 82 | } 83 | }; 84 | 85 | var dragHandler = { 86 | get sm() { 87 | delete this.sm; 88 | return this.sm = Components.classes["@mozilla.org/gfx/screenmanager;1"] 89 | .getService(Components.interfaces.nsIScreenManager); 90 | }, 91 | handleEvent: function(e) { 92 | switch(e.type) { 93 | case "mousedown": 94 | if(e.button != 0) 95 | break; 96 | window.addEventListener("mouseup", this, true); 97 | window.addEventListener("keypress", this, true); 98 | window.addEventListener("mousemove", this, true); 99 | this.pos = { 100 | x: e.screenX, 101 | y: e.screenY 102 | }; 103 | this.winPos = { 104 | x: window.screenX, 105 | y: window.screenY 106 | }; 107 | break; 108 | case "mouseup": 109 | this.stopEvent(e); 110 | this.cancel(); 111 | break; 112 | case "keypress": 113 | if(e.keyCode != e.DOM_VK_ESCAPE) 114 | break; 115 | this.stopEvent(e); 116 | window.moveTo(this.winPos.x, this.winPos.y); 117 | this.cancel(); 118 | break; 119 | case "mousemove": 120 | let x = e.screenX; 121 | let y = e.screenY; 122 | if(this.sm.numberOfScreens == 1) { 123 | let edge = 10; 124 | x = Math.max(screen.availLeft + edge, Math.min(screen.availLeft + screen.availWidth - edge, x)); 125 | y = Math.max(screen.availTop + edge, Math.min(screen.availTop + screen.availHeight - edge, y)); 126 | } 127 | window.moveTo( 128 | this.winPos.x + x - this.pos.x, 129 | this.winPos.y + y - this.pos.y 130 | ); 131 | } 132 | }, 133 | cancel: function() { 134 | window.removeEventListener("mouseup", this, true); 135 | window.removeEventListener("keypress", this, true); 136 | window.removeEventListener("mousemove", this, true); 137 | this.pos = this.winPos = null; 138 | }, 139 | stopEvent: function(e) { 140 | e.preventDefault(); 141 | e.stopPropagation(); 142 | } 143 | }; 144 | addEventListener("mousedown", dragHandler, true, this); 145 | this.ondblclick = function(e) { 146 | if(e.button != 0) 147 | return; 148 | if("fullScreen" in window && window.fullScreen) { 149 | window.fullScreen = false; 150 | return; 151 | } 152 | if(window.windowState != window.STATE_NORMAL) 153 | window.restore(); 154 | else 155 | window.maximize(); 156 | }; 157 | 158 | var s = document.documentElement.style; 159 | var boxShadowPrefix = "boxShadow" in s ? "" : "-moz-"; 160 | var cssStr = ('\ 161 | @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");\n\ 162 | @-moz-document url("' + window.location.href + '") {\n\ 163 | %button% {\n\ 164 | width: ' + titleWidth + ' !important;\n\ 165 | min-width: ' + titleWidthMin + ' !important;\n\ 166 | max-width: ' + titleWidthMax + ' !important;\n\ 167 | -moz-box-flex: 1 !important;\n\ 168 | padding: 1px 3px !important;\n\ 169 | -moz-box-pack: center !important;\n\ 170 | -moz-box-orient: horizontal !important;\n\ 171 | -moz-appearance: none !important;\n\ 172 | }\n\ 173 | %button%,\n\ 174 | %button% > .toolbarbutton-text {\n\ 175 | color: windowText !important;\n\ 176 | text-shadow: window 2px -2px 4px, window -2px 2px 4px, window -2px -4px 4px, window 2px 4px 4px !important;\n\ 177 | background: transparent !important;\n\ 178 | border: none !important;\n\ 179 | ' + boxShadowPrefix + 'box-shadow: none !important;\n\ 180 | }\n\ 181 | %button% > .toolbarbutton-icon {\n\ 182 | display: none !important;\n\ 183 | }\n\ 184 | %button% > .toolbarbutton-text {\n\ 185 | display: -moz-box !important;\n\ 186 | text-align: left !important;\n\ 187 | }\n\ 188 | toolbarpaletteitem > %button% {\n\ 189 | min-width: ' + titleWidthCustomize + ' !important;\n\ 190 | max-width: ' + titleWidthCustomize + ' !important;\n\ 191 | }\n\ 192 | }') 193 | .replace(/%button%/g, "#" + this.id); 194 | 195 | var cssURI = makeURI("data:text/css," + encodeURIComponent(cssStr)); 196 | var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"] 197 | .getService(Components.interfaces.nsIStyleSheetService); 198 | if(!sss.sheetRegistered(cssURI, sss.USER_SHEET)) 199 | sss.loadAndRegisterSheet(cssURI, sss.USER_SHEET); 200 | function removeStyles() { 201 | if(sss.sheetRegistered(cssURI, sss.USER_SHEET)) 202 | sss.unregisterSheet(cssURI, sss.USER_SHEET); 203 | } 204 | 205 | this.title = document.title; 206 | titleUpdater.init(); 207 | 208 | this.onDestroy = function(reason) { 209 | titleUpdater.destroy(); 210 | if(reason == "update" || reason == "delete") 211 | removeStyles() 212 | else if(reason == "constructor" && this.parentNode.nodeName == "toolbar") 213 | setTimeout(removeStyles, 0); // Only for "flexibleWidth = false" hack 214 | }; -------------------------------------------------------------------------------- /Toggle_Find/README.md: -------------------------------------------------------------------------------- 1 | **Toggle Find** button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Toggle find bar and prefill it with selected text -------------------------------------------------------------------------------- /Toggle_Find/toggleFind.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Find 2 | 3 | // (c) Infocatcher 2015 4 | // version 0.1.0 - 2015-09-21 5 | 6 | // Toggle Find button for Custom Buttons 7 | // (code for "code" section) 8 | // Also the code can be used from main window context (as Mouse Gestures code, for example) 9 | 10 | var fb = window.gFindBar || document.getElementById("FindToolbar") || document.getElementsByTagName("findbar")[0]; 11 | if("TabView" in window && TabView.isVisible()) 12 | TabView.enableSearch(); 13 | else { 14 | var handleSelection = function(sel) { 15 | var fv = fb._findField.value; 16 | if(fb.hidden || sel && sel != fv) { 17 | fb._findField.value = sel; 18 | fb.onFindCommand(); 19 | fb._find(); 20 | } 21 | else { 22 | fb.toggleHighlight(false); 23 | fb.close(); 24 | } 25 | }; 26 | if("_getInitialSelection" in fb) 27 | handleSelection(fb._getInitialSelection()); 28 | else { // Firefox 38+ 29 | var finder = fb.browser.finder; 30 | var listener = { 31 | onCurrentSelection: function(sel) { 32 | finder.removeResultListener(listener); 33 | handleSelection(sel); 34 | } 35 | }; 36 | finder.addResultListener(listener); 37 | finder.getInitialSelection(); 38 | } 39 | } -------------------------------------------------------------------------------- /Toggle_Flash/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_Flash/icon.png) Toggle Flash button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Toggle Shockwave Flash plugin. 3 |
Or modify 4 | ```js 5 | var options = { 6 | pluginName: "Shockwave Flash", // Or name of any other plugin 7 | searchInTypes: ["plugin"], // Use "extension" to toggle restartless extensions 8 | ``` 9 | to toggle any other add-on. -------------------------------------------------------------------------------- /Toggle_Flash/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_Flash/icon.png -------------------------------------------------------------------------------- /Toggle_Flash/toggleFlash.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/toggleFlash.js 2 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_Flash 3 | 4 | // Toggle Flash button for Custom Buttons 5 | // (code for "initialization" section) 6 | 7 | // (c) Infocatcher 2012-2015 8 | // version 0.1.4.2 - 2015-05-31 9 | 10 | var options = { 11 | pluginName: Services.appinfo.name == "Pale Moon" ? "Adobe Flash" : "Shockwave Flash", // Or name of any other plugin 12 | searchInTypes: ["plugin"], // Use "extension" to toggle restartless extensions 13 | // Button styles, possible values: 14 | // checked: [true|false] 15 | // style: "any valid CSS" 16 | // iconStyle: "any valid CSS" 17 | // iconGrayscale: [true|false] 18 | // iconOpacity: 0..1 19 | styleEnabled: { 20 | checked: false, 21 | style: "", 22 | iconStyle: "", 23 | iconGrayscale: false, 24 | iconOpacity: 1, 25 | }, 26 | styleClickToPlay: { 27 | checked: false, 28 | style: "", 29 | iconStyle: "", 30 | iconGrayscale: false, 31 | iconOpacity: 0.65 32 | }, 33 | styleDisabled: { 34 | checked: false, 35 | style: "", 36 | iconStyle: "", 37 | iconGrayscale: true, 38 | iconOpacity: 0.65 39 | } 40 | }; 41 | 42 | function _localize(s, key) { 43 | var strings = { 44 | "%N: %S": { // Example: "Some plugin: Enabled" 45 | ru: "%N: %S" 46 | }, 47 | "Enabled": { 48 | ru: "Включено" 49 | }, 50 | "Disabled": { 51 | ru: "Выключено" 52 | }, 53 | "Ask to activate": { 54 | ru: "Включать по запросу" 55 | }, 56 | "Not installed": { 57 | ru: "Не установлено" 58 | } 59 | }; 60 | var locale = (function() { 61 | if("Services" in window && "locale" in Services) { 62 | var locales = Services.locale.requestedLocales // Firefox 64+ 63 | || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales(); 64 | if(locales) 65 | return locales[0]; 66 | } 67 | var prefs = "Services" in window && Services.prefs 68 | || Components.classes["@mozilla.org/preferences-service;1"] 69 | .getService(Components.interfaces.nsIPrefBranch); 70 | function pref(name, type) { 71 | return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined; 72 | } 73 | if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390 74 | var locale = pref("general.useragent.locale", "Char"); 75 | if(locale && locale.substr(0, 9) != "chrome://") 76 | return locale; 77 | } 78 | return Components.classes["@mozilla.org/chrome/chrome-registry;1"] 79 | .getService(Components.interfaces.nsIXULChromeRegistry) 80 | .getSelectedLocale("global"); 81 | })().match(/^[a-z]*/)[0]; 82 | _localize = !locale || locale == "en" 83 | ? function(s) { 84 | return s; 85 | } 86 | : function(s) { 87 | return strings[s] && strings[s][locale] || s; 88 | }; 89 | return _localize.apply(this, arguments); 90 | } 91 | 92 | var _addon, _addonId; 93 | this._pluginDisabled = undefined; 94 | var stateNotInstalled = "notInstalled"; 95 | this.__defineGetter__("pluginDisabled", function() { 96 | return this._pluginDisabled; 97 | }); 98 | this.__defineSetter__("pluginDisabled", function(dis) { 99 | if(this._pluginDisabled == dis) 100 | return; 101 | this._pluginDisabled = dis; 102 | 103 | var style; 104 | var state; 105 | if("STATE_ASK_TO_ACTIVATE" in AddonManager && dis == AddonManager.STATE_ASK_TO_ACTIVATE) { 106 | style = options.styleClickToPlay; 107 | state = _localize("Ask to activate"); 108 | } 109 | else if(!dis) { 110 | style = options.styleEnabled; 111 | state = _localize("Enabled"); 112 | } 113 | else if(dis == stateNotInstalled) { 114 | style = options.styleDisabled; 115 | state = _localize("Not installed"); 116 | } 117 | else { 118 | style = options.styleDisabled; 119 | state = _localize("Disabled"); 120 | } 121 | 122 | if(style.hasOwnProperty("checked")) 123 | this.checked = style.checked; 124 | if(style.hasOwnProperty("style")) 125 | this.style.cssText = style.style; 126 | if( 127 | style.hasOwnProperty("iconStyle") 128 | || style.hasOwnProperty("iconGrayscale") 129 | || style.hasOwnProperty("iconOpacity") 130 | ) { 131 | var icon = this.icon 132 | || this.ownerDocument.getAnonymousElementByAttribute(this, "class", "toolbarbutton-icon"); 133 | if(icon) { 134 | if(style.hasOwnProperty("iconStyle")) 135 | icon.style.cssText = style.iconStyle; 136 | if(style.hasOwnProperty("iconGrayscale")) { 137 | icon.style.filter = style.iconGrayscale 138 | ? "CSS" in window && "supports" in CSS && CSS.supports("filter", "grayscale(1)") 139 | ? "grayscale(1)" 140 | : 'url("chrome://mozapps/skin/extensions/extensions.svg#greyscale")' 141 | : ""; 142 | } 143 | if(style.hasOwnProperty("iconOpacity")) 144 | icon.style.opacity = style.iconOpacity; 145 | } 146 | } 147 | 148 | this.tooltipText = _localize("%N: %S") 149 | .replace("%N", options.pluginName) 150 | .replace("%S", state); 151 | }); 152 | if(!("AddonManager" in window)) 153 | Components.utils.import("resource://gre/modules/AddonManager.jsm"); 154 | 155 | this.initAddonListener = function() { 156 | var addonListener = { 157 | button: this, 158 | onEnabled: function(addon) { 159 | this._updateButton(addon); 160 | }, 161 | onDisabled: function(addon) { 162 | this._updateButton(addon); 163 | }, 164 | onInstalled: function(addon) { 165 | if( 166 | !_addon 167 | && options.searchInTypes.indexOf(addon.type) != -1 168 | && addon.name.indexOf(options.pluginName) != -1 169 | ) { 170 | _addon = addon; 171 | _addonId = addon.id; 172 | this.button.pluginDisabled = addon.userDisabled; 173 | } 174 | }, 175 | onUninstalled: function(addon) { 176 | if(_addon && addon.id == _addonId) { 177 | _addon = _addonId = undefined; 178 | this.button.pluginDisabled = stateNotInstalled; 179 | } 180 | }, 181 | onPropertyChanged: function(addon, properties) { 182 | if(properties && properties.indexOf("userDisabled") != -1) 183 | this._updateButton(addon); 184 | }, 185 | _updateButton: function(addon) { 186 | if(addon.id == _addonId) 187 | this.button.pluginDisabled = addon.userDisabled; 188 | } 189 | }; 190 | AddonManager.addAddonListener(addonListener); 191 | this.onDestroy = function() { 192 | AddonManager.removeAddonListener(addonListener); 193 | }; 194 | }; 195 | 196 | var btn = this; 197 | var then, promise = AddonManager.getAddonsByTypes(options.searchInTypes, then = function(addons) { 198 | addons.some(function(addon) { 199 | if(addon.name.indexOf(options.pluginName) == -1) 200 | return false; 201 | _addon = addon; 202 | _addonId = addon.id; 203 | btn.pluginDisabled = addon.userDisabled; 204 | return true; 205 | }); 206 | if(!_addon) 207 | btn.pluginDisabled = stateNotInstalled; 208 | btn.initAddonListener(); 209 | }); 210 | promise && typeof promise.then == "function" && promise.then(then, Components.utils.reportError); // Firefox 61+ 211 | 212 | this.onclick = function(e) { 213 | if(e.button != 0) 214 | return; 215 | if(!_addon) { 216 | Services.prompt.alert(window, this.label, options.pluginName + " not installed!"); 217 | return; 218 | } 219 | // Note: we manually updates styles because this is a bit faster, than callback in case of addon changes 220 | this.pluginDisabled = setNewDisabled(_addon); 221 | }; 222 | function setNewDisabled(addon) { 223 | var newDis = getNewDisabled(addon); 224 | var oldDis = addon.userDisabled; 225 | addon.userDisabled = newDis; 226 | var realDis = addon.userDisabled; 227 | if(realDis != newDis && "enable" in addon) { // Firefox 62+? Not needed for now, just fail safe 228 | newDis ? addon.disable() : addon.enable(); 229 | realDis = addon.userDisabled; 230 | } 231 | if(realDis != newDis) { // We can't enable vulnerable plugins 232 | var err = "Can't set addon.userDisabled to " + newDis + ", real value: " + realDis; 233 | if(newDis) 234 | Components.utils.reportError(err); 235 | else { 236 | LOG(err + "\nVulnerable plugin?"); 237 | if(oldDis == AddonManager.STATE_ASK_TO_ACTIVATE) 238 | newDis = true; 239 | else 240 | newDis = AddonManager.STATE_ASK_TO_ACTIVATE; 241 | addon.userDisabled = newDis; 242 | } 243 | } 244 | return addon.userDisabled; 245 | } 246 | function getNewDisabled(addon) { 247 | // disabled -> STATE_ASK_TO_ACTIVATE -> enabled -> ... 248 | var curDis = addon.userDisabled; 249 | var newDis; 250 | if("STATE_ASK_TO_ACTIVATE" in AddonManager && curDis == AddonManager.STATE_ASK_TO_ACTIVATE) 251 | newDis = false; 252 | else if(!curDis) 253 | newDis = true; 254 | else { 255 | if(isAskToActivateAddon(addon)) 256 | newDis = AddonManager.STATE_ASK_TO_ACTIVATE; 257 | else 258 | newDis = false; 259 | } 260 | return newDis; 261 | } 262 | function isAskToActivateAddon(addon) { 263 | return addon.type == "plugin" 264 | && "STATE_ASK_TO_ACTIVATE" in AddonManager 265 | && Services.prefs.getBoolPref("plugins.click_to_play", true); 266 | } -------------------------------------------------------------------------------- /Toggle_GIF_Animation/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_GIF_Animation/icon.png) Toggle GIF Animation button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Disable or enable GIF animation on current page. 3 |
You can use old version for hotkeys or mouse gestures. -------------------------------------------------------------------------------- /Toggle_GIF_Animation/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_GIF_Animation/icon.png -------------------------------------------------------------------------------- /Toggle_GIF_Animation/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_GIF_Animation/icon.xcf -------------------------------------------------------------------------------- /Toggle_GIF_Animation/icon_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_GIF_Animation/icon_enabled.png -------------------------------------------------------------------------------- /Toggle_GIF_Animation/toggleGifAnimation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Toggle GIF Animation [0.3.0 - 2020-02-25] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Toggle_GIF_Animation/toggleGifAnimation.js: -------------------------------------------------------------------------------- 1 | // http://infocatcher.ucoz.net/js/cb/toggleGifAnimation.js 2 | // https://forum.mozilla-russia.org/viewtopic.php?id=57977 3 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toggle_GIF_Animation 4 | 5 | // Toggle GIF Animation button for Custom Buttons 6 | // (code for "initialization" section) 7 | 8 | // (c) Infocatcher 2013-2020 9 | // version 0.3.0 - 2020-02-25 10 | 11 | // Tip: use image.animation_mode = none to disable animation by default 12 | // http://kb.mozillazine.org/Firefox_:_Tips_:_Animated_Images#Image_animation_preference 13 | 14 | var gifAnimation = this.gifAnimation = { 15 | // Note: we use original button's icon to indicate disabled state 16 | iconEnabled: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABlElEQVR4nI2SsUsCcRTHv+/yJGzS4kCRWqqpQ5xahYwER/8CGxoPh2rxP6itWXLQKQiXGiQh3JrUKYgIogbvQBwMTTB/r8XfeXde5BcOfvd+733e9/d+P2JmAEC5XN7MZrN3RKRiJiKCVzKfmZ81TctRt14Ro9uLxUwfhXLnWEkeSYipaVoUrXSYX/O77NTbic7MzO/HO654Kx1my7LYsiw2TbPLzAgAwPb1C9qHkYWO/Y8etgDXnjyClOItSj707fX38MeOOePMbIMCmHVwJtiA0RQA0EisgRRCZCPoKgYA6tYrontpLDXE6NkVWD+whxiLxaIkaaVSaT+TyTwB8+v75xrNeDweDTg3hBCuIu/A/EAugPyWdLAIkA4k5C8HzrgvwFvsB1twIIRwAZxyAprNJgaDAQA0CoXC/CFJB0IITKdTe+39b7fb6HQ6N7VaLW87MAyDUqkUCSGYZu39BggAk8nkMZFInOq6HioWi0NiZlSr1XUiyqmqukdEEQCrAEIAgo5aAeBrPB6PFEXpAfgEcP8LWVgYRnUM0zMAAAAASUVORK5CYII=", 17 | 18 | remote: window.gMultiProcessBrowser, 19 | button: this, 20 | getUtils: function(win) { 21 | return win.windowUtils || win.QueryInterface(Components.interfaces.nsIInterfaceRequestor) 22 | .getInterface(Components.interfaces.nsIDOMWindowUtils); 23 | }, 24 | get mode() { 25 | var utils = this.getUtils(content); 26 | return utils.imageAnimationMode; 27 | }, 28 | set mode(mode) { 29 | this.setMode(content, mode); 30 | this.updateState(mode); 31 | }, 32 | toggle: function() { 33 | if(this.remote) { 34 | this.toggleRemote(); 35 | return; 36 | } 37 | var ic = Components.interfaces.imgIContainer; 38 | this.mode = this.mode == ic.kNormalAnimMode 39 | ? ic.kDontAnimMode 40 | : ic.kNormalAnimMode; 41 | }, 42 | toggleRemote: function() { 43 | this.loadFrameScript(function() { 44 | var ic = Components.interfaces.imgIContainer; 45 | var mode = content.windowUtils.imageAnimationMode == ic.kNormalAnimMode ? ic.kDontAnimMode : ic.kNormalAnimMode; 46 | (function setMode(win) { 47 | try { 48 | win.windowUtils.imageAnimationMode = mode; 49 | } 50 | catch(e) { // NS_ERROR_NOT_AVAILABLE 51 | } 52 | Array.prototype.forEach.call(win.frames, setMode); 53 | })(content); 54 | sendAsyncMessage("CB:ToggleGIFAnimation:mode", mode); 55 | }); 56 | }, 57 | setMode: function(win, mode) { 58 | Array.prototype.forEach.call(win.frames, function(win) { 59 | this.setMode(win, mode); 60 | }, this); 61 | var utils = this.getUtils(win); 62 | try { 63 | utils.imageAnimationMode = mode; 64 | } 65 | catch(e) { // NS_ERROR_NOT_AVAILABLE 66 | } 67 | }, 68 | updateState: function(mode) { 69 | if(mode === undefined && this.remote) { 70 | this.updateStateRemote(); 71 | return; 72 | } 73 | if(mode === undefined) 74 | mode = this.mode; 75 | var btn = this.button; 76 | var icon = btn.icon 77 | || btn.ownerDocument.getAnonymousElementByAttribute(btn, "class", "toolbarbutton-icon"); 78 | icon.src = mode == Components.interfaces.imgIContainer.kDontAnimMode 79 | ? btn.image 80 | : this.iconEnabled; 81 | }, 82 | updateStateRemote: function() { 83 | this.loadFrameScript(function() { 84 | try { 85 | var mode = content.windowUtils.imageAnimationMode; 86 | } 87 | catch(e) { // NS_ERROR_NOT_AVAILABLE 88 | } 89 | sendAsyncMessage("CB:ToggleGIFAnimation:mode", mode); 90 | }); 91 | }, 92 | loadFrameScript: function(fn) { 93 | var code = "(" + fn + ")();"; 94 | var data = "data:application/javascript," + encodeURIComponent(code); 95 | var mm = gBrowser.selectedBrowser.messageManager; 96 | var _this = this; 97 | mm.addMessageListener("CB:ToggleGIFAnimation:mode", function receiveMessage(msg) { 98 | mm.removeMessageListener("CB:ToggleGIFAnimation:mode", receiveMessage); 99 | if(msg.data != null) 100 | _this.updateState(msg.data); 101 | }); 102 | mm.loadFrameScript(data, false); 103 | }, 104 | _updateStateTimer: 0, 105 | updateStateDelayed: function() { 106 | if(this._updateStateTimer) 107 | return; 108 | this._updateStateTimer = setTimeout(function(_this) { 109 | _this._updateStateTimer = 0; 110 | _this.updateState(); 111 | }, 20, this); 112 | } 113 | }; 114 | 115 | this.setAttribute("oncommand", "this.gifAnimation.toggle();"); 116 | 117 | var progressListener = { 118 | onLocationChange: function(aWebProgress, aRequest, aLocation) { 119 | gifAnimation.updateStateDelayed(); 120 | } 121 | }; 122 | //progressListener.onStateChange = 123 | // progressListener.onProgressChange = 124 | // progressListener.onStatusChange = 125 | // progressListener.onSecurityChange = function dummy() {}; 126 | 127 | gifAnimation.updateStateDelayed(); 128 | gBrowser.addProgressListener(progressListener); 129 | this.onDestroy = function() { 130 | gBrowser.removeProgressListener(progressListener); 131 | }; -------------------------------------------------------------------------------- /Toggle_Restartless_Add-ons/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Toggle_Restartless_Add-ons/icon.png) Toggle Restartless Add-ons button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Drop-down menu to toggle restartless add-ons 3 |
4 |
Usage: 5 |
Left-click – open drop-down menu 6 |
Middle-click or left-click with any modifier – open Add-ons Manager 7 |
In menu: 8 |
Left-click – toggle enabled/disabled 9 |
Shift+left-click – toggle enabled/disabled and don't close menu 10 |
Middle-click or left-click with any modifier (except Shift) – open add-on page 11 |
Right-click – open add-on options (if any) 12 | 13 | ##### Screenshot: 14 | Button menu -------------------------------------------------------------------------------- /Toggle_Restartless_Add-ons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_Restartless_Add-ons/icon.png -------------------------------------------------------------------------------- /Toggle_Restartless_Add-ons/toggleRestartlessAddons-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_Restartless_Add-ons/toggleRestartlessAddons-en.png -------------------------------------------------------------------------------- /Toggle_Restartless_Add-ons/toggleRestartlessAddons-ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Toggle_Restartless_Add-ons/toggleRestartlessAddons-ru.png -------------------------------------------------------------------------------- /Toolbar_Flexible_Space/README.md: -------------------------------------------------------------------------------- 1 | Toolbar Flexible Space button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Just looks like toolbar flexible space, may be useful in Firefox 29+ (Australis) -------------------------------------------------------------------------------- /Toolbar_Flexible_Space/toolbarFlexibleSpace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Toolbar Flexible Space [0.1.0 - 2014-05-12] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Toolbar_Flexible_Space/toolbarFlexibleSpace.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toolbar_Flexible_Space 2 | 3 | // Toolbar Flexible Space button for Custom Buttons 4 | // (code for "initialization" section) 5 | 6 | // (c) Infocatcher 2014 7 | // version 0.1.0 - 2014-05-12 8 | 9 | this.tooltipText = ""; // Remove tooltip 10 | this.style.cssText = '\ 11 | /* styles for toolbarspring from chrome://global/skin/toolbar.css */\n\ 12 | -moz-box-flex: 1000;\n\ 13 | /* Remove button styles */\n\ 14 | -moz-appearance: listitem !important; /* Hack, try use "none" in case of wrong appearance */\n\ 15 | list-style-image: none !important;\n\ 16 | margin: 0 !important;\n\ 17 | padding: 0 !important;\n\ 18 | /* Force make it accessible anyway */\n\ 19 | min-width: 4px !important;\n\ 20 | '; 21 | this.setAttribute("flex", "1"); 22 | setTimeout(function() { // Force hide icon 23 | var icon = self.icon 24 | || self.ownerDocument.getAnonymousElementByAttribute(self, "class", "toolbarbutton-icon"); 25 | icon.style.display = "none"; 26 | }, 50); -------------------------------------------------------------------------------- /Toolbar_Separator/README.md: -------------------------------------------------------------------------------- 1 | Toolbar Separator button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Just looks like toolbar separator, may be useful in Firefox 29+ (Australis) -------------------------------------------------------------------------------- /Toolbar_Separator/toolbarSeparator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Toolbar Separator [0.1.0 - 2014-05-12] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Toolbar_Separator/toolbarSeparator.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toolbar_Separator 2 | 3 | // Toolbar Separator button for Custom Buttons 4 | // (code for "initialization" section) 5 | 6 | // (c) Infocatcher 2014 7 | // version 0.1.0 - 2014-05-12 8 | 9 | this.tooltipText = ""; // Remove tooltip 10 | this.style.cssText = '\ 11 | /* styles for toolbarseparator from chrome://global/skin/toolbar.css */\n\ 12 | -moz-appearance: separator !important;\n\ 13 | border-top: 2px solid transparent;\n\ 14 | border-bottom: 2px solid transparent;\n\ 15 | border-left: 3px solid transparent;\n\ 16 | border-right: 3px solid transparent;\n\ 17 | -moz-border-left-colors : transparent transparent ThreeDShadow;\n\ 18 | -moz-border-right-colors : transparent transparent ThreeDHighlight;\n\ 19 | /* Remove button styles */\n\ 20 | list-style-image: none !important;\n\ 21 | margin: 0 !important;\n\ 22 | padding: 0 !important;\n\ 23 | '; 24 | setTimeout(function() { // Force hide icon 25 | var icon = self.icon 26 | || self.ownerDocument.getAnonymousElementByAttribute(self, "class", "toolbarbutton-icon"); 27 | icon.style.display = "none"; 28 | }, 50); -------------------------------------------------------------------------------- /Toolbar_Space/README.md: -------------------------------------------------------------------------------- 1 | Toolbar Space button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Just looks like toolbar space, may be useful in Firefox 29+ (Australis) -------------------------------------------------------------------------------- /Toolbar_Space/toolbarSpace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Toolbar Space [0.1.0 - 2014-05-12] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /Toolbar_Space/toolbarSpace.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/Toolbar_Space 2 | 3 | // Toolbar Space button for Custom Buttons 4 | // (code for "initialization" section) 5 | 6 | // (c) Infocatcher 2014 7 | // version 0.1.0 - 2014-05-12 8 | 9 | this.tooltipText = ""; // Remove tooltip 10 | this.style.cssText = '\ 11 | /* styles for toolbarspacer from chrome://global/skin/toolbar.css */\n\ 12 | width: 15px;\n\ 13 | /* Remove button styles */\n\ 14 | -moz-appearance: listitem !important; /* Hack, try use "none" in case of wrong appearance */\n\ 15 | list-style-image: none !important;\n\ 16 | margin: 0 !important;\n\ 17 | padding: 0 !important;\n\ 18 | '; 19 | setTimeout(function() { // Force hide icon 20 | var icon = self.icon 21 | || self.ownerDocument.getAnonymousElementByAttribute(self, "class", "toolbarbutton-icon"); 22 | icon.style.display = "none"; 23 | }, 50); -------------------------------------------------------------------------------- /Undo_Close_Tabs/README.md: -------------------------------------------------------------------------------- 1 | ![icon](https://raw.github.com/Infocatcher/Custom_Buttons/master/Undo_Close_Tabs/icons/icon.png) Undo Close Tabs button for [Custom Buttons](https://addons.mozilla.org/addon/custom-buttons/) 2 |
Allows restore recently closed tabs and windows -------------------------------------------------------------------------------- /Undo_Close_Tabs/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Undo_Close_Tabs/icons/icon.png -------------------------------------------------------------------------------- /Undo_Close_Tabs/icons/merged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Undo_Close_Tabs/icons/merged.png -------------------------------------------------------------------------------- /Undo_Close_Tabs/icons/merged.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Infocatcher/Custom_Buttons/42f096e4470ea06c623c9b60761c81f07df47d46/Undo_Close_Tabs/icons/merged.xcf -------------------------------------------------------------------------------- /code_snippets/README.md: -------------------------------------------------------------------------------- 1 | This is some code snippets related to Custom Buttons. 2 | 3 | ###### autoOpenCloseMenu.js 4 | Automatically open menu on mouse over (and hide it on mouse out) 5 | 6 | ###### customizableUI.js 7 | Dummy wrapper to create Custom Buttons using CustomizableUI.jsm 8 | 9 | ###### menuWithDelayedInitialization.js 10 | Example menu with delayed initialization, install page 11 | 12 | ###### mergeInitialization.js 13 | Example for safely use only one button for initialization of many “buttons” without UI 14 | 15 | ###### multilinePrompt.js 16 | Multiline prompt example: opens custom dialog like built-in prompt() function 17 | 18 | ###### oneTimeCommand.js 19 | Lazy initialize button using “code” section 20 | 21 | ###### prefNS.js 22 | Get unique preferences root for each button 23 | 24 | ###### prefs.js 25 | Simple preferences, that syncs with about:config 26 |
Warning: this is test version, use at your own risk! -------------------------------------------------------------------------------- /code_snippets/autoOpenCloseMenu.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/autoOpenCloseMenu.js 2 | // Automatically open menu on mouse over (and hide it on mouse out) 3 | // (code for "initialization" section) 4 | 5 | // Dummy menu 6 | this.type = "menu"; 7 | this.orient = "horisontal"; 8 | this.appendChild(parseXULFromString( 9 | '\ 10 | \ 11 | \ 12 | \ 13 | ' 14 | )); 15 | function parseXULFromString(xul) { 16 | xul = xul.replace(/>\s+<"); 17 | try { 18 | return new DOMParser().parseFromString(xul, "application/xml").documentElement; 19 | } 20 | catch(e) { 21 | // See http://custombuttons.sourceforge.net/forum/viewtopic.php?f=5&t=3720 22 | // + https://forum.mozilla-russia.org/viewtopic.php?pid=732243#p732243 23 | var dummy = document.createElement("dummy"); 24 | dummy.innerHTML = xul.trimLeft(); 25 | return dummy.firstChild; 26 | } 27 | } 28 | 29 | // Autoopen/close feature 30 | var openDelay = 200; 31 | var closeDelay = 350; 32 | 33 | var _openTimer = 0; 34 | var _closeTimer = 0; 35 | this.onmouseover = function(e) { 36 | clearTimeout(_closeTimer); 37 | if(e.target == this && closeOtherMenus()) { 38 | this.open = true; 39 | return; 40 | } 41 | _openTimer = setTimeout(function() { 42 | self.open = true; 43 | }, openDelay); 44 | }; 45 | this.onmouseout = function(e) { 46 | clearTimeout(_openTimer); 47 | _closeTimer = setTimeout(function() { 48 | if(!isContextOpened()) 49 | self.open = false; 50 | }, closeDelay); 51 | }; 52 | function closeOtherMenus() { 53 | return Array.prototype.some.call( 54 | self.parentNode.getElementsByTagName("*"), 55 | function(node) { 56 | if( 57 | node != self 58 | && node.namespaceURI == xulns 59 | // See https://github.com/Infocatcher/Custom_Buttons/issues/28 60 | //&& node.boxObject 61 | //&& node.boxObject instanceof Components.interfaces.nsIMenuBoxObject 62 | && "open" in node 63 | && node.open 64 | && node.getElementsByTagName("menupopup").length 65 | ) { 66 | node.open = false; 67 | return true; 68 | } 69 | return false; 70 | } 71 | ); 72 | } 73 | function isContextOpened() { 74 | return inBtn(document.popupNode); 75 | } 76 | function inBtn(node) { 77 | for(; node; node = node.parentNode) 78 | if(node == self) 79 | return true; 80 | return false; 81 | } -------------------------------------------------------------------------------- /code_snippets/customizableUI.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/CustomizableUI.js 2 | // Dummy wrapper to create Custom Buttons using CustomizableUI.jsm 3 | // https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm 4 | 5 | //== Configuration begin 6 | CustomButton({ 7 | id: "someCustomButton", // Unique identifier 8 | fileInit: "someCustomButton.js", // Relative path to script file or empty string ("") 9 | fileCode: "", // Relative path to script file or empty string ("") 10 | label: "Button name", 11 | tooltip: "Button tooltip", 12 | icon: "chrome://branding/content/icon16.png", 13 | // https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm#Area_constants 14 | defaultArea: CustomizableUI.AREA_NAVBAR // Default toolbar 15 | }); 16 | //== Configuration end 17 | 18 | function CustomButton(cb) { 19 | var cbEnv = { 20 | xulns: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 21 | xhtmlns: "http://www.w3.org/1999/xhtml", 22 | LOG: function(msg) { 23 | var head = "[Custom Buttons CustomizableUI.jsm: id: " + this._id + "@" + this._phase 24 | + ", line: " + Components.stack.caller.lineNumber + "]"; 25 | Services.console.logStringMessage(head + "\n" + msg); 26 | } 27 | }; 28 | 29 | var path = new Error().fileName.replace(/[^\\\/]*$/, ""); 30 | function cbExec(cb, win, btn, codeEvent) { 31 | // Note: be careful with global variables inside cb-script 32 | var context = Object.assign(btn, cbEnv, { 33 | _id: btn.id, 34 | _phase: codeEvent ? "code" : "init", 35 | event: codeEvent || new win.Object(), 36 | self: btn 37 | }); 38 | context.LOG = context.LOG.bind(context); 39 | Object.defineProperty(context, "top", { value: win.top }); 40 | var file = path + (codeEvent ? cb.fileCode : cb.fileInit); 41 | context.LOG("cbExec()\n" + file); 42 | Services.scriptloader.loadSubScript(file, context, "UTF-8"); 43 | } 44 | 45 | (CustomButton = function(cb) { 46 | CustomizableUI.createWidget({ 47 | id: "__cb_" + cb.id, 48 | type: "custom", 49 | defaultArea: cb.defaultArea, 50 | onBuild: function(doc) { 51 | var btn = doc.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbarbutton"); 52 | var id = cbEnv._id = this.id; 53 | var attrs = { 54 | id: id, 55 | class: "toolbarbutton-1 chromeclass-toolbar-additional", 56 | label: cb.label, 57 | tooltiptext: cb.tooltip, 58 | style: 'list-style-image: url("' + cb.icon + '");', 59 | __proto__: null 60 | }; 61 | for(var p in attrs) 62 | btn.setAttribute(p, attrs[p]); 63 | var win = doc.defaultView; 64 | cb.fileCode && btn.addEventListener("command", function(e) { 65 | cbExec(cb, win, btn, e); 66 | }, false); 67 | cb.fileInit && win.setTimeout(function() { 68 | cbExec(cb, win, btn, false); 69 | }, 0); 70 | return btn; 71 | } 72 | }); 73 | })(cb); 74 | } -------------------------------------------------------------------------------- /code_snippets/menuWithDelayedInitialization.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example: menu with delayed initialization [0.1.1 - 2013-02-08] 4 | 5 | Install 7 | | Source 8 | | Instructions 9 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /code_snippets/menuWithDelayedInitialization.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/menuWithDelayedInitialization.js 2 | 3 | // Example menu button for Custom Buttons 4 | // Code for "code" and "initialization" sections (see comments) 5 | 6 | // (c) Infocatcher 2013 7 | // version 0.1.1 - 2013-02-08 8 | 9 | 10 | //== "Code" section: 11 | if(!event.target) { // Button's hotkey pressed 12 | LOG("hotkey"); 13 | this.open = true; 14 | return; 15 | } 16 | if(event.target != this) { 17 | LOG("code() from child node"); 18 | return; 19 | } 20 | LOG("code()"); 21 | var mp = this.mp; // See initialization 22 | addEventListener("command", function(e) { 23 | // Button shouldn't handle "command" event from child nodes 24 | e.stopPropagation(); 25 | }, false, mp); 26 | // Create menu contents (just an example): 27 | var df = document.createDocumentFragment(); 28 | for(var i = 1; i <= 10; ++i) { 29 | var mi = document.createElement("menuitem"); 30 | mi.setAttribute("label", "Item #" + i); 31 | mi.setAttribute("oncommand", "this.parentNode.parentNode.handleCommand(" + i + ");"); 32 | df.appendChild(mi); 33 | } 34 | mp.appendChild(df); 35 | this.handleCommand = function(i) { 36 | alert("Command #" + i); 37 | }; 38 | 39 | 40 | //============================ 41 | //== "Initialization" section: 42 | LOG("init()"); 43 | this.type = "menu"; 44 | this.orient = "horizontal"; 45 | var mp = this.mp = document.createElement("menupopup"); 46 | mp.setAttribute("onpopupshowing", "this.parentNode.initMenuOnce();"); 47 | this.appendChild(mp); 48 | 49 | this.initMenuOnce = function() { 50 | LOG("onpopupshowing"); 51 | delete this.initMenuOnce; 52 | // Looks like Gecko bug: handler can't be removed using removeAttribute() 53 | mp.setAttribute("onpopupshowing", ""); 54 | mp.removeAttribute("onpopupshowing"); 55 | this.doCommand(); 56 | }; -------------------------------------------------------------------------------- /code_snippets/mergeInitialization.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/mergeInitialization.js 2 | // Example for safely use only one button for initialization of many "buttons" without UI 3 | 4 | var _destructors = []; 5 | function destructor() { 6 | var args = arguments; 7 | _destructors.forEach(function(destructor) { 8 | try { 9 | destructor.apply(this, args); 10 | } 11 | catch(e) { 12 | Components.utils.reportError(e); 13 | } 14 | }, this); 15 | } 16 | if("defineProperty" in Object) { // Firefox 4+ 17 | Object.defineProperty(this, "onDestroy", { 18 | get: function() { 19 | return _destructors.length ? destructor : undefined; 20 | }, 21 | set: function(f) { 22 | _destructors.push(f); 23 | }, 24 | enumerable: true, 25 | configurable: true 26 | }); 27 | } 28 | else { 29 | this.__defineGetter__("onDestroy", function() { 30 | return _destructors.length ? destructor : undefined; 31 | }); 32 | this.__defineSetter__("onDestroy", function(f) { 33 | _destructors.push(f); 34 | }); 35 | } 36 | 37 | // Usage example: 38 | (function() { 39 | // Some code #1 40 | LOG("Initialize button #1"); 41 | function destructor(reason) { 42 | LOG("onDestroy #1 " + reason); 43 | } 44 | this.onDestroy = destructor; 45 | }).apply(this, arguments); 46 | 47 | (function() { 48 | // Some code #2 49 | LOG("Initialize button #2"); 50 | function destructor(reason) { 51 | LOG("onDestroy #2 " + reason); 52 | } 53 | this.onDestroy = destructor; 54 | }).apply(this, arguments); 55 | 56 | (function() { 57 | // Code of any button without UI here 58 | }).apply(this, arguments); 59 | 60 | // ... -------------------------------------------------------------------------------- /code_snippets/multilinePrompt.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/multilinePrompt.js 2 | // Multiline prompt example: opens custom dialog like built-in prompt() function 3 | // Note: may be used not only in Custom Buttons :) 4 | 5 | function multilinePrompt(title, desc, defaultVal) { 6 | function encodeHTML(s, isAttr) { 7 | s = String(s) 8 | .replace(/&/g, "&") 9 | .replace(//g, ">") 11 | .replace(/"/g, """); 12 | if(isAttr) { 13 | s = s 14 | .replace(/\t/g, " ") 15 | .replace(/\n/g, " ") 16 | .replace(/\r/g, " "); 17 | } 18 | return s; 19 | } 20 | var xul = '\n\ 21 | \n\ 22 | \n\ 28 | '; 40 | var data = "data:application/vnd.mozilla.xul+xml," + encodeURIComponent(xul); 41 | var out = { value: null }; 42 | window.openDialog(data, "_blank", "chrome,all,resizable,centerscreen,modal", out); 43 | return out.value; 44 | } 45 | 46 | // Usage example: 47 | var text = multilinePrompt("Example", "Type some text here:", "Example\ndata..."); 48 | alert(text); -------------------------------------------------------------------------------- /code_snippets/oneTimeCommand.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/oneTimeCommand.js 2 | // Lazy initialize button using "code" section 3 | 4 | // Some initialization 5 | function action() { 6 | alert("action()"); 7 | } 8 | 9 | // Prevent subsequent execution of code from button's "code" section 10 | var btn = this; 11 | addEventListener("command", function(e) { 12 | if(e.target != btn) 13 | return; 14 | e.preventDefault(); 15 | e.stopPropagation(); 16 | // Called after second and following clicks on the button: 17 | alert("Catch command: don't initialize twice"); 18 | action(); 19 | }, true, this.parentNode); 20 | 21 | // Called only after first click on the button: 22 | alert("Initialize"); 23 | action(); -------------------------------------------------------------------------------- /code_snippets/prefNS.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/prefNS.js 2 | // Get unique preferences root for each button 3 | 4 | const prefNS = (function() { 5 | const buttonId = "coolButton"; // Human-readable "name" of button 6 | var btnNum = "." + this.id.match(/\d*$/)[0]; 7 | var appInfo = Components.classes["@mozilla.org/xre/app-info;1"] 8 | .getService(Components.interfaces.nsIXULAppInfo); 9 | var windowId = custombuttons.cbService.getWindowId(document.documentURI); 10 | if(windowId != appInfo.name) { 11 | windowId = windowId.substr(appInfo.name.length); 12 | btnNum += "." + windowId.charAt(0).toLowerCase() + windowId.substr(1); 13 | } 14 | return "extensions.custombuttons.buttons." + buttonId + btnNum + "."; 15 | }).call(this); 16 | 17 | alert(prefNS); -------------------------------------------------------------------------------- /code_snippets/prefs.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/prefs.js 2 | // Simple preferences, that syncs with about:config 3 | // Warning: this is test version, use at your own risk! 4 | 5 | const prefNS = "extensions.custombuttons.buttons.coolButton."; 6 | // Also see https://github.com/Infocatcher/Custom_Buttons/blob/master/code_snippets/prefNS.js 7 | // for better namespace, if you wish to use many copies of button 8 | 9 | // Some options: 10 | var options = { 11 | a: 0, 12 | b: 1, 13 | sub: { 14 | c: 2, 15 | d: "something", 16 | e: true 17 | }, 18 | array: ["a", "b"], 19 | pattern: /^some RegExp/i 20 | }; 21 | makePrefable(this, options, prefNS); 22 | 23 | // Now just use options.a to get (possible changed) value: 24 | alert(options.a); 25 | 26 | function makePrefable(btn, options, ns) { 27 | var prefs = Components.classes["@mozilla.org/preferences-service;1"] 28 | .getService(Components.interfaces.nsIPrefService) 29 | .QueryInterface(Components.interfaces.nsIPrefBranch2 || Components.interfaces.nsIPrefBranch); 30 | var db = prefs.getDefaultBranch(""); 31 | parseObject(options, ns); 32 | if(btn && btn instanceof XULElement && "init" in btn && "destroy" in btn) { 33 | sync.__timer = 0; 34 | var syncObserver = { observe: sync }; 35 | prefs.addObserver(ns, syncObserver, false); 36 | addDestructor(function() { 37 | prefs.removeObserver(ns, syncObserver); 38 | }); 39 | } 40 | function parseObject(o, base) { 41 | for(var p in o) if(o.hasOwnProperty(p)) { 42 | var v = o[p]; 43 | var t = typeof v; 44 | if( 45 | t == "boolean" || t == "number" || t == "string" 46 | || v instanceof Array 47 | || v instanceof RegExp 48 | ) 49 | makeGetter(o, p, base + p, v); 50 | else if(v && t == "object") 51 | parseObject(v, base + p + "."); 52 | } 53 | } 54 | function makeGetter(o, p, n, dv) { 55 | o.__defineGetter__(p, function() { 56 | var v = get(n, dv); 57 | delete o[p]; 58 | return o[p] = v == dv ? v : parse(v, dv); 59 | }); 60 | setTimeout(function() { 61 | set(n, serialize(dv), db); 62 | }, 10); 63 | } 64 | function parse(v, dv) { 65 | if(dv instanceof Array) 66 | return JSON.parse(v); 67 | if(dv instanceof RegExp && /^\/(.+)\/(\w+)$/.test(v)) 68 | return new RegExp(RegExp.$1, RegExp.$2); 69 | return v; 70 | } 71 | function serialize(v) { 72 | if(v instanceof Array) 73 | return JSON.stringify(v); 74 | if(v instanceof RegExp) 75 | return "" + v; 76 | return v; 77 | } 78 | function sync(subject, topic, n) { 79 | clearTimeout(sync.__timer); 80 | sync.__timer = setTimeout(function() { 81 | btn.destroy("update"); 82 | btn.init(); 83 | }, 50); 84 | } 85 | function get(n, dv, pb) { 86 | var ps = pb || prefs; 87 | switch(ps.getPrefType(n)) { 88 | case ps.PREF_BOOL: return ps.getBoolPref(n); 89 | case ps.PREF_INT: return ps.getIntPref(n); 90 | case ps.PREF_STRING: return ps.getComplexValue(n, Components.interfaces.nsISupportsString).data; 91 | } 92 | return dv; 93 | } 94 | function set(n, v, pb) { 95 | var ps = pb || prefs; 96 | var pType = ps.getPrefType(n); 97 | if(pType == ps.PREF_INVALID) 98 | pType = getValueType(v); 99 | switch(pType) { 100 | case ps.PREF_BOOL: ps.setBoolPref(n, v); break; 101 | case ps.PREF_INT: ps.setIntPref(n, v); break; 102 | case ps.PREF_STRING: 103 | var ss = Components.interfaces.nsISupportsString; 104 | var s = Components.classes["@mozilla.org/supports-string;1"] 105 | .createInstance(ss); 106 | s.data = v; 107 | ps.setComplexValue(n, ss, s); 108 | } 109 | } 110 | function getValueType(v) { 111 | switch(typeof v) { 112 | case "boolean": return prefs.PREF_BOOL; 113 | case "number": return prefs.PREF_INT; 114 | } 115 | return prefs.PREF_STRING; 116 | } 117 | } -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | This is some buttons for test purposes, for Custom Buttons extension. 2 | 3 | ###### dndTest.js 4 | Writes information about dragged data into Error Console, so you can see all available data types -------------------------------------------------------------------------------- /tests/dndTest.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Infocatcher/Custom_Buttons/tree/master/tests 2 | 3 | // Drag-And-Drop Test button for Custom Buttons 4 | // Code for "code" section 5 | 6 | // Writes information about dragged data into Error Console 7 | // (disabled by default, left-click to enable/disable) 8 | 9 | // (c) Infocatcher 2013-2014 10 | // version 0.1.1 - 2014-03-07 11 | 12 | if("__dndTest" in this) { 13 | this.checked = false; 14 | removeEventListener("dragstart", this.__dndTest, true); 15 | removeEventListener("drop", this.__dndTest, true); 16 | delete this.__dndTest; 17 | } 18 | else { 19 | this.checked = true; 20 | this.__dndTest = function(e) { 21 | var dt = e.dataTransfer; 22 | setTimeout(function() { 23 | var types = dt.types; 24 | var c = dt.itemCount || dt.mozItemCount; 25 | var r = []; 26 | for(var i = 0, li = types.length; i < li; ++i) { 27 | var type = types[i]; 28 | r.push(i + ": " + type); 29 | for(var j = 0; j < c; ++j) { 30 | var data = "getDataAt" in dt ? dt.getDataAt(type, j) : dt.mozGetDataAt(type, j); 31 | if(data) 32 | r.push(" " + j + ": " + data); 33 | } 34 | } 35 | Components.classes["@mozilla.org/consoleservice;1"] 36 | .getService(Components.interfaces.nsIConsoleService) 37 | .logStringMessage("DND test: " + e.type + "\n" + r.join("\n")); 38 | }, 10); 39 | }; 40 | addEventListener("dragstart", this.__dndTest, true); 41 | addEventListener("drop", this.__dndTest, true); 42 | } --------------------------------------------------------------------------------