Объявление

В связи с наплывом спама и ботов на форуме, регистрация новых пользователей будет приостановлена. О восстановлении регистрации будет сообщено дополнительно

Administrator

№1735103-05-2025 23:56:47

Ki_rrrilll
Участник
 
Группа: Members
Зарегистрирован: 22-11-2013
Сообщений: 136
UA: Firefox 115.0

Re: Custom Buttons

yup пишет
Ki_rrrilll пишет

Как открыть папку с закладкой по имени этой закладки или по имени папки?

Задача не столь проста, как кажется. Советую найти старое расширение "Go Parent Folder" и посмотреть, как оно работает.


Главная проблема в том, что скрипту доступны только те элементы дерева закладок, которые видны в данный момент. Если нужные закладка или папка находятся внутри  свёрнутой папки, до них так просто не добраться.

Ну я все равно не разберусь как работает то расширение. И  UCF я не использую.
Сейчас я открываю папку с закладкой кодом

Выделить код

Код:

PlacesUtils.bookmarks.fetch(guid, null, {includePath: true})
  .then(res => PlacesCommandHook.showPlacesOrganizer(["AllBookmarks", ...res.path.map(b => b.guid), guid]))

А guid беру из резервной копии закладок в формате json. Ни о каких "живых" результатах конечно и речи нет, ну хоть как то.
Так вот я думал, может можно из этого json получать guid, по ключевому слову закладки? И желательно имя родительской папки.
Потому что я не очень умею обращаться с этими json и сейчас выуживаю нужный guid путем многочисленных split-ов, отсекая ненужное.

Отредактировано Ki_rrrilll (04-05-2025 00:02:27)

Отсутствует

 

№1735204-05-2025 02:23:48

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1141
UA: Seamonkey 2.49

Re: Custom Buttons

Ki_rrrilll пишет

А guid беру из резервной копии закладок в формате json.

А что является критерием для поиска этого GUID? Имя закладки, URL, метка, ключевое слово или что?


Ki_rrrilll пишет

Так вот я думал, может можно из этого json получать guid, по ключевому слову закладки? И желательно имя родительской папки.
Потому что я не очень умею обращаться с этими json и сейчас выуживаю нужный guid путем многочисленных split-ов, отсекая ненужное.

Если преобразовать JSON в объект (а это просто один вызов функции JSON.parse(str)), то можно прогуляться по получившемуся дереву и найти в нём нужный элемент. А заодно в процессе этой прогулки и путь к закладке построится.


Только вот алгоритм прохода по дереву абсолютно аналогичен алгоритму, который используется скрипте SidebarBookmarkSearchOpenFolder. Зато скрипт не нуждается в JSON-е, он напрямую с данными окна работает.


И ещё мне кажется, что если в поиске информации о нужной закладке используется человек, то, наверное, имеет смысл взять ранее упомянутое расширение "Go Parent Folder" и засунуть его в кнопку. Потому что работает расширение так: ткнулись мышкой в нужную закладку, выбрали из её контекстного меню пункт "Go Parent Folder" - и происходит переход в папку, в которой где эта закладка лежит. А слева, соответственно, дерево до этой папки разворачивается и папка выбирается (становится текущей).
А  SidebarBookmarkSearchOpenFolder делает то же самое, только не в окне, а в боковой панели.


Ki_rrrilll пишет

И  UCF я не использую.

В кнопку данный скрипт засовывается с минимальными усилиями.

Отредактировано yup (04-05-2025 02:44:26)

Отсутствует

 

№1735304-05-2025 07:55:52

leex
Участник
 
Группа: Members
Зарегистрирован: 24-03-2011
Сообщений: 331
UA: Firefox 138.0

Re: Custom Buttons

Всем привет!
Если вы используете это расширение, отличные новости — с помощью ИИ удалось устранить баги, возникшие при работе в Firefox 138.
Теперь код для расширения снова работает корректно.

Оригинальный код был создан Dumby и отлично себя показал в более ранних версиях браузера.
Новая версия кода базируется на том же исходнике, но адаптирована под последние изменения Firefox.

