Полезная информация

Заказывай стафф с атрибутикой Mozilla и... пусть все вокруг завидуют тебе! Быть уникальным - быть с Mozilla!

№1270111-07-2018 23:55:22

firefan
Участник
 
Группа: Members
Зарегистрирован: 23-06-2016
Сообщений: 16
UA: Firefox 52.0

Re: Custom Buttons

momo2000 пишет:

https://addons.mozilla.org/en-US/firefox/addon/contextsearch-web-ext-lite/
https://addons.mozilla.org/en-US/firefox/addon/mozlz4-edit/

Спасибо, но первое - только для quantum (я остаюсь на ESR 52, а потом Pale Moon или Waterfox),
а второе - просто редактирование поисковых систем, которое я и так умею.

Отсутствует

 

№1270212-07-2018 02:17:30

difabor
Участник
 
Группа: Members
Зарегистрирован: 21-09-2013
Сообщений: 519
UA: Firefox 52.0
Веб-сайт

Re: Custom Buttons

firefan пишет:

momo2000 пишет:

https://addons.mozilla.org/en-US/firefox/addon/contextsearch-web-ext-lite/
https://addons.mozilla.org/en-US/firefox/addon/mozlz4-edit/

Спасибо, но первое - только для quantum (я остаюсь на ESR 52, а потом Pale Moon или Waterfox),
а второе - просто редактирование поисковых систем, которое я и так умею.

Я пользуюсь https://addons.mozilla.org/ru/firefox/a … ed-search/ - мне нравится.
Кроме того - посмотрите кнопку https://forum.mozilla-russia.org/viewto … 50#p703450

Отредактировано difabor (12-07-2018 02:34:53)


Хорошо, когда у человека есть выбор, но плохо, когда он перед ним стоит ©

Отсутствует

 

№1270312-07-2018 09:27:23

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 860
UA: Firefox 52.0

Re: Custom Buttons

unter_officer пишет:

Dumby
Поправьте пожалуйста кнопочку под [firefox] 60+

Не, это не то, что можно просто «поправить».
И, количество совпадений findbar'ы умеют показывать уже давно.
А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.

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

Выделить код

Код:

