Jelajahi Sumber

Support the modification of individual items withing a menu bar

Nariman Jelveh 11 bulan lalu
induk
melakukan
72641c66a2
6 mengubah file dengan 103 tambahan dan 10 penghapusan
  1. 20 0
      packages/puter-js/src/modules/UI.js
  2. 45 5
      src/IPC.js
  3. 12 4
      src/UI/UIContextMenu.js
  4. 10 1
      src/UI/UIWindow.js
  5. 1 0
      src/globals.js
  6. 15 0
      src/helpers.js

+ 20 - 0
packages/puter-js/src/modules/UI.js

@@ -678,6 +678,26 @@ class UI extends EventListener {
         this.#postMessageWithObject('setMenubar', spec);
     }
 
+    disableMenuItem = function(item_id) {
+        this.#postMessageWithObject('disableMenuItem', {id: item_id});
+    }
+
+    enableMenuItem = function(item_id) {
+        this.#postMessageWithObject('enableMenuItem', {id: item_id});
+    }
+
+    setMenuItemIcon = function(item_id, icon) {
+        this.#postMessageWithObject('setMenuItemIcon', {id: item_id, icon: icon});
+    }
+
+    setMenuItemIconActive = function(item_id, icon) {
+        this.#postMessageWithObject('setMenuItemIconActive', {id: item_id, icon: icon});
+    }
+
+    setMenuItemChecked = function(item_id, checked) {
+        this.#postMessageWithObject('setMenuItemChecked', {id: item_id, checked: checked});
+    }
+
     contextMenu = function(spec) {
         this.#postMessageWithObject('contextMenu', spec);
     }

+ 45 - 5
src/IPC.js