Финальная версия доступна здесь:

скрытый текст

Выделить код

Код:

// ==UserScript==
// @name        Иконки поисковых систем из расширения ContextSearch-web-ext в контекстном меню
// @namespace   cswem
// @version     2.1
// @description Редактирует контекстное меню Firefox
// @match       *://*/*
// @grant       none
// @icon        https://www.mozilla.org/favicon.ico
// ==/UserScript==

(function() {
    'use strict';
    
    // Конфигурация
    const SETTINGS = {
        initializedFlag: 'cswemInitialized',  // Флаг инициализации
        menuId: 'cswem-menugroup',           // ID группы меню
        styleId: 'cswem-styles',             // ID стилей
        hiddenItems: [                       // Элементы для скрытия
            '_5dd73bb9-e728-4d1e-990b-c77d8e03670f_-menuitem-_root_menu',
            'context-searchselect',
            'context-keywordfield'
        ]
    };

    // Проверяем, не запущен ли скрипт ранее
    if (window[SETTINGS.initializedFlag]) return;
    window[SETTINGS.initializedFlag] = true;

    try {
        // ██████████████████████████████████████████████████████████████
        // █ 1. ДОБАВЛЯЕМ СТИЛИ ДЛЯ СКРЫТИЯ ЛИШНИХ ЭЛЕМЕНТОВ И НАСТРОЙКИ МЕНЮ
        // ██████████████████████████████████████████████████████████████
        const style = document.createElement('style');
        style.id = SETTINGS.styleId;
        style.textContent = `
            #${SETTINGS.menuId} {
                padding-left: 30px;
                display: grid;
                grid-template-columns: repeat(auto-fill, 32px);
                grid-auto-rows: 26px;
                gap: 2px;
            }
            #${SETTINGS.menuId} > menuitem {
                -moz-box-pack: center;
                list-style-image: var(--image) !important;
            }
            ${SETTINGS.hiddenItems.map(id => `#${id}`).join(', ')},
            #${SETTINGS.menuId}:empty {
                display: none !important;
            }
        `;
        document.head.appendChild(style);

        // ██████████████████████████████████████████████████████████████
        // █ 2. СОЗДАЕМ КОНТЕЙНЕР ДЛЯ ИКОНОК
        // ██████████████████████████████████████████████████████████████
        const menugroup = document.createXULElement('menugroup');
        menugroup.id = SETTINGS.menuId;
        
        // Размещаем после поисковой строки или в начало меню
        const searchSelect = document.getElementById('context-searchselect');
        if (searchSelect) {
            searchSelect.after(menugroup);
        } else {
            document.getElementById('contentAreaContextMenu').prepend(menugroup);
        }

        // ██████████████████████████████████████████████████████████████
        // █ 3. ФУНКЦИЯ ФИЛЬТРАЦИИ: ОПРЕДЕЛЯЕМ, КАКИЕ ЭЛЕМЕНТЫ ОСТАВИТЬ
        // ██████████████████████████████████████████████████████████████
        const shouldKeepItem = (item) => {
            const forbiddenClasses = ['menuitem-iconic-webext', 'extension-menu-item'];
            const forbiddenIds = ['ublock', 'adguard', 'grammarly', 'ext-', 'extension-', ...SETTINGS.hiddenItems];
            
            return (
                item.tagName === 'menuitem' &&
                !item.hidden &&
                item.getAttribute('image') &&
                item.getAttribute('label') &&
                !item.id?.includes('_separator') &&
                !forbiddenClasses.some(c => item.classList.contains(c)) &&
                !forbiddenIds.some(id => item.id?.includes(id))
            );
        };

        // ██████████████████████████████████████████████████████████████
        // █ 4. ОБНОВЛЕНИЕ МЕНЮ: УДАЛЯЕМ СТАРЫЕ ЭЛЕМЕНТЫ И ДОБАВЛЯЕМ НОВЫЕ
        // ██████████████████████████████████████████████████████████████
        const refreshMenu = () => {
            // Полностью очищаем меню перед обновлением
            while (menugroup.firstChild) {
                menugroup.removeChild(menugroup.firstChild);
            }
            
            // Находим все элементы меню и фильтруем их
            const allMenuItems = Array.from(document.querySelectorAll('#contentAreaContextMenu menuitem'));
            const validItems = allMenuItems.filter(shouldKeepItem);
            
            // Клонируем и добавляем только нужные элементы
            validItems.forEach(item => {
                const clone = item.cloneNode(true);
                clone.id = ''; // Удаляем ID, чтобы избежать конфликтов
                
                // Назначаем обработчик клика
                clone.addEventListener('command', () => {
                    try {
                        item.click();
                    } catch (e) {
                        console.error('Ошибка при клике:', e);
                    }
                });
                
                menugroup.appendChild(clone);
            });
            
            // Скрываем группу, если нет элементов
            menugroup.hidden = menugroup.children.length === 0;
        };

        // ██████████████████████████████████████████████████████████████
        // █ 5. НАСТРОЙКА СОБЫТИЙ: ОБНОВЛЯЕМ МЕНЮ ПРИ КАЖДОМ ОТКРЫТИИ
        // ██████████████████████████████████████████████████████████████
        const contextMenu = document.getElementById('contentAreaContextMenu');
        contextMenu.addEventListener('popupshowing', refreshMenu);

        // ██████████████████████████████████████████████████████████████
        // █ 6. ОЧИСТКА: УДАЛЯЕМ ЭЛЕМЕНТЫ ПРИ ЗАКРЫТИИ СТРАНИЦЫ
        // ██████████████████████████████████████████████████████████████
        window.addEventListener('unload', () => {
            contextMenu.removeEventListener('popupshowing', refreshMenu);
            document.getElementById(SETTINGS.menuId)?.remove();
            document.getElementById(SETTINGS.styleId)?.remove();
            delete window[SETTINGS.initializedFlag];
        });

    } catch (error) {
        console.error('Ошибка в скрипте контекстного меню:', error);
    }
})();



image.jpg



Кинуть код в поле «Инициализация».
Иконки поисковых систем автоматически подгружаются в контекстное меню из установленного дополнения ContextSearch-web-ext.

Отредактировано leex (04-05-2025 12:23:42)

Отсутствует

 

№1735405-05-2025 03:28:04

Ki_rrrilll
Участник
 
Группа: Members
Зарегистрирован: 22-11-2013
Сообщений: 136
UA: Firefox 115.0

Re: Custom Buttons

yup пишет
Ki_rrrilll пишет

А guid беру из резервной копии закладок в формате json.

А что является критерием для поиска этого GUID? Имя закладки, URL, метка, ключевое слово или что?

Имя или ключевое слово. Желательно, чтоб можно было искать и так, и так. Поиск по ключевому слову нужнее, по имени закладку можно найти через встроенный поиск, а вот если помнишь только ключевое слово - то никак. Можно конечно по ключевому слову открыть закладку, увидеть ее URL и вставить его в поле поиска. Но ведь это не выход.

Если преобразовать JSON в объект (а это просто один вызов функции JSON.parse(str)), то можно прогуляться по получившемуся дереву и найти в нём нужный элемент. А заодно в процессе этой прогулки и путь к закладке построится.

Только вот алгоритм прохода по дереву абсолютно аналогичен алгоритму, который используется скрипте SidebarBookmarkSearchOpenFolder. Зато скрипт не нуждается в JSON-е, он напрямую с данными окна работает.

Я открывал свой JSON в онлайн парсере, видел там это дерево.  Но я не программист и не знаю как вытащить из него то что мне нужно. А нужно мне: по ключевому слову определить имя закладки, имя папки и желательно имя родителя папки. Просто получить эту информацию, скажем, в виде алерта.
Ну и GUID, на случай если захочу увидеть закладку в ее папке.

И ещё мне кажется, что если в поиске информации о нужной закладке используется человек, то, наверное, имеет смысл взять ранее упомянутое расширение "Go Parent Folder" и засунуть его в кнопку. Потому что работает расширение так: ткнулись мышкой в нужную закладку, выбрали из её контекстного меню пункт "Go Parent Folder" - и происходит переход в папку, в которой где эта закладка лежит.

Я как раз хочу найти решение для случаев, когда ткнуть в закладку не получается - я не знаю где она лежит. Надо закладку сперва найти. Особенно это касается букмарклетов. Знаю, что есть у меня такой букмарклет, знаю keyword для его вызова. А как называется - не помню.

Отсутствует

 

№1735505-05-2025 14:33:48

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1141
UA: Seamonkey 2.49

Re: Custom Buttons

Ki_rrrilll

В тех браузерах, которыми я пользуюсь, у закладок есть Tags / Метки и Keyword / Краткое имя. Очевидно, мы сейчас говорим о кратких именах.

Firefox в связи с особенностями интерфейса окна Библиотека показывает в таблице только Метки. Если попытаться обойтись совсем-совсем без программирования, то есть два решения:

  1. Если в адресной строке набрать краткое имя, то под адресной строкой браузер вывалит найденную по этому слову закладку, после чего можно скопировать её URL и но нему найти закладку обычным поиском.
  2. Можно скопировать тексты из кратких имён в метки. А по меткам стандартный поиск ищет.

А если с программированием, то вместо поиска по GUID вполне можно искать сразу по кратким именам:

скрытый текст

Выделить код

Код:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");

let keyword = prompt("Что ищем?");
if (!keyword ) return;

PlacesUtils.keywords.fetch(keyword)
  .then(res => { if (!res) return;
                 let query = PlacesUtils.history.getNewQuery();
                 query.searchTerms = res.url.href;
                 let options = PlacesUtils.history.getNewQueryOptions();
                 options.queryType = 1; // QUERY_TYPE_BOOKMARKS;
                 res = PlacesUtils.history.executeQuery(query, options);
                 res.root.containerOpen = true;
                 let guid = res.root.getChild(0).bookmarkGuid;
                 /* что-то делать с guid */
                 PlacesUtils.bookmarks.fetch(guid, null, {includePath: true})
                   .then(res => PlacesCommandHook.showPlacesOrganizer(["AllBookmarks", ...res.path.map(b => b.guid), guid]));
               },
        error => { console.log(error); }
       );

Но что лучше всего делать с полученным guid, я сказать на могу. Скорее всего, его можно засунуть в:

Выделить код

Код:

PlacesUtils.bookmarks.fetch(guid, null, {includePath: true})
  .then(res => PlacesCommandHook.showPlacesOrganizer(["AllBookmarks", ...res.path.map(b => b.guid), guid]))

- как у меня в коде, и сразу откроется нужное окно, но проверить это я не могу, потому что у доступных мне браузеров у функции PlacesUtils.bookmarks.fetch() нет параметра {includePath: true}.

Так что дальше пусть кто-то из местных владельцев современных Firefox поможет, если это не заработает.


Но обращаю внимание: если имеется несколько закладок с одинаковым URL, и одной из них прописать Keyword / Краткое имя, то то же самое окажется прописанным и у всех остальных закладок, потому что браузер эти имена присваивает не закладкам, а URL-ам.


Соответственно, если закладок с одинаковым URL-ом будет существовать несколько, то мой код покажет только первую из них.

Отредактировано yup (06-05-2025 10:26:16)

Отсутствует

 

№1735606-05-2025 23:39:05

Ki_rrrilll
Участник
 
Группа: Members
Зарегистрирован: 22-11-2013
Сообщений: 136
UA: Firefox 115.0

Re: Custom Buttons

yup пишет

Если в адресной строке набрать краткое имя, то под адресной строкой браузер вывалит найденную по этому слову закладку, после чего можно скопировать её URL и но нему найти закладку обычным поиском.

Это как раз то, о чем я и писал постом выше. Что это способ неудобный :D


Но что лучше всего делать с полученным guid, я сказать на могу. Скорее всего, его можно засунуть в:

Выделить код

Код:

PlacesUtils.bookmarks.fetch(guid, null, {includePath: true})
  .then(res => PlacesCommandHook.showPlacesOrganizer(["AllBookmarks", ...res.path.map(b => b.guid), guid]))

Это как раз то, что я и делал до сих пор :D
Просто получить guid чтобы сюда вставлять для меня было затруднительно.


А вот код ваш я утащил. Большое спасибо!
Но ведь ваш код открывает менеджер закладок тоже через  guid? Иначе наверное никак не открыть?

Отсутствует

 

№1735707-05-2025 02:03:33

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1141
UA: Seamonkey 2.49

Re: Custom Buttons

Ki_rrrilll пишет

Это как раз то, что я и делал до сих пор :D

Да. Мне пришлось этому коду "поверить на слово", потому что проверить его в своих браузерах я не могу.


Но ведь ваш код открывает менеджер закладок тоже через  guid?

Точнее будет сказать: открывает с указанием guid-ов закладки, которую нужно выделить, и всех папок, которые нужно развернуть, чтобы до неё добраться. (Зачем эту цепочку папок нужно указывать, я не знаю. По идее, код браузера и сам мог бы её получить, вызвав ту же самую функцию bookmarks.fetch()).


Может быть,  для указания нужной закладки можно использовать не только её guid, но и ещё что-то, но мне посмотреть негде.


Иначе наверное никак не открыть?

Закладки можно открыть разными способами. Но открыть окно, развернуть папки и выделить нужную закладку - этот способ самый простой. Альтернативные варианты здесь приводились в предыдущие два дня.

Отсутствует

 

№1735807-05-2025 22:53:24

Ki_rrrilll
Участник
 
Группа: Members
Зарегистрирован: 22-11-2013
Сообщений: 136
UA: Firefox 115.0

Re: Custom Buttons

yup
Вот еще добавить бы к вашему коду проверку - если окно менеджера закладок уже существует, то закрыть его, а потм уже выполнять код дальше.
А то бывает, не заметишь, что окно свернуто или просто в фоне, тогда  в консоли  появляется ошибка
Uncaught (in promise) NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsINavHistoryContainerResultNode.getChild]


И на этом все останавливается.

Отредактировано Ki_rrrilll (07-05-2025 22:55:04)

Отсутствует

 

№1735907-05-2025 23:38:21

yup
Участник
 
Группа: Members
Зарегистрирован: 15-04-2016
Сообщений: 1141
UA: Seamonkey 2.49

Re: Custom Buttons

Ki_rrrilll
Надо же... Я думал, в функции showPlacesOrganizer() возможность такой ситуации учтена.


Как закрыть имеющееся окно, я знаю. Но прежде, чем это добавлять, прошу проверить вариант:

скрытый текст

Выделить код

Код:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");

let keyword = prompt("Что ищем?");
if (!keyword ) return;

PlacesUtils.keywords.fetch(keyword)
  .then(kwd => { if (!kwd) return;
                 let query = PlacesUtils.history.getNewQuery();
                 query.searchTerms = kwd.url.href;
                 let options = PlacesUtils.history.getNewQueryOptions();
                 options.queryType = 1; // QUERY_TYPE_BOOKMARKS;
                 let result = PlacesUtils.history.executeQuery(query, options);
                 result.root.containerOpen = true;
                 let guid = result.root.getChild(0).bookmarkGuid;
                 PlacesUtils.bookmarks.fetch(guid, null, {includePath: true})
                   .then(res => PlacesCommandHook.showPlacesOrganizer(["AllBookmarks", ...res.path.map(b => b.guid), guid]));
               },
        error => { console.log(error); }
       );


- вдруг удастся обойтись "малой кровью".

Отсутствует

 

№17360Вчера 23:34:49

Ki_rrrilll
Участник
 
Группа: Members
Зарегистрирован: 22-11-2013
Сообщений: 136
UA: Firefox 115.0

Re: Custom Buttons

yup
Все работает, обошлось "малой кровью" :)
Спасибо!

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]