((bar, button = true, insertAtTop = true, ctrlFcloseFinbar = false) => ({
    init(parent) {
        var has = bar = parent.querySelector("#appcontent > findbar");
        has || this.initFinbar(parent);
        var lo = bar.linkedObject;
        lo.listenCtrlF = ctrlFcloseFinbar
            ? listen => listen
                ? addEventListener("keydown", lo, true)
                : removeEventListener("keydown", lo, true)
            : () => {};
        has && !bar.hidden && lo.listenCtrlF(true);
        if (button) self._handleClick = () => bar.hidden
            ? bar.startFind(bar.FIND_NORMAL)
            : bar.collapsed || bar.close();
        addDestructor(lo.destroy, lo);
    },
    destroy(reason) {
        if (reason[5] != "e") return;
        bar.close();
        bar._browser = {};
        bar.remove();
        this.setProgressListener(false);
        for(var key of ["gFindBar", "gFindBarInitialized"])
            Object.defineProperty(window, key, this[key]);
        gBrowser[this.gBrKey] = this[this.gBrKey];
        Services.ppmm.removeDelayedProcessScript(this.url);
        Services.ppmm.loadProcessScript("data:," + encodeURIComponent(`
            Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT
            && Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT
            || (nsvo => {
                var proto = nsvo.Finder.prototype;
                if ("_requestMatchesCount" in proto) {
                    proto.requestMatchesCount = proto._requestMatchesCount;
                    delete proto._requestMatchesCount;
                }
            })(Cu.import("resource://gre/modules/Finder.jsm", {}));`
        ) , false);
    },
    initFinbar(parent) {
        for(var tab of gBrowser.tabs) {
            if (!tab._findBar) continue;
            tab._findBar.browser = null;
            tab._findBar._browser = {};
            tab._findBar.remove();
            delete tab._findBar;
        }
        bar = document.createElement("findbar");
        var p = new Proxy({}, {get: () => () => {}});
        bar._browser = {finder: p, messageManager: p};
        parent.insertBefore(bar, insertAtTop ? parent.firstChild : null);
        bar.linkedObject = this;

        ["gFindBar", "gFindBarInitialized"].forEach((key, ind) => {
            this[key] = Object.getOwnPropertyDescriptor(window, key);
            delete window[key];
            window[key] = ind ? true : bar;
        });
        var key = "getCachedFindBar" in gBrowser ? "getCachedFindBar" : "getFindBar";
        this[this.gBrKey = key] = gBrowser[key];
        gBrowser[key] = () => bar;
        [
            "close", "startFind", "onMatchesCountResult",
            "_updateMatchesCount", "_onBrowserKeypress", "receiveMessage"

        ].forEach((key, ind) => {
            var func = bar[key].bind(bar);
            bar[key] = ind
                ? (...args) => this[key](...args) || func(...args)
                : (...args) => func(...args) || this[key](...args);
        });
        this.url = "data:," + encodeURIComponent(`
            Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT
            && Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT
            || (nsvo => {
                var proto = nsvo.Finder.prototype;
                if ("_requestMatchesCount" in proto) return;
                proto._requestMatchesCount = proto.requestMatchesCount;
                proto.requestMatchesCount = ${
                    this.newRequestMatchesCount
                }
            })(Cu.import("resource://gre/modules/Finder.jsm", {}));`
        );
        delete this.newRequestMatchesCount;
        Services.ppmm.loadProcessScript(this.url, true);
    },
    newRequestMatchesCount: async function requestMatchesCount(aWord, aLinksOnly) {
        if (typeof aLinksOnly != "boolean") {

            var {linksOnly, data} = aLinksOnly;
            aLinksOnly = linksOnly;

            this.entireWord = data.entireWord;
            this.caseSensitive = data.caseSensitive;
            this.onModalHighlightChange(data.useModalHighlight);
            this.onHighlightAllChange(data.highlightAll);
            data.highlightAll && await this.highlighter.highlight(true, aWord, linksOnly);
            this._iterator && this._iterator.reset();
            var obj;
            Object.defineProperty(this, "_currentMatchesCountResult", {
                configurable: true, enumerable: true,
                get: (val = obj) => {
                    if (val) {
                        if (!val.total) val.total = new Number(0);
                        val.currentFound = val._currentFound;
                    }
                    return obj = val;
                },
                set: val => {
                    if (val) return obj = val;
                    delete this._currentMatchesCountResult;
                    return obj = this._currentMatchesCountResult = val;
                }
            });
            var lfr = this._lastFindResult;
            lfr !== null && lfr != Ci.nsITypeAheadFind.FIND_NOTFOUND
            || Object.defineProperty(this, "_lastFindResult", {
                configurable: true, enumerable: true, get: () => null,
                set: val => {
                    if (val == Ci.nsITypeAheadFind.FIND_WRAPPED)
                        val = Ci.nsITypeAheadFind.FIND_FOUND;
                    delete this._lastFindResult;
                    return this._lastFindResult = val;
                }
            });
        }
        this._requestMatchesCount(aWord, aLinksOnly);
    },

    close() {
        bar.collaped = false;
        this.setProgressListener(false);
        this.setBrowser(null, null);
    },
    startFind() {
        if (this.maybeCollapse(gBrowser.selectedBrowser))
            return true;
        if (bar.hidden)
            this.setBrowser(300),
            this.setProgressListener(true);
        else if (!ctrlFcloseFinbar)
            setTimeout(() => this.updateMatchesCount(), 100);
    },
    onMatchesCountResult(res) {
        if (!("currentFound" in res) || res.total == -1 || res.currentFound)
            return;

        bar._foundMatches.value = `${+res.total || "Нет"} совпадени${
            bar.pluralForm.get(res.total, "е;я;й")
        }.`;
        bar._foundMatches.hidden = false;
        return true;
    },
    _updateMatchesCount() {
        return true;
    },
    _onBrowserKeypress(e) {
        if (!bar.hidden) return;
        if (!e.charCode) return true;
        this.setBrowser(300);
        this.setProgressListener(true);
    },
    receiveMessage(msg) {
        msg.target = bar._browser;
    },

    progressListenerAdded: false,
    setProgressListener(add) {
        if (add) {
            if (this.progressListenerAdded) return;
            this.progressListenerAdded = true;
            gBrowser.addProgressListener(this);
            this.listenCtrlF(true);
        } else {
            if (!this.progressListenerAdded) return;
            this.progressListenerAdded = false;
            gBrowser.removeProgressListener(this);
            this.listenCtrlF(false);
        }
    },
    handleEvent(e) {
        if (
            e.ctrlKey && e.code == "KeyF"
            && !e.shiftKey && !e.altKey && !bar.collapsed
        )
            e.preventDefault(),
            e.stopPropagation(),
            bar.close();
    },
    updateMatchesCount() {
        var str = bar._findField.value;
        if (!str) return;
        var data = {
            entireWord: bar._entireWord,
            caseSensitive: bar._typeAheadCaseSensitive,
            highlightAll: bar._highlightAll,
            useModalHighlight: bar._useModalHighlight
        };
        bar.browser.finder.requestMatchesCount(
            bar._findField.value, 
            {linksOnly: bar._findMode == bar.FIND_LINKS, data}
                );
    },
    maybeCollapse(br) {
        return br.isSyntheticDocument ||
            br.documentContentType == "application/vnd.mozilla.xul+xml";
    },
    setBrowser(updateDelay, br = gBrowser.selectedBrowser) {
        if (bar._browser != br) {
            var b = bar._browser;
            if (b) {
                b.messageManager.removeMessageListener("Findbar:Mouseup", bar);
                b.finder.removeResultListener(bar);
                bar._highlightAll && b.finder.highlight(false);
            }
            if (br) {
                br.messageManager.addMessageListener("Findbar:Mouseup", bar);
                bar._updateBrowserWithState();
            }
            bar._browser = br;
        }
        if (!br) return;
        bar._updateStatusUI();
        bar._foundMatches.value = "";
        br.finder.addResultListener(bar);
        if (
            !(bar.collapsed = this.maybeCollapse(br))
            && br.currentURI.spec != "about:blank"
            && updateDelay !== null
        )
            updateDelay
                ? setTimeout(this.updateMatchesCount, updateDelay)
                : this.updateMatchesCount();
    },
    onStateChange(wpr, req, state) {
        state & Ci.nsIWebProgressListener.STATE_STOP && this.setBrowser();
        },
    onLocationChange(wpr, req) {
        req || Components.stack.formattedStack.includes("SessionStore.jsm")
        || this.setBrowser();
    }
}).init(document.getElementById("appcontent")))();


thrower пишет:

У немцев есть код, но он у меня на [firefox] 60 ESR не работает:
https://www.camp-firefox.de/forum/viewtopic.php?f=16&t=123867&start=15

Есть несколько WE-расширений для [firefox] Quantum. Но в силу того, что они высокоуровнево работают (в отдельном процессе), возникают видимые дергания ("перескакивания") вкладок, когда сперва срабатывает by default браузера, а через десятую долю секунды уже расширение. Не ахти, короче.

Ну, если позволительно будет переопределить функцию браузера, то вот вариант.
Вроде должно работать, в большинстве случаев.

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

Выделить код

Код:

((blurTab, dummy, s, lastSelect) => {
    (s = () => lastSelect = Date.now())();
    addEventListener("TabSelect", s, false, gBrowser.tabContainer || 1);
    gBrowser._blurTab = tab => {
        if (!tab.selected) return;
        var tabToSelect = dummy;
        for(var t of gBrowser.tabs) if (
            !t.hidden && !t.closing
            && t.lastAccessed > tabToSelect.lastAccessed
            && t.lastAccessed < lastSelect
        )
            tabToSelect = t;
        if (tabToSelect == dummy) blurTab.call(gBrowser, tab);
        else gBrowser.selectedTab = tabToSelect;
    }
    addDestructor(() => gBrowser._blurTab = blurTab);
})(gBrowser._blurTab, {lastAccessed: 0});


momo2000 пишет:

А как вызвать это окно по типу паролей window.openDialog('chrome://passwordmgr/content/passwordManager.xul')

Как-то так, наверно.

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

Выделить код

Код:

var win = Services.wm.getMostRecentWindow("Browser:SiteDataSettings");
if (win) win.focus(); else
    ChromeUtils.import("resource:///modules/SiteDataManager.jsm", null).SiteDataManager.updateSites(),
    window.openDialog("chrome://browser/content/preferences/siteDataSettings.xul", "_blank", "");


drage2 пишет:

т.е загнать закладку - всегда в тоже место, а надо в разные

Да, difabor правильно сказал. Можно просто повторить код,
и изменить в первой строке имя настройки, в которую заносится guid папки.
Но если пунктов нужно много, то лучше переписать под такую задачу.

firefan пишет:

Для простоты указания нужной поисковой системы, в коде кнопки можно использовать цифру из строки "order", которую я сам посмотрю файле search.json.json

json.json, order. Как странно.

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

Выделить код

Код:

((topic, popup, menuitem, order = 3) => addEventListener("popupshowing", {
    handleEvent(e) {
        if (e.target != popup || this.souldHide()) return;
        menuitem = document.createElement("menuitem");
        menuitem.id = "context-searchselect-order" + order;
        menuitem.className = "menuitem-iconic";
        menuitem.setAttribute("oncommand", "search();");
        menuitem.search = this.search.bind(this);

        var before = popup.querySelector("#context-searchselect + *");
        popup.insertBefore(menuitem, before);
        addDestructor(() => {
            menuitem.remove();
            this._engine && Services.obs.removeObserver(this, topic);
        }, this);
        order--;
        (this.handleEvent = e => e.target == popup
            && !(menuitem.hidden = this.souldHide()) && this.update()
        )(e);
    },
    search() {
        var submission = this.engine.getSubmission(
            this.selectedText, null, "contextmenu"
        );
        submission && openLinkIn(submission.uri.spec, "tab", {
            postData: submission.postData,
            inBackground: Services.prefs.getBoolPref(
                "browser.search.context.loadInBackground"
            ),
            relatedToCurrent: true
        });
    },
    souldHide() {
        return !gContextMenu.isTextSelected && !gContextMenu.onLink
            || gContextMenu.onImage;
    },
    update() {
        var selectedText = this.selectedText = gContextMenu.isTextSelected
            ? gContextMenu.textSelected : gContextMenu.linkTextStr;
        if (selectedText.length > 15) {
            var len = 15, code = selectedText[15].charCodeAt(0);
            if (code >= 0xDC00 && code <= 0xDFFF) len++;
            selectedText = selectedText.slice(0, len) + gContextMenu.ellipsis;
        }
        menuitem.label = gNavigatorBundle.getFormattedString(
            "contextMenuSearch", [this.engine.name, selectedText]
        );
    },
    _engine: null,
    get engine() {
        return this._engine || this.getEngine();
    },
    getEngine() {
        var engine = Services.search.getEngines()[order]
            || Services.search.defaultEngine;
        engine.iconURI && menuitem.setAttribute(
            "image", engine.iconURI.spec
        );
        Services.obs.addObserver(this, topic, false);
        return this._engine = engine;
    },
    observe() {
        this._engine = null;
        Services.obs.removeObserver(this, topic);
    }
}, false, popup || 1))(
    "browser-search-engine-modified",
    document.getElementById("contentAreaContextMenu")
);

Отредактировано Dumby (21-10-2018 19:09:56)

Отсутствует

 

№1270412-07-2018 11:10:07

drage2
Участник
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 227
UA: Firefox 62.0

Re: Custom Buttons

Dumby
Респект, шо то я тупанул...Жаль ссылки берет без favicon, ни кнопка , ни аддон от Vitaliy не работают в 62...Зато скорость....,это нечто.

Отсутствует

 

№1270512-07-2018 13:52:21

unter_officer
Участник
 
Группа: Members
Откуда: Санкт-Петербург
Зарегистрирован: 27-03-2011
Сообщений: 129
UA: Firefox 47.0

Re: Custom Buttons

Dumby пишет:

А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.

Dumby, а в чём ерунда?
Я проверил на 60.1.0 ESR. Получилось то, что надо.
Спасибо большое.

Отсутствует

 

№1270612-07-2018 13:56:23

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 87
UA: Firefox 47.0

Re: Custom Buttons

Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")

У меня оно висит секунд 20 и это мне не нравится.

Отсутствует

 

№1270712-07-2018 14:29:33

okkamas_knife
We are the Borg.       Resistance is futile.
 
Группа: Members
Зарегистрирован: 21-10-2009
Сообщений: 9349
UA: Seamonkey 2.14

Re: Custom Buttons

в конфиге набери alerts


я помню те времена когда обновления программ убирали проблемы и исправляли баги, а не добавляли их.

Отсутствует

 

№1270812-07-2018 15:50:50

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 860
UA: Firefox 52.0

Re: Custom Buttons

beggrr пишет:

Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")