@@ -393,7 +393,6 @@ window.addEventListener('message', async (event) => {
         // get parent window
         const el_window = window.window_for_app_instance(event.data.appInstanceID);
 
-
         let items = value.items ?? [];
         const sanitize_items = items => {
             return items.map(item => {
@@ -432,6 +431,36 @@ window.addEventListener('message', async (event) => {
 
         $(target_iframe).get(0).focus({preventScroll:true});
     }
+    // --------------------------------------------------------
+    // disableMenuItem
+    // --------------------------------------------------------
+    else if(event.data.msg === 'disableMenuItem'){
+        set_menu_item_prop(window.menubars[event.data.appInstanceID], event.data.value.id, 'disabled', true);
+    }
+    // --------------------------------------------------------
+    // enableMenuItem
+    // --------------------------------------------------------
+    else if(event.data.msg === 'enableMenuItem'){
+        set_menu_item_prop(window.menubars[event.data.appInstanceID], event.data.value.id, 'disabled', false);
+    }
+    //--------------------------------------------------------
+    // setMenuItemIcon
+    //--------------------------------------------------------
+    else if(event.data.msg === 'setMenuItemIcon'){
+        set_menu_item_prop(window.menubars[event.data.appInstanceID], event.data.value.id, 'icon', event.data.value.icon);
+    }
+    //--------------------------------------------------------
+    // setMenuItemIconActive
+    //--------------------------------------------------------
+    else if(event.data.msg === 'setMenuItemIconActive'){
+        set_menu_item_prop(window.menubars[event.data.appInstanceID], event.data.value.id, 'icon_active', event.data.value.icon_active);
+    }
+    //--------------------------------------------------------
+    // setMenuItemChecked
+    //--------------------------------------------------------
+    else if(event.data.msg === 'setMenuItemChecked'){
+        set_menu_item_prop(window.menubars[event.data.appInstanceID], event.data.value.id, 'checked', event.data.value.checked);
+    }
     //--------------------------------------------------------
     // setMenubar
     //--------------------------------------------------------
@@ -452,6 +481,9 @@ window.addEventListener('message', async (event) => {
             e.preventDefault();
         });
 
+        if(!window.menubars[event.data.appInstanceID])
+            window.menubars[event.data.appInstanceID] = value.items;
+
         const sanitize_items = items => {
             return items.map(item => {
                 // Check if the item is just '-'
@@ -461,6 +493,10 @@ window.addEventListener('message', async (event) => {
                 // Otherwise, proceed as before
                 return {
                     html: item.label,
+                    disabled: item.disabled,
+                    checked: item.checked,
+                    icon: item.icon ? `<img style="width: 15px; height: 15px; position: absolute; top: 4px; left: 6px;" src="${html_encode(item.icon)}" />` : undefined,
+                    icon_active: item.icon_active ? `<img style="width: 15px; height: 15px; position: absolute; top: 4px; left: 6px;" src="${html_encode(item.icon_active)}" />` : undefined,
                     action: item.action,
                     items: item.items ? sanitize_items(item.items) : undefined
                 };
@@ -489,8 +525,8 @@ window.addEventListener('message', async (event) => {
 
             // Open the context menu
             const ctxMenu = UIContextMenu({
-                delay,
-                parent_element,
+                delay: delay,
+                parent_element: parent_element,
                 position: {top: pos.top + 30, left: pos.left},
                 css: {
                     'box-shadow': '0px 2px 6px #00000059'
@@ -517,9 +553,13 @@ window.addEventListener('message', async (event) => {
                 const item = items[i];
                 const label = html_encode(item.label);
                 const el_item = $(`<div class="window-menubar-item"><span>${label}</span></div>`);
-                const parent_element = el_item.parent()[0];
+                const parent_element = el_item.get(0);
                 
                 el_item.on('mousedown', (e) => {
+                    // check if it has has-open-context-menu class
+                    if ( el_item.hasClass('has-open-contextmenu') ) {
+                        return;
+                    }
                     if ( state_open ) {
                         state_open = false;
                         current && current.cancel({ meta: 'menubar' });
@@ -563,7 +603,7 @@ window.addEventListener('message', async (event) => {
                 menubar_buttons.push(el_item);
             }
         };
-        add_items($menubar, value.items);
+        add_items($menubar, window.menubars[event.data.appInstanceID]);
     }
     //--------------------------------------------------------
     // setWindowWidth

+ 12 - 4
src/UI/UIContextMenu.js

@@ -21,7 +21,6 @@ function UIContextMenu(options){
     $('.window-active .window-app-iframe').css('pointer-events', 'none');
 
     const menu_id = window.global_element_id++;
-
     let h = '';
     h += `<div 
                 id="context-menu-${menu_id}" 
@@ -42,8 +41,13 @@ function UIContextMenu(options){
                             class="context-menu-item ${options.items[i].disabled ? ' context-menu-item-disabled' : ''}"
                             >`;
                         // icon
-                        h += `<span class="context-menu-item-icon">${options.items[i].icon ?? ''}</span>`;
-                        h += `<span class="context-menu-item-icon-active">${options.items[i].icon_active ?? (options.items[i].icon ?? '')}</span>`;
+                        if(options.items[i].checked === true){
+                            h += `<span class="context-menu-item-icon">✓</span>`;
+                            h += `<span class="context-menu-item-icon-active">✓</span>`;
+                        }else{
+                            h += `<span class="context-menu-item-icon">${options.items[i].icon ?? ''}</span>`;
+                            h += `<span class="context-menu-item-icon-active">${options.items[i].icon_active ?? (options.items[i].icon ?? '')}</span>`;
+                        }
                         // label
                         h += `<span class="contextmenu-label">${options.items[i].html}</span>`;
                         h += `<span class="contextmenu-label-active">${options.items[i].html_active ?? options.items[i].html}</span>`;
@@ -275,7 +279,11 @@ function UIContextMenu(options){
         if(options.parent_element){
             $(options.parent_element).parent().removeClass('children-have-open-contextmenu');
 
-            $(options.parent_element).css('overflow', 'scroll');
+            // if the parent element is not a window, make it scrollable again
+            if (!$(options.parent_element).hasClass('window-body')) {
+                $(options.parent_element).css('overflow', 'scroll');
+            }
+            
             $(options.parent_element).removeClass('has-open-contextmenu');
             if($(options.parent_element).hasClass('taskbar-item')){
                 window.make_taskbar_sortable()

+ 10 - 1
src/UI/UIWindow.js

@@ -2807,16 +2807,25 @@ $.fn.close = async function(options) {
     $(this).each(async function() {
         const el_iframe = $(this).find('.window-app-iframe');
         const app_uses_sdk = el_iframe.length > 0 && el_iframe.attr('data-appUsesSDK') === 'true';
-        // tell child app that this window is about to close, get its response
+
         if(app_uses_sdk){
+            // get appInstanceID
+            const appInstanceID = el_iframe.closest('.window').attr('data-element_uuid');
+            // tell child app that this window is about to close, get its response
             if(!options.bypass_iframe_messaging){
                 const resp = await window.sendWindowWillCloseMsg(el_iframe.get(0));
                 if(!resp.msg){
                     return false;
                 }
             }
+            // remove the menubar from the window.menubars array
+            if(appInstanceID){
+                delete window.menubars[appInstanceID];
+                window.app_instance_ids.delete(appInstanceID);
+            }
         }
 
+
         if ( this.on_before_exit ) {
             if ( ! await this.on_before_exit() ) return false;
         }

+ 1 - 0
src/globals.js

@@ -26,6 +26,7 @@ window.progress_tracker = [];
 window.upload_item_global_id = 0;
 window.app_instance_ids = new Set();
 
+window.menubars = [];
 window.download_progress = [];
 window.download_item_global_id = 0;
 

+ 15 - 0
src/helpers.js

@@ -3587,3 +3587,18 @@ window.check_password_strength = (password) => {
         report: criteria_report,
     };
 }
+
+window.set_menu_item_prop = (items, item_id, prop, val) => {
+    // iterate over items
+    for (const item of items) {
+        // find the item with the given item_id
+        if (item.id === item_id) {
+            // set the property value
+            item[prop] = val;
+            break;
+        }
+        else if(item.items){
+            set_menu_item_prop(item.items, item_id, prop, val);
+        }
+    }
+};