├── 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 |  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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |
6 |
7 |
--------------------------------------------------------------------------------
/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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |  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 |  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 |
23 | ;
24 | this.appendChild(cbu.makeXML(xml));
25 |
26 | var xml =
27 |
28 |
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 |
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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |  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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |  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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 | #####  [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 | #####  [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 | #####  [Bookmarks Folder](Bookmarks_Folder)
21 | Show contents of any bookmarks folder in drop-down menu
22 |
23 | #####  [Custom Buttons: Disable Initialization](CB_Disable_Initialization)
24 | Adds “Enabled” checkbox to custom button's context menu (for test purposes)
25 |
26 | #####  [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 | #####  [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 | #####  [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 | #####  [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 | #####  [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 | #####  [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 | #####  [Edit Custom Button in Tab](Edit_Custom_Button_in_Tab)
49 | Add “Edit button in tab…” to custom button's context menu
50 |
51 | #####  [Extensions Developer Tools](Extensions_Developer_Tools)
52 | Some tools for extensions or custom buttons developers
53 |
54 | #####  [Extensions Installer](Extensions_Installer)
55 | For extensions developers: installs extension from given link, useful to test restartless extensions
56 |
57 | #####  [List All Tabs](List_All_Tabs)
58 | Shows built-in list of all tabs
59 |
60 | #####  [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 | #####  [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 | #####  [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 | #####  [Reload Broken Images](Reload_Broken_Images)
86 | Reload broken or not loaded images
87 |
88 | #####  [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 | #####  [Show Anchors](Show_Anchors)
94 | Show/hide all anchors on the page to easily copy link to some section of the page
95 |
96 | #####  [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 | #####  [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 | #####  [Toggle Flash](Toggle_Flash)
109 | Toggle Shockwave Flash plugin (also may be easily configured to toggle any other add-on)
110 |
111 | #####  [Toggle GIF Animation](Toggle_GIF_Animation)
112 | Disable or enable GIF animation on current page
113 |
114 | #####  [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 | #####  [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 |  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 |  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 |
9 |
10 |
--------------------------------------------------------------------------------
/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 |  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 |  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 |  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 |  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 |  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 |  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 |
--------------------------------------------------------------------------------
/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 |  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 | ';
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 | }
--------------------------------------------------------------------------------