У меня оно висит секунд 20

Открой вкладку с адресом:  chrome://global/content/alerts/alert.js
Поиск:  function onAlertLoad

Там увидишь константу ALERT_DURATION_IMMEDIATE
И видно, какая настройка проверяется (зависит от версии Firefox).
Далее, если алерт самозакрывающийся, то,
в зависимости от значения настройки, два варианта:

1. Таймаут на эту константу.

2. Слушатель на событие "animationend".
    В этом случае длительность анимации сразу увидишь по адресу
    chrome://global/content/alerts/alert.css

Отсутствует

 

№1270912-07-2018 16:35:08

drage2
Участник
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 227
UA: Firefox 62.0

Re: Custom Buttons

Dumby

Dumby пишет:

Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")

У меня оно висит секунд 20

Не понял,что висит ? Да, хорошая кнопка Find bar, а нельзя ее использовать через гор. клавишу или дв.клик по странице?

Отсутствует

 

№1271012-07-2018 18:03:50

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 87
UA: Firefox 47.0

Re: Custom Buttons

Dumby пишет:

beggrr пишет:

Подскажите, где устанавливается длительность вот этого оповещения
custombuttons.alertSlide(" ", " ")

У меня оно висит секунд 20

Открой вкладку с адресом:  chrome://global/content/alerts/alert.js
Поиск:  function onAlertLoad

Там увидишь константу ALERT_DURATION_IMMEDIATE
И видно, какая настройка проверяется (зависит от версии Firefox).
Далее, если алерт самозакрывающийся, то,
в зависимости от значения настройки, два варианта:

1. Таймаут на эту константу.

2. Слушатель на событие "animationend".
    В этом случае длительность анимации сразу увидишь по адресу
    chrome://global/content/alerts/alert.css

Dumby
Я открыл вкладку  с адресом:  chrome://global/content/alerts/alert.js  там константа ALERT_DURATION_IMMEDIATE действительно была 20 000

Что я сделал. Нашел этот файл alert.js (конечно все делалось при закрытом браузере), распаковал, отредактировал в текстовом редакторе, переправил константу на 3000 и заменил этим файлом тот оригинальный. Результата никакого.
Все равно слайдер держится 20 секунд.

Может я неправильно понял что надо сделать?

Отсутствует

 

№1271112-07-2018 18:22:23

drage2
Участник
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 227
UA: Firefox 62.0

Re: Custom Buttons

beggrr
Еще alert.css есть, там 20сек стоит, хотя и js должно хватить...И startupCache надо сбросить, если правильно все сделано...

Отсутствует

 

№1271212-07-2018 20:31:14

thrower
Участник
 
Группа: Members
Зарегистрирован: 28-11-2013
Сообщений: 181
UA: Firefox 60.0

Re: Custom Buttons

Dumby
спасибо, работает!

После запуска в консоли появилась ошибка: ReferenceError: addDestructor is not defined. [Запускаю весь код на Quantum как юзерхром-скрипт.]
Я удалил строку с addDestructor, и код после этого заработал.

Отсутствует

 

№1271312-07-2018 23:01:20

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 87
UA: Firefox 47.0

Re: Custom Buttons

drage2 пишет:

beggrr
Еще alert.css есть, там 20сек стоит, хотя и js должно хватить...И startupCache надо сбросить, если правильно все сделано...

А как сбросить startupCache?

Отсутствует

 

№1271413-07-2018 00:28:19

drage2
Участник
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 227
UA: Firefox 60.0

Re: Custom Buttons

beggrr
alert.css - поставил 4сек и все ок! в alert.js   - 4000/Сбросить? Просто выкинуть из профиля startupCache. И alert.js не главное, alert.css - верняк!

Отсутствует

 

№1271513-07-2018 02:02:58

difabor
Участник
 
Группа: Members
Зарегистрирован: 21-09-2013
Сообщений: 519
UA: Firefox 52.0
Веб-сайт

Re: Custom Buttons

Dumby пишет:

drage2 пишет:

    т.е загнать закладку - всегда в тоже место, а надо в разные

Да, difabor правильно сказал. Можно просто повторить код,
и изменить в первой строке имя настройки, в которую заносится guid папки.
Но если пунктов нужно много, то лучше переписать под такую задачу.

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

var s = "CB.bookmarkFolderForSaving_1";// или _2, или _3 и т.д.

Затем бы импортировала этот общий код (если он ещё не импортирован) и пользовалась бы им как своим.
Тогда бы большим был бы только "материнский" код, а все остальные кнопки, его использующие, были бы предельно простыми?
И в случае необходимости исправлять надо было бы только в одном месте.


Хорошо, когда у человека есть выбор, но плохо, когда он перед ним стоит ©

Отсутствует

 

№1271613-07-2018 07:11:49

firefan
Участник
 
Группа: Members
Зарегистрирован: 23-06-2016
Сообщений: 16
UA: Firefox 52.0

Re: Custom Buttons

Dumby пишет:

json.json, order. Как странно.

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

Выделить код

Код:

