From 22d9e9a32397f1df3dbe5dd3077908f6d72599e9 Mon Sep 17 00:00:00 2001 From: Venus Date: Thu, 6 Nov 2025 01:30:13 -0600 Subject: [PATCH] initial commit from extension examples --- README.md | 36 +++++++++ _locales/en/messages.json | 52 +++++++++++++ background.js | 160 ++++++++++++++++++++++++++++++++++++++ icons/LICENSE | 4 + icons/page-16.png | Bin 0 -> 251 bytes icons/page-32.png | Bin 0 -> 344 bytes icons/page-48.png | Bin 0 -> 310 bytes icons/paint-blue-16.png | Bin 0 -> 416 bytes icons/paint-blue-32.png | Bin 0 -> 899 bytes icons/paint-green-16.png | Bin 0 -> 405 bytes icons/paint-green-32.png | Bin 0 -> 870 bytes manifest.json | 35 +++++++++ sidebar/sidebar.html | 13 ++++ 13 files changed, 300 insertions(+) create mode 100644 README.md create mode 100644 _locales/en/messages.json create mode 100644 background.js create mode 100644 icons/LICENSE create mode 100644 icons/page-16.png create mode 100644 icons/page-32.png create mode 100644 icons/page-48.png create mode 100644 icons/paint-blue-16.png create mode 100644 icons/paint-blue-32.png create mode 100644 icons/paint-green-16.png create mode 100644 icons/paint-green-32.png create mode 100644 manifest.json create mode 100644 sidebar/sidebar.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca79920 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# menu-demo + +A demo of the [menus API](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/menus/). + +**This add-on injects JavaScript into web pages. The `addons.mozilla.org` domain disallows this operation, so this add-on will not work properly when it's run on pages in the `addons.mozilla.org` domain.** + +**This add-on uses the `menus` namespace to access the functions it needs to create menu items. Note that Chrome, Edge, and Opera all use the `contextMenus` namespace for this, so this extension will not work in these browsers. For compatibility with these browsers, Firefox also offers the `contextMenus` namespace, so to make this extension work with other browsers, use `contextMenus`.** + +## What it does + +This add-on adds several items to the browser's context menu: + +* one shown when there is a selection in the page, that logs the selected text +to the browser console when clicked. +* one shown in all contexts, that is removed when clicked. +* two "radio" items that are shown in all contexts. +These items are grouped using a separator item on each side. +One radio item adds a blue border to the page, the other adds a green border. +Note that these buttons only work on normal web pages, not special pages +like about:debugging. +* one "checkbox" item, shown in all contexts, whose title is updated when the +item is clicked. +* one item that uses the "commands" property to open the add-on's sidebar. + +It also adds one item to the browser's "Tools" menu. + +## What it shows + +* How to create various types of menu item: + * normal + * radio + * separator + * checkbox +* How to use contexts to control when an item appears. +* How to update an item's properties. +* How to remove an item. diff --git a/_locales/en/messages.json b/_locales/en/messages.json new file mode 100644 index 0000000..709898f --- /dev/null +++ b/_locales/en/messages.json @@ -0,0 +1,52 @@ +{ + "extensionName": { + "message": "Menu demo", + "description": "Name of the extension." + }, + + "extensionDescription": { + "message": "Demonstrates the menus API.", + "description": "Description of the add-on." + }, + + "menuItemSelectionLogger": { + "message": "Log '%s' to the browser console", + "description": "Title of context menu item that logs the selected text when clicked." + }, + + "menuItemRemoveMe": { + "message": "Remove me!", + "description": "Title of context menu item that removes itself when clicked." + }, + + "menuItemGreenify": { + "message": "Greenify", + "description": "Title of context menu item that adds a green border when clicked." + }, + + "menuItemBluify": { + "message": "Bluify", + "description": "Title of context menu item that adds a green border when clicked." + }, + + "menuItemCheckMe": { + "message": "Check me", + "description": "Title of context menu item when the item is checked." + }, + + "menuItemUncheckMe": { + "message": "Uncheck me", + "description": "Title of context menu item when the item is unchecked." + }, + + "menuItemOpenSidebar": { + "message": "Open sidebar", + "description": "Title of context menu item that opens a sidebar." + }, + + "menuItemToolsMenu": { + "message": "Click me!", + "description": "Title of tools menu item." + } + +} diff --git a/background.js b/background.js new file mode 100644 index 0000000..7eb5df3 --- /dev/null +++ b/background.js @@ -0,0 +1,160 @@ +/* +Called when the item has been created, or when creation failed due to an error. +We'll just log success/failure here. +*/ +function onCreated() { + if (browser.runtime.lastError) { + console.log(`Error: ${browser.runtime.lastError}`); + } else { + console.log("Item created successfully"); + } +} + +/* +Called when the item has been removed. +We'll just log success here. +*/ +function onRemoved() { + console.log("Item removed successfully"); +} + +/* +Called when there was an error. +We'll just log the error here. +*/ +function onError(error) { + console.log(`Error: ${error}`); +} + +/* +Create all the context menu items. +*/ +browser.menus.create({ + id: "log-selection", + title: browser.i18n.getMessage("menuItemSelectionLogger"), + contexts: ["selection"] +}, onCreated); + +browser.menus.create({ + id: "remove-me", + title: browser.i18n.getMessage("menuItemRemoveMe"), + contexts: ["all"] +}, onCreated); + +browser.menus.create({ + id: "separator-1", + type: "separator", + contexts: ["all"] +}, onCreated); + +browser.menus.create({ + id: "greenify", + type: "radio", + title: browser.i18n.getMessage("menuItemGreenify"), + contexts: ["all"], + checked: true, + icons: { + "16": "icons/paint-green-16.png", + "32": "icons/paint-green-32.png" + } +}, onCreated); + +browser.menus.create({ + id: "bluify", + type: "radio", + title: browser.i18n.getMessage("menuItemBluify"), + contexts: ["all"], + checked: false, + icons: { + "16": "icons/paint-blue-16.png", + "32": "icons/paint-blue-32.png" + } +}, onCreated); + +browser.menus.create({ + id: "separator-2", + type: "separator", + contexts: ["all"] +}, onCreated); + +browser.menus.create({ + id: "check-uncheck", + type: "checkbox", + title: browser.i18n.getMessage("menuItemUncheckMe"), + contexts: ["all"], + checked: true, +}, onCreated); + +browser.menus.create({ + id: "open-sidebar", + title: browser.i18n.getMessage("menuItemOpenSidebar"), + contexts: ["all"], + command: "_execute_sidebar_action" +}, onCreated); + +browser.menus.create({ + id: "tools-menu", + title: browser.i18n.getMessage("menuItemToolsMenu"), + contexts: ["tools_menu"], +}, onCreated); + +/* +Set a colored border on the document in the given tab. + +Note that this only work on normal web pages, not special pages +like about:debugging. +*/ +let blue = 'document.body.style.border = "5px solid blue"'; +let green = 'document.body.style.border = "5px solid green"'; + +function borderify(tabId, color) { + browser.tabs.executeScript(tabId, { + code: color + }); +} + +/* +Update the menu item's title according to current "checked" value. +*/ +function updateCheckUncheck(checkedState) { + if (checkedState) { + browser.menus.update("check-uncheck", { + title: browser.i18n.getMessage("menuItemUncheckMe"), + }); + } else { + browser.menus.update("check-uncheck", { + title: browser.i18n.getMessage("menuItemCheckMe"), + }); + } +} + +/* +The click event listener, where we perform the appropriate action given the +ID of the menu item that was clicked. +*/ +browser.menus.onClicked.addListener((info, tab) => { + switch (info.menuItemId) { + case "log-selection": + console.log(info.selectionText); + break; + case "remove-me": + let removing = browser.menus.remove(info.menuItemId); + removing.then(onRemoved, onError); + break; + case "bluify": + borderify(tab.id, blue); + break; + case "greenify": + borderify(tab.id, green); + break; + case "check-uncheck": + updateCheckUncheck(info.checked); + break; + case "open-sidebar": + console.log("Opening my sidebar"); + break; + case "tools-menu": + console.log("Clicked the tools menu item"); + break; + } +}); diff --git a/icons/LICENSE b/icons/LICENSE new file mode 100644 index 0000000..5e98d3b --- /dev/null +++ b/icons/LICENSE @@ -0,0 +1,4 @@ + +The "page-32.png" and "page-48.png" icons are taken from the miu iconset created by Linh Pham Thi Dieu, and are used under the terms of its license: http://linhpham.me/miu/. + +The "paint-blue-16", "paint-blue-32", "paint-green-16", and "paint-green-32" icons are adapted from an icon in the ["Outline icons" set](https://www.iconfinder.com/icons/1021026/paint_icon). diff --git a/icons/page-16.png b/icons/page-16.png new file mode 100644 index 0000000000000000000000000000000000000000..a6fed5ce35db2eec07aa361536fb6ba9817b389a GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5t|=cq7;*`i57AB^IBSk^BPThyw) zK``gYHNQo^O^PapYabjqV3a@eZ~TMBdP!HU9!KyTz9W;|k=|N9C^o z+Gk#IDQL#{UHa3;cTFPYbfBkW#EI&a;xEnBUOWy7ogg^nWhl=qfhVFSnm>g9*c{yP s%*w~`kQsN>&g0cxGipAvO4~f(O>s1qoy@j-5740up00i_>zopr001sm+yDRo literal 0 HcmV?d00001 diff --git a/icons/page-32.png b/icons/page-32.png new file mode 100644 index 0000000000000000000000000000000000000000..dae663dbb4989c607cb29de15c2d5300060c459d GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq zxP?KOkzv*x383IFPZ!6Kh}O5)?7f%+1&)984`Ja~^yE|2Fx%-6#VyUBIMq6$fry* z{)J8Fd3GP*J~orN!QCe1*}CZ82Uh4?Y-tpd$}%(TVU<-8+kGtZ$xq&UR(}?6>*N%R z?OZ7x(RII8_N44~Um5j%-1W&1s|yC9yDm!jKi9ar+^ zNc`vx(*!cU_)S_JTgN^rL~;dB2%8r3)W%Z|sSAt*ZXekB?EQ`wKU1GS7wQxq3b@a* kp0>Z(uE>6;pio#-$q%07HSn)78&qol`;+0OH(%rvLx| literal 0 HcmV?d00001 diff --git a/icons/page-48.png b/icons/page-48.png new file mode 100644 index 0000000000000000000000000000000000000000..ba042cdcd5f88b6666d52e2ff60c3c963bc5ac35 GIT binary patch literal 310 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8wRq zxP?KOkzv*x383H&PZ!6KjK;S!y}1rK2(Wq!+J}Fc($%%7d_v6O)^v&R%>f)IRW4U{ ztzR(xvhCEgduj>$=CgS?mNJ`NWD1;qzO;ARiRMMW)E+RcVNTn_+x2SpYo7^6LYO!$ z7+0@w46L<(?UCAP)_Cc7RMEeHU?;^14YnJ4L?lj6&g+crbqr*Re&G1?Sy!jf3Zrtn zgRV}IJr>c`+M5;I|5Y(J?~BN-t78@mcq|eGM9GY%eu^N3MIiVSo5+6-tCyP_)&7XR fz0Px$T1iAfR5%f}lD|s=VHn5H6pTb7Dy79Hr=Y>1AKG?NOG_;-4ed>WG(`k14n=b< z{sk$GhC@&y6&n2uH8?rcT4bN^aVK}D7cPC_bI*_WeV%*Yd(JTaQE_@-LIZAK8^+cg zJ3DY>S4?A1;T*#7rxL6-L2osEJJ*P>Ah1c2#TH~C56%g22U^8D8$>QgZ+?W0NT%Nx z_^&Vpew9dUDjBg?X0bYQk-~dBCsT$8(3QII0Y8v}LuiC}Ou`+UP+Z4)^xX*+$X|Gp z1ms^ZnF$`cYkO2Nc|*l)-i0^CF7@QA!2-N12ogi{ zE)`gJ#(HF(#g)+=E1Px&JxN4CR9Fe+mhEeeaTv$XIKokC-ki`ZRvvwCOheCJ-EzkzTkXM;U^f#bH&)|-0{G8`7sPwttU&E zv3B4$9ETv}RO*N}2>Q=2Cy6Y-x6lqcs+>pzQGP)e=s!FH$)u9W`yl`FWR8C3HsGY> zPoM<);UuJzi8$PXr;zbZY-DlN2~rxIJFM-01b4xYOu*?Lw8B_F3*0`N7$~{6u}sOG z0!}d=f~nv~bR2!qAqcn&Si$%vyoY5hP$Nkx z1lx)4nUsz$2iBZtxLqbYf@wT!D^+pCZ*qJCN>0EXdQL;sQ(|HT9AKnIv5$Z+N2dJ$ zWzAWNh(My>i#M1qvY1!_I{PSrE;#nI6>D2rR80}5eJuWNK0)VUGWr{o*hD6pB0g&! zMX2|ykLczMVV{L|ON9-rfKM1o&6usWLKKH$=0iKSQgjQt9`kg|VMp))LlF)ko5+PG z-U8yNVHNYd6+PaGTkYuhTVSuzew)ZvlW-9+^gU1nTcC>nel=P$Wkmhm2Rbk=g@rik z+Ra!?jhIJiphJIo`M8^f6SP!xz(8L~4YrUvJrb6H)tkoN#Ygl)R`ipiTF8K7> zz+FHu#@!IYq0Jo9(X0#OujD#wCAT)Mqi{>N4cx8RY-&o!pqXuJFk>oBa=mibKp!3Y zg1P~2kxh5NIM8zsB$UI<=o0CG3JQsRh$PbZ)WIOAm9K%E$U&m0h<8w*B)Kk?D5#NX z7ji0kchxpkNGCKx6{us@z&X&|SEz-&$PA(?xe|?rz8TbT@-7iFTmgM248RL$f=Tf2 Z${$|e6TZVU=9d5f002ovPDHLkV1g&sr7r*g literal 0 HcmV?d00001 diff --git a/icons/paint-green-16.png b/icons/paint-green-16.png new file mode 100644 index 0000000000000000000000000000000000000000..02f35a8642ad0414b931b98f4a1b700bba274450 GIT binary patch literal 405 zcmV;G0c!qPx$Pf0{UR5%f}lDjViQ51)NCoyjX0f;n(Iz>U<8w-H4#$5y_95tZ~EAUzS+$8wyz zjx%aORXEa$J%&7m#c)ij)ja+x*pXi04ZgsR(gZW0I=F`MXl1tpv(ie+xLtCfMZQ~! zNv@GJP0q8IBb{1xHFUs>1*t0Okm62`l!KEnuf?o2IEOw9Dv(`th9-O1?s$HIV9eX1 z+rG2X0y+0E33fLh5UCCC7J3t#NK4G!fxVVt&%FPx&AW1|)R9Fe+mdkHUaTLc7nher3ojy|1#)?WMB2p2x&`MCD6@o-0h;(mZA(q5S zCFnm;#D*0~BT*HpS1de&c*G+%9zj^3=&0cHz4!if=Js~xPG@EzPV$*^f9H38=bZby z_nzOF{qHiVfDNc%Z5J$q>F^Bt-~#-Hl1ektUxE_dhf8VW2VA#7$z&ywhad&5p)75T zwFAH45R^etrGse0pgTX6C9?cp!2sw{6-Cw)f+TtJ+Ws4G1>(q5oUTGYOo_7~-DficCD%4qdCC0( zjxzoU^$SdYS2i=TnH;Qevn@tD~+1Nl!*hzf<}%q2H~Hb;|W;EQnixf6{$ny^`x?bJCF! z&+MF=h|+3GD&kDWqFhCotzeCIa2VD?SoE(-XUub05S|Q=_hC>GgHV&R5VH>alvu5N zH55hm5=BMmWQ#uav@2#iK*zW4UX7=yqHkAiQ;GCvLhncesAK9)KMtDHb8m%`h`tUb wSE4B1Vpqc{xwMnvH0Y=vf=AE|b@1=XADykJyBA=|T>t<807*qoM6N<$g6ve7ng9R* literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..59c12ea --- /dev/null +++ b/manifest.json @@ -0,0 +1,35 @@ +{ + + "manifest_version": 2, + "name": "__MSG_extensionName__", + "description": "__MSG_extensionDescription__", + "version": "1.0", + "default_locale": "en", + "browser_specific_settings": { + "gecko": { + "strict_min_version": "56.0a1" + } + }, + + "background": { + "scripts": ["background.js"] + }, + + "permissions": [ + "menus", + "activeTab" + ], + + "icons": { + "16": "icons/page-16.png", + "32": "icons/page-32.png", + "48": "icons/page-48.png" + }, + + "sidebar_action": { + "default_icon": "icons/page-32.png", + "default_title" : "My sidebar", + "default_panel": "sidebar/sidebar.html" + } + +} diff --git a/sidebar/sidebar.html b/sidebar/sidebar.html new file mode 100644 index 0000000..bbfc03b --- /dev/null +++ b/sidebar/sidebar.html @@ -0,0 +1,13 @@ + + + + + + + + + +

My panel

+ + +