((topic, popup, menuitem, order = 3) => addEventListener("popupshowing", {
    handleEvent(e) {
        if (e.target != popup || this.souldHide()) return;
        menuitem = document.createElement("menuitem");
        menuitem.id = "context-searchselect-order" + order;
        menuitem.className = "menuitem-iconic";
        menuitem.setAttribute("oncommand", "search();");
        menuitem.search = this.search.bind(this);

        var before = popup.querySelector("#context-searchselect + *");
        popup.insertBefore(menuitem, before);
        addDestructor(() => {
            menuitem.remove();
            this._engine && Services.obs.removeObserver(this, topic);
        }, this);
        order--;
        (this.handleEvent = e => e.target == popup
            && !(menuitem.hidden = this.souldHide()) && this.update()
        )(e);
    },
    search() {
        var submission = this.engine.getSubmission(
            this.selectedText, null, "contextmenu"
        );
        submission && openLinkIn(submission.uri.spec, "tab", {
            postData: submission.postData,
            inBackground: Services.prefs.getBoolPref(
                "browser.search.context.loadInBackground"
            ),
            relatedToCurrent: true
        });
    },
    souldHide() {
        return !gContextMenu.isTextSelected && !gContextMenu.onLink
            || gContextMenu.onImage;
    },
    update() {
        var selectedText = this.selectedText = gContextMenu.isTextSelected
            ? gContextMenu.textSelected : gContextMenu.linkTextStr;
        if (selectedText.length > 15) {
            var len = 15, code = selectedText[15].charCodeAt(0);
            if (code >= 0xDC00 && code <= 0xDFFF) len++;
            selectedText = selectedText.slice(0, len) + gContextMenu.ellipsis;
        }
        menuitem.label = gNavigatorBundle.getFormattedString(
            "contextMenuSearch", [this.engine.name, selectedText]
        );
    },
    _engine: null,
    get engine() {
        return this._engine || this.getEngine();
    },
    getEngine() {
        var engine = Services.search.getEngines()[order]
            || Services.search.defaultEngine;
        engine.iconURI && menuitem.setAttribute(
            "image", engine.iconURI.spec
        );
        Services.obs.addObserver(this, topic, false);
        return this._engine = engine;
    },
    observe() {
        this._engine = null;
        Services.obs.removeObserver(this, topic);
    }
}, false, popup || 1))(
    "browser-search-engine-modified",
    document.getElementById("contentAreaContextMenu")
);


Нереально круто. То что нужно. Спасибо большое!

А порядковый номер я смотрю в search.json, потому что у меня поисковиков и их модификаций больше 50, и отсчитывать нужный по списку из настроек слишком утомительно.

Отредактировано firefan (13-07-2018 07:48:04)

Отсутствует

 

№1271713-07-2018 07:49:48

momo2000
Участник
 
Группа: Members
Зарегистрирован: 03-09-2015
Сообщений: 61
UA: Firefox 61.0

Re: Custom Buttons

drage2 пишет:

Как-то так, наверно.

Да, оно):beer:


Dumby пишет:

А если имеется в виду один findbar на окно браузера,
то я пробовал что-то сочинить, типа browser для него переставлять,
но получается какая-то ерунда, сомневаюсь, что подойдёт.

Работает!
Может быть кто подправит код, чтобы осталась только функция "один findbar на окно браузера" без всего лишнего.

Отредактировано momo2000 (14-07-2018 09:30:43)

Отсутствует

 

№1271813-07-2018 21:00:47

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 87
UA: Firefox 47.0

Re: Custom Buttons

drage2 пишет:

beggrr
alert.css - поставил 4сек и все ок! в alert.js   - 4000/Сбросить? Просто выкинуть из профиля startupCache. И alert.js не главное, alert.css - верняк!

Да!
Подправил alert.css и все стало как надо. И startupCache не пришлось сбрасывать, заработало сразу.

Благодарю! :D

Отсутствует

 

№1271914-07-2018 11:52:07

toxa
Участник
 
Группа: Members
Зарегистрирован: 11-04-2012
Сообщений: 223
UA: Chrome 52.0

Re: Custom Buttons

У меня до недавнего времени безотказно работала кнопка find вот с этим кодом

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

Выделить код

Код:

const forceFind = false, forceFindCS = true;

 // Приклеить элемент findbar к странице( #appcontent ) ................................
const fbID = "FindToolbar-m";
delete window.gFindBar;
window.gFindBar = document.getElementById(fbID);
if (!gFindBar) {
    gFindBar = gBrowser.parentNode.insertBefore(document.createElement("findbar"), gBrowser);
    gFindBar.id = fbID;
    gFindBar.setAttribute("browserid", "content");
    gFindBar.clientTop;
    delete window.gFindBarInitialized;
    window.gFindBarInitialized = true;
    gFindBar._selectionMaxLen = 1000;    // лимит символов для поиска
}


// Ctrl+F, показать - скрыть панель поиска ....................................
function toggleFindbar() gFindBar.hidden ? gFindBar.onFindCommand() : gFindBar.close();
addEventListener("keydown", function(e)
    e.keyCode == e.DOM_VK_F && e.ctrlKey && !e.altKey && !e.shiftKey
    && !e.preventDefault() && toggleFindbar()
, false);
this.onclick = function(e) { if (!e.button) toggleFindbar() };


// Показать количество совпадений на панели поиска ................................
const textbox = gFindBar.getElement("findbar-textbox"),
nrm = Ci.nsISelectionController.SELECTION_NORMAL, labID = "hits-m";
var lab = document.getElementById(labID);
if (!lab) {
    lab = textbox.parentNode.insertBefore(document.createElement("label"), textbox);
    lab.id = labID;
}
var curHit, allHits;

function updateHits(arg) {
    if (gFindBar.hidden) return;
    var word = textbox.value;
    if (!word) {
        lab.value = "0/0";
        textbox.removeAttribute("status");
        return;
    }
    var win = arg instanceof Window && arg || content;
    if (win == content) curHit = allHits = 0;
    var findbarFinder = gFindBar._browser.finder;
    var controller = findbarFinder._getSelectionController(win);
    var doc = win.document;

    if (word && controller && doc && doc.documentElement) {
        var body = doc instanceof HTMLDocument && doc.body ? doc.body : doc.documentElement;

        var searchRange = doc.createRange();
        searchRange.selectNodeContents(body);
        var startPt = searchRange.cloneRange();
        startPt.collapse(true);
        var endPt = searchRange.cloneRange();
        endPt.collapse(false);

        var retRange = null;
        var finder = Cc["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Ci.nsIFind);
        finder.caseSensitive = gFindBar._shouldBeCaseSensitive(word);

        while ((retRange = finder.Find(word, searchRange, startPt, endPt))) {
            allHits++;
            if (!curHit) {
                var sel = controller.getSelection(nrm), range;
                if (sel.toString()) range = sel.getRangeAt(0)
                else {
                    var editableNode = findbarFinder._getEditableNode(retRange.startContainer);
                    if (editableNode) sel = editableNode.editor.selectionController.getSelection(nrm);
                    if (sel.toString()) range = sel.getRangeAt(0);
                }
                var comp = range && ["startContainer", "endContainer", "startOffset", "endOffset"]
                    .every(function(prop) range[prop] == retRange[prop]);
                if (comp) curHit = allHits;
            }
            startPt = retRange.cloneRange();
            startPt.collapse(false);
        }
        Array.forEach(win.frames, function(frame) updateHits(frame));
    }
    if (win != content) return;
    allHits ? textbox.removeAttribute("status") : textbox.setAttribute("status", "notfound");
    forceFind && !curHit && allHits && gFindBar._find();
    lab.value = curHit + "/" + allHits;
}
updateHits();


gFindBar.updateHits = updateHits;
function insUpd(methodName, code) {
    const method = gFindBar[methodName];
    gFindBar[methodName] = Function("arguments.callee.method.apply(this, arguments);" + (code || "") + " this.updateHits();");
    gFindBar[methodName].method = method;
    addDestructor(function() gFindBar[methodName] = method);
}
insUpd("_find"); insUpd("_findAgain");
insUpd("_setCaseSensitivity", forceFindCS && " this._find();");


const progressListener = {
    onStateChange: function(wpr, req, state)
        state & Ci.nsIWebProgressListener.STATE_STOP && setTimeout(updateHits, 320),
    onLocationChange: function(wpr, req) !req && updateHits()
};
addDestructor(function() gBrowser.removeProgressListener(progressListener));


function onFindbar() {
    gBrowser[(gFindBar.hidden ? "remove" : "add") + "ProgressListener"](progressListener);
    !gFindBar.hidden && updateHits();
}
onFindbar();
const observer = new MutationObserver(onFindbar);
observer.observe(gFindBar, { attributes: true, attributesFilter: ["hidden"] });
addDestructor(function() observer.disconnect());

lab.addEventListener("mousedown", function(e){
    if (e.button == 0) gFindBar.hidden=true;
    if (e.button == 2) {
      textbox.value="";
      textbox.removeAttribute("status", "notfound");
      updateHits();
    } 
 })


Но после обновления где то с версии 55 стала косячить. Вроде работает, но в текстовых полях счетчик совпадений перестает считать, хотя совпвдения подсвечиваются. В консоли при этом ошибка:
TypeError: findbarFinder._getEditableNode is not a function
Большая просьба подправить код, я уже привык к этой кнопке.


И попутно вопрос: как повесить обработчик onclick  или onwheel на текстовое поле родной кнопки Find браузера? Как к этому текстовому полю обратиться?
C gFindBar._findField не получается, хотя раньше работало.

Отсутствует

 

№1272014-07-2018 23:01:05

drage2
Участник
 
Группа: Members
Откуда: Донецк
Зарегистрирован: 23-11-2017
Сообщений: 227
UA: Firefox 62.0

Re: Custom Buttons

beggrr
Будет проблема с непрочитанной вкладкой, а она будет(61 и т.д.) - обращайся.

Отсутствует

 

№1272116-07-2018 09:22:12

momo2000
Участник
 
Группа: Members
Зарегистрирован: 03-09-2015
Сообщений: 61
UA: Firefox 62.0

Re: Custom Buttons

А можно сделать так, чтобы папка custombuttons была не в папке профиля, а в папке browser-extension-data, как все настройки расширений?

Отредактировано momo2000 (16-07-2018 11:17:27)

Отсутствует

 

№1272217-07-2018 12:16:48

Duche
Участник
 
Группа: Members
Зарегистрирован: 07-02-2016
Сообщений: 145
UA: Firefox 38.0

Re: Custom Buttons

Добрый день. Просьба к специалистам . Возможно решить задачу? Сделать гибрид двух  кнопок https://forum.mozilla-russia.org/viewto … 20#p729920 и https://forum.mozilla-russia.org/viewto … 26#p701226 . Кнопку "Открыть страницу в другом браузере из контекстного меню" по типу кнопки "Запуск портативной программы из портативного браузера", положив портативные браузеры в папку "Soft" в профайле а работали портативные браузеры как кнопка "Открыть страницу в другом браузере из контекстного меню" . Мне было бы удобно положить портативное браузеры  в папку  "Soft" в профайле и не переписывать пути к портативным браузерам для "открытия страницы в другом браузере из контекстного меню" . А так «Всё своё ношу с собой». Заранее спасибо.

Отредактировано Duche (20-07-2018 14:55:29)

Отсутствует

 

№1272317-07-2018 16:56:42

func4ptch4
Участник
 
Группа: Members
Зарегистрирован: 03-05-2018
Сообщений: 49
UA: Firefox 60.0

Re: Custom Buttons

Почему в CB showPopup не пашет, а openPopup пашет в 61фф?
Пришлось многие кнопки на openPopup перевести( неудобно, а раньше только навел сразу видно меню.

bunda1 редко отвечает, может раз в пол года... тут или dumby, или кто-то другой быстрее ответят...

Отредактировано func4ptch4 (17-07-2018 17:23:05)

Отсутствует

 

№1272422-07-2018 13:44:08

firefan
Участник
 
Группа: Members
Зарегистрирован: 23-06-2016
Сообщений: 16
UA: Firefox 52.0

Re: Custom Buttons

Товарищи, помогите пожалуйста.
Для Spotify Web Player нужен глобальный хоткей (OS - Windows), при нажатии на который, даже если браузер свернут, прожималась бы кнопка в веб-плеере "Save to your Favorite Songs" (сердечко такое рядом с названием текущего трека). Если сердечко зеленое, значит песня уже в библиотеке, и прожимать его не нужно.

Вот CSS класс этого элемента:
spoticon-heart-16 - сердечко неактивно, нажимать можно.
spoticon-heart-active-16 - сердечко активно, не нажимать.

Хоть плеер и использует DRM, инструменты разработчика работают по хоткею (Ctrl+Shift+ I) по крайней мере на ESR 52.

Есть аддон Media Keys, который включает глобальные хоткеи для медиа кнопок на клавиатуре, но они контролируют только проигрывание (play/pause/next track/previous track и т.п.), а не добавление трека в фейворитс.

P.S. Зарегистрировать Spotify аккаунт можно с помощью любой US-прокси, например, подойдет бесплатный anonymox. После регистрации можно будет пользоваться web-плеером https://open.spotify.com/browse уже без прокси и без ограничений, а также, поскольку они официально в РФ не работают, то и рекламы нет.

P.P.S. Стендэлон приложение Spotify не использую, потому что из него как раз выкидывает по прошествии пары месяцев и нужно плясать с постоянно включенным прокси/впн.

P.P.P.S. Если кому-то интересно, могу скинуть профиль (или userChrome.css и ссылки на аддоны), чтобы получилось такое (я убрал все лишние элементы браузера, включая скролбар и адресную строку, убрал пустой рекламный блок и добавил возможность закреплять поверх всех окон; здесь скрин minimized окна, но также прекрасно и функционально работает в развернутом виде):
https://i.imgur.com/b8QPUUV.png

Отредактировано firefan (22-07-2018 16:53:19)

Отсутствует

 

№1272522-07-2018 21:31:07

firepox
Участник
 
Группа: Members
Зарегистрирован: 17-11-2011
Сообщений: 294
UA: Firefox 56.0

Re: Custom Buttons

Здравствуйте,
Кнопка сохраняла страницу в firefox 56
В firefox 60 не сохраняет.
custom_buttons-0.0.5.8.9-fixed7.1.xpi
Пожалуйста, помогите :whiteflag:

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

Выделить код

Код:

var saveToFile = function (fileContent, fileName) {
    var uc = Components.classes['@mozilla.org/intl/scriptableunicodeconverter'].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
    uc.charset = 'utf-8';
    fileContent = uc.ConvertFromUnicode(fileContent);

    var nsIFilePicker = Components.interfaces.nsIFilePicker;
    var fp = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
    fp.init(window, '', fp.modeSave);
    fp.defaultString = fileName;
    fp.appendFilters(fp.filterHTML);
    fp.appendFilters(fp.filterAll);
    if(fp.show() == fp.returnCancel) return;
    var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream);
    stream.init(fp.file, 0x02|0x20|0x08, 0666, 0);
    stream.write(fileContent, fileContent.length);
    stream.close();
};
var resolveURL = function (url, base) {
    try {
        var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
        var baseURI = ioService.newURI(base, null, null);
        var absURI = ioService.newURI(url, null, baseURI);
        return absURI.spec;
    } catch (e) {}
};

var getSelWin = function (w) {
    if (w.getSelection().toString()) return w;
    for (var i = 0, f, r; f = w.frames[i]; i++) {
        try {
            if (r = getSelWin(f)) return r;
        } catch(e) {}
    }
};
var encodeImg = function (src, obj) {
    var canvas, img, ret = src;
    if (/^https?:\/\//.test(src)) {
        canvas = doc.createElement('canvas');
        if (!obj || obj.nodeName.toLowerCase() != 'img') {
            img = doc.createElement('img');
            img.src = src;
        } else {
            img = obj;
        };
        if (img.complete) try{
            canvas.width = img.width;
            canvas.height = img.height;
            canvas.getContext('2d').drawImage(img, 0, 0);
            ret = canvas.toDataURL((/\.jpe?g/i.test(src) ? 'image/jpeg' : 'image/png'));
        } catch (e) {};
        if (img != obj) img.src = 'about:blank';
    };
    return ret;
};
var toSrc = function (obj) {
    var strToSrc = function (str) {
        var chr, ret = '', i = 0, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\x22' : '\\\x22', '\\': '\\\\'};
        while (chr = str.charAt(i++)) {
            ret += meta[chr] || chr;
        };
        return '\x22' + ret + '\x22';
    },
    arrToSrc = function (arr) {
        var ret = [];
        for (var i = 0; i < arr.length; i++) {
            ret[i] = toSrc(arr[i]) || 'null';
        };
        return '[' + ret.join(',') + ']';
    },
    objToSrc = function (obj) {
        var val, ret = [];
        for (var prop in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, prop) && (val = toSrc(obj[prop]))) ret.push(strToSrc(prop) + ': ' + val);
        };
        return '{' + ret.join(',') + '}';
    };

    switch (Object.prototype.toString.call(obj).slice(8, -1)) {
        case 'Array': return arrToSrc(obj);
        case 'Boolean':
        case 'Function':
        case 'RegExp': return obj.toString();
        case 'Date': return 'new Date(' + obj.getTime() + ')';
        case 'Math': return 'Math';
        case 'Number': return isFinite(obj) ? String(obj) : 'null';
        case 'Object': return objToSrc(obj);
        case 'String': return strToSrc(obj);
        default: return obj ? (obj.nodeType == 1 && obj.id ? 'document.getElementById(' + strToSrc(obj.id) + ')' : '{}') : 'null';
    }
};

var mainWin = document.commandDispatcher.focusedWindow.top == content ? document.commandDispatcher.focusedWindow : content;
var selWin = getSelWin(mainWin), win = selWin || mainWin, doc = win.document, loc = win.location;
var ele, pEle, clone, reUrl = /(url\(\x22)(.+?)(\x22\))/g;

if (selWin) {
    var rng = win.getSelection().getRangeAt(0);
    pEle = rng.commonAncestorContainer;
    ele = rng.cloneContents();
} else {
    pEle = doc.documentElement;
    ele = (doc.body || doc.getElementsByTagName('body')[0]).cloneNode(true);
};
while (pEle) {
    if (pEle.nodeType == 1) {
        clone = pEle.cloneNode(false);
        clone.appendChild(ele);
        ele = clone;
    };
    pEle = pEle.parentNode
};
var sel = doc.createElement('div');
sel.appendChild(ele);

for (var el, all = sel.getElementsByTagName('*'), i = all.length; i--;) {
    el = all[i];
    if (el.style && el.style.backgroundImage) el.style.backgroundImage = el.style.backgroundImage.replace(reUrl, function (a, prev, url, next) {
        if (!/^[a-z]+:/.test(url)) url = resolveURL(url, loc.href);
        return prev + encodeImg(url) + next;
    });
    switch (el.nodeName.toLowerCase()) {
        case 'link':
        case 'style':
        case 'script': el.parentNode.removeChild(el); break;
        case 'a': 
        case 'area': if (el.hasAttribute('href') && el.getAttribute('href').charAt(0) != '#') el.href = el.href; break;
        case 'img':
        case 'input': if (el.hasAttribute('src')) el.src = encodeImg(el.src, el); break;
        case 'audio':
        case 'video':
        case 'embed':
        case 'frame':
        case 'iframe': if (el.hasAttribute('src')) el.src = el.src; break;
        case 'object': if (el.hasAttribute('data')) el.data = el.data; break;
        case 'form': if (el.hasAttribute('action')) el.action = el.action; break;
    }
};

var head = ele.insertBefore(doc.createElement('head'), ele.firstChild);
var meta = doc.createElement('meta');
meta.httpEquiv = 'content-type';
meta.content = 'text/html; charset=utf-8';
head.appendChild(meta);
var title = doc.getElementsByTagName('title')[0];
if (title) head.appendChild(title.cloneNode(true));

head.copyScript = function (unsafeWin) {
    if ('$' in unsafeWin) return;
    var f = doc.createElement('iframe');
    f.src = 'about:blank';
    f.setAttribute('style', 'position:fixed;left:0;top:0;visibility:hidden;width:0;height:0;');
    doc.documentElement.appendChild(f);
    var str, script = doc.createElement('script');
    script.type = 'text/javascript';
    for (var name in unsafeWin) {
        if (name in f.contentWindow || !/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) continue;
        try {
            str = toSrc(unsafeWin[name]);
            if (!/\{\s*\[native code\]\s*\}/.test(str)) {
                script.appendChild(doc.createTextNode('var ' + name + ' = ' + str.replace(/<\/(script>)/ig, '<\\/$1') + ';\n'));
            }
        } catch (e) {};
    };
    f.parentNode.removeChild(f);
    if (script.childNodes.length) this.nextSibling.appendChild(script);
};
head.copyScript(win.wrappedJSObject || win);

head.copyStyle = function (s) {
    if (!s) return;
    var style = doc.createElement('style');
    style.type = 'text/css';
    if (s.media && s.media.mediaText) style.media = s.media.mediaText;
    try {
        for (var i = 0, rule; rule = s.cssRules[i]; i++) {
            if (rule.type != 3) {
                if((!rule.selectorText || rule.selectorText.indexOf(':') != -1) || (!sel.querySelector || sel.querySelector(rule.selectorText))) {
                    var css = !rule.cssText ? '' : rule.cssText.replace(reUrl, function (a, prev, url, next) {
                        if (!/^[a-z]+:/.test(url)) url = resolveURL(url, s.href || loc.href);
                        if(rule.type == 1 && rule.style && rule.style.backgroundImage) url = encodeImg(url);
                        return prev + url + next;
                    });
                    style.appendChild(doc.createTextNode(css + '\n'));
                }
            } else {
                this.copyStyle(rule.styleSheet);
            }
        }
    } catch(e) {
        if (s.ownerNode) style = s.ownerNode.cloneNode(false);
    };
    this.appendChild(style);
};
var sheets = doc.styleSheets;
for (var j = 0; j < sheets.length; j++) head.copyStyle(sheets[j]);
head.appendChild(doc.createTextNode('\n'));

var doctype = '', dt = doc.doctype;
if (dt && dt.name) {
    doctype += '<!DOCTYPE ' + dt.name;
    if (dt.publicId) doctype += ' PUBLIC \x22' + dt.publicId + '\x22';
    if (dt.systemId) doctype += ' \x22' + dt.systemId + '\x22';
    doctype += '>\n';
};
var fileName = selWin ? win.getSelection().toString() : (title && title.text ? title.text : loc.pathname.split('/').pop());
fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '_').replace(/\s+/g, ' ').slice(0, 100).replace(/^\s+|\s+$/g, '');
fileName += ("  " + new Date().toLocaleFormat("%d.%m.%Y. %H:%M:%S"));
if(!/\.html?$/.test(fileName))fileName += '.html';

saveToFile(doctype + sel.innerHTML + '\n<!-- This document saved from ' + (loc.protocol != 'data:' ? loc.href : 'data:uri') + ' -->', fileName);

Отредактировано firepox (22-07-2018 21:35:42)

Отсутствует

 

Board footer

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