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

В мире Mozilla происходит много интересных событий. Но вам не нужно постоянно посещать новостные сайты, чтобы быть в курсе всех изменений. Зайдите на ленту новостей Mozilla Россия.

№7626-08-2019 20:23:23

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin
Я обычно и в других темах тоже вижу, просто не всегда есть время на осмысленные ответы.

Andrey_Krropotkin пишет

Не знаю правильно это или нет, но вроде работает.

На удивление не все еще отломали. У меня было опасение, что дублирование command/oncommand (от загружаемого оверлея в старых версиях и дописанное вручную) может привести к дублирующейся отработке команд, но, вроде (как минимум, в Firefox 52 и 56), работает нормально.
Добавил, спасибо: https://github.com/Infocatcher/Custom_B … a2ec1e4d2d

Заодно оживил в новых версиях: https://github.com/Infocatcher/Custom_B … fd057a0614


Andrey_Krropotkin пишет

Не решенным осталось еще, что не работает кнопка "Внешний редактор", вообще не как не реагирует.
Может Вы все таки посмотрите, ну просто без кнопки, такое чувство, что что-то не хватает.

Я не пользуюсь... В самых новых – и вовсе редактирование поломало, я открытием во вкладке спасаюсь. Dumby, насколько я помню, тоже говорил, что не пользуется...


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

№7726-08-2019 21:44:51

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

Re: [CB]Attributes Inspector (для разработчиков)

Да-да, не пользуюсь, и Source Editor'ом тоже.
Не потому, что нехорош, а просто не пользуюсь.

Открытие внешнего редактора показалось мне
настолько простым, что думал Андрей подкумекает
это если не в тот же день, то на следующий.
Я просто дописал в начало метода initWindow()

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

Выделить код

Код:

window.edit_button = function edit_button() {
                var panel = document.getElementById(
                    "custombuttons-editbutton-tabbox"
                ).tabpanels.selectedPanel;
                if (/sourceEditor-(.+)/.test(panel.id))
                    panel = document.getElementById(RegExp.$1);
                if (panel.localName == "cbeditor")
                    window.edittarget(panel);
            }


И, ещё «See also» нарисовался:
Bug 1566457 - Loaders summer cleanup
То есть, предположительно, так
скрытый текст

Выделить код

Код:

//var require = Components.utils.import(loader, {}).devtools.require;
                var g = Components.utils.import(loader, {});
                var require = (g.devtools || g).require;

Отсутствует

 

№7826-08-2019 22:00:21

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

Re: [CB]Attributes Inspector (для разработчиков)

Infocatcher и Dumby спасибо и вот еще по этому коду вопрос (может только у меня - не знаю): неправильно работает выделение в URL кнопки, Имя, Изображение. Текст мышкой не выделяется (или как у меня двойной дубль-клик), но если нажать в контекстном меню после этого копировать или выделить все и копировать, то текст нормально копируется (т.е. не видно полосы выделения текста).

Отредактировано Andrey_Krropotkin (26-08-2019 22:11:56)

Отсутствует

 

№7927-08-2019 18:44:46

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

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

(может только у меня - не знаю)

Подтвержаю, у меня на Win7 выделенное там тоже не подсвечивается фоном.
И, я тебе в начало метода initWindow() добавить посоветовал,
нет, в конец, конечно же.

Выделение можно стилем задать, а кодом — ничего лучше не придумал,
тоже в конец метода initWindow()

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

Выделить код

Код:

if(this.platformVersion >= 68) (function(events, win) {
                var listener = function(e) {
                    if(e.type == "unload") return destroy();
                    var sheets = win.document.styleSheets;
                    for(var ind = sheets.length - 1; ind; ind--) {
                        var sheet = sheets.item(ind);
                        if(sheet.href != "resource://devtools/client/themes/common.css")
                            continue;
                        destroy();
                        for(let ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
                            var rule = sheet.cssRules.item(ind);
                            if(rule.selectorText && rule.selectorText == "::selection")
                                return sheet.deleteRule(ind);
                        }
                    }
                }
                var destroy = function() {
                    events.forEach(function(type) {
                        win.removeEventListener(type, listener, false);
                    });
                }
                events.forEach(function(type) {
                    win.addEventListener(type, listener, false);
                });
            })(["mousedown", "keydown", "unload"], window);

Отсутствует

 

№8027-08-2019 20:44:40

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

Re: [CB]Attributes Inspector (для разработчиков)

Dumby спасибо, теперь вообще комфортнее стало.

Отсутствует

 

№8113-09-2019 20:21:55

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 484
UA: unknown 0.0

Re: [CB]Attributes Inspector (для разработчиков)

Dumby есть ещё маленький такой момент, у Infocatcher есть ещё кнопка редактировать во вкладке, при совместной работе с  Source Editor-ом на 68 проблем не было, и в редакторе и во вкладке все было одинаково, на 69, Source Editor работает только в редакторе, а во вкладке как обычно, т. е. Source Editor не применяется, посмотри пожалуйста. В какой из этих двух кнопках где-то неисправность не знаю.

Отсутствует

 

№8214-09-2019 12:42:52

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

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

В какой из этих двух кнопках где-то неисправность не знаю.

В коде Source Editor'а поиск:
isBrowserWindow: function(window) {

Как только увидишь — всё сразу станет ясно.

Отсутствует

 

№8314-09-2019 13:27:08

Andrey_Krropotkin
Участник
 
Группа: Members
Зарегистрирован: 11-11-2011
Сообщений: 484
UA: unknown 0.0

Re: [CB]Attributes Inspector (для разработчиков)

Dumby спасибо, слона и не заметил, заменил, все работает.

Отсутствует

 

№8430-11-2019 15:35:28

Garalf
Участник
 
Группа: Members
Зарегистрирован: 19-09-2017
Сообщений: 316
UA: Firefox 72.0

Re: [CB]Attributes Inspector (для разработчиков)

В 71 перестал работать, также как и dom inspector

Отредактировано Garalf (30-11-2019 15:38:30)

Отсутствует

 

№8506-12-2019 20:37:57

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Garalf пишет

В 71 перестал работать, также как и dom inspector

DOM Inspector и правда снова отвалился...
А вот Attributes Inspector, на первый взгляд, живой:

ntiWJv7.png

mqUnF2d.png

Что конкретно не работает и что пишет в консоль (Ctrl+Shift+J)?


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

№8606-12-2019 21:08:09

kokoss
Участник
 
Группа: Members
Зарегистрирован: 15-02-2018
Сообщений: 1739
UA: Firefox 52.0

Re: [CB]Attributes Inspector (для разработчиков)

Garalf пишет

В 71 перестал работать

В [firefox] 71 работает!

Отредактировано kokoss (06-12-2019 21:09:10)


Win7

Отсутствует

 

№8706-12-2019 22:24:58

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

Re: [CB]Attributes Inspector (для разработчиков)

Да и в 73, на данный момент, работает.

А DOMi, ну давайте попробую скинуть.

DOMi-7.0.{4a1-5}-fx.js

Выделить код

Код:

// DOMi-7.0.{4a1-5}-fx.js
(async re => {
    var gzip = "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";

    var sel = "Select";
    try {sel = Services.strings.createBundle("chrome://global/locale/commonDialogs.properties")
        .GetStringFromName(sel);} catch(ex) {}
    var picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
    picker.init(window, sel + " DOMi 7.0.4a1", picker.modeOpen);
    picker.appendFilter(null, "dom_inspector-7.0.4a1-fx-*.xpi");
    await new Promise(resolve => picker.open(resolve));
    var {file} = picker; if (!file) return;
    var ln = file.leafName;
    if (!re.test(ln)) return alert("???\n" + ln);
    var {fileURL} = picker;

    var xpi = file.parent.clone();
    xpi.append(ln = ln.replace("4a1-", "5-"));
    file.copyTo(file.parent, ln);

    var obs = {}, data;
    var td = new TextDecoder(), te = new TextEncoder();
    var scs = Cc["@mozilla.org/streamConverters;1"].getService(Ci.nsIStreamConverterService);
    var sis = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
    var sl =  Cc["@mozilla.org/network/stream-loader;1"].createInstance(Ci.nsIStreamLoader);

    sis.data = atob(gzip);
    obs.onStreamComplete = (a, b, c, d, result) => data = td.decode(new Uint8Array(result));
    sl.init(obs);
    var converter = scs.asyncConvertData("gzip", "uncompressed", sl, null);

    converter.onStartRequest(null, null);
    var args = [null, null, sis, 0, sis.data.length];
    if (converter.onDataAvailable.length == 4) args.shift();
    converter.onDataAvailable(...args);
    converter.onStopRequest(null, null, null);

    var zw = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
    var mt = Date.now() * 1000, cp = zw.COMPRESSION_DEFAULT;
    var bootstrap = ln.includes("bootstrap");
    var prefix = "jar:" + fileURL.spec + "!/";
    var lr = /^¦(?:\d+)?$/, sep1 = "£", sep2 = "¥";

    zw.open(xpi, 0x04); // PR_RDWR
    for(var item of data.split(sep1)) {
        var [entry, val] = item.split(sep2);
        if (bootstrap && (entry == "manifest.json" || entry == "startup.jsm")) continue;
        if (val == "+") {
            zw.addEntryDirectory(entry, mt, false); continue;
        }
        if (zw.hasEntry(entry)) {
            if (val.includes("¦")) {
                var lines = val.split("\n");
                var oldLines = (await (await fetch(prefix + entry)).text()).split("\n");

                lines.forEach((line, ind) => {
                    if (lr.test(line)) lines[ind] = oldLines[
                        line.length == 1 ? ind : +line.slice(1)
                    ];
                });
                val = lines.join("\n");
            }
            zw.removeEntry(entry, false);
            if (val == "-") continue;
        }
        var stream = Cc["@mozilla.org/io/string-input-stream;1"]
            .createInstance(Ci.nsISupportsCString);
        stream.data = String.fromCharCode(...new Uint8Array(te.encode(val)));
        zw.addEntryStream(entry, mt, cp, stream, false);
        stream.close();
    }
    zw.close(); xpi.reveal();
})(
    /^dom_inspector-7\.0\.4a1-fx-(?:paxmod|bootstrap)\.xpi$/
);

Отсутствует

 

№8816-12-2019 11:59:38

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

Re: [CB]Attributes Inspector (для разработчиков)

Infocatcher, Dumby в кнопке для 71 версии

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

Выделить код

Код:

// https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Editor_Toggle_on_Top
// (c) Infocatcher 2012-2015
// version 0.1.11 - 2015-06-04
 // Hotkey: Ctrl+T 

const watcherId = "customButtonsToggleOnTop_" + this.id;
var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older
var storage = (function() {
    if(!("Services" in window)) // Firefox 3.6 and older
        return Application.storage;
    var global = Components.utils.import("resource://gre/modules/Services.jsm", {});
    var ns = "_cbEditorToggleOnTopStorage";
    var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null));
    return {
        get: function(key, defaultVal) {
            if(key in storage)
                return storage[key];
            return defaultVal;
        },
        set: function(key, val) {
            if(key === null)
                delete storage[key];
            else
                storage[key] = val;
        }
    };
})();
var watcher = storage.get(watcherId, null);
if(!watcher) {
    watcher = {
        btnPos: 0, // 0 - at top right window corner, 1 - at end of tabs, 2 - before dialog buttons spacer
        btnStyle: "toolbarbutton", // "button" or "toolbarbutton"
        btnChecked: true, // use "checked" style: true or false
         // http://www.iconfinder.com/icondetails/12276/16/gps_location_pin_icon
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AgNBjAx4SevkwAAAjxJREFUKM+FUk1oE0EU/mZnRU0U6cFLIT1KKkkNpIcSWwUvVty2l142hZpDoQcPgYQKQkUEz6V6sHgR/KGQQwleQg/xEKRRsIEmga4NoZa2oRGKpJaWmp2Z52UX12Dxg4838+D73ps3jzUYQycIgDc7l0oNAkgqpZ4n5uc/NgHsEEHDKZB/X5OJRGJcSplemJ6+6SZPFStvJ0Ta4eEhTNMcE0I8fDsxcQsAdPwHc6nUoBRCOz4+Rr1eR39//+18Pn/h/cjIGea+eS6VegLgKoBfRPRdKbXGOf8GIBmPx8cty0Kz2YTf74ff70cmkynpNSIAwP7+/t2ZmZnowcGBPDo6+rm1tdWo1Wo7pmnesSwLtm2jWCx+EkJwKSUnoln2wWnv9eTkMBE9TafT0b29PbTbbXDO0Wq1YNs2lpaWVpVSj8ZyuWXhaPg953CtXK6v9fVtr6ys9A4NDXU3Gg24JoVC4fPJycnjsVxu2TtMzgCUAVQAUKVSrwDtzc3NQCQS6d7d3XU7EK1W62twY+ML84i1N4zB5TvgYrVaPTs1NRXNZDKlrq4u+Hw+BAKBy1LK6zYA2xE+6/gqzhgbXl9fnw+FQrPBYPCHlBKjo6NRIjpPRD3kEdbcJWGMgTF2Y3Fx8UE4HE4yxl70WtYCEc1ms9kS51wDcM4r/FOS87BhGK90XTc0TeNuPgggFosNG4axOjAw8PJKxwIxAD26rt9XShWVUtvOWosO2h1RAJAMwCUAPseInGG6UTlm6l/8DZ+nFuAjSdH0AAAAAElFTkSuQmCC",
        iconPinned: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AgNBjIpwH1VRwAAAgdJREFUKM+FkkFoU0EQhr/dtxFSquLBS8CAICISQci1oBWLKaaINL300psXDxH0ItSD4L21UKgUxV4aWnKyiIGaQwio2IQ0PQQpBaEhoaEk0dSQNsnb9WAepg+LPwz/7DD/7O7MiJIQuGEAV3QIiNowV4f0HlA0BskJsI8fo75YLHIEjw3ccIInivVxX1IqcXFu7l4Lnhq4BaD4P4Y6INsHB+zlcpwfH7+zG48PavCIvj8/B64CRxoqXdg8Bd+BqG9xMVJNpaiUy5zxehkcGCC2uppV28Y44rs3V1aCFIt2p15v/MzlSj/S6eKlmZnRairFoW2zmUx+boHVBsvAtEj+fV5Iw4vbS0tBe2uLw04H2+ulUy5zaNu8X17OdOGZgkTX3TADCRumP0xNZY3fz6/9fSr5PNVGg6/x+BfdE/Y3wxJAHtj6wzt5aHsSiQv+4WFfbWcHu9VCeDzdRq32DdgQfZMQom9JjDGngcn19fWF2shI9vrYWNBqNjFCND8mk+8MTDq5s65RWUKIUKFQmA0EAtP3pawdra0xGokE0dqrwe8kvgS2e1cjpURKORyLxTaUUg+UUuciUvIWQq8hU5uYMPOQmQcuu7fAsqxr4XD4jVIqLKW0nPgV4AmEFiDzCF65hQLwK6Ueaq0/aa13e2vddVnHxV3AFsBZYKBXyPSa6bDuFdP/st/BfOD54p3eIQAAAABJRU5ErkJggg==",

        boxId: "cbToggleOnTopBox",
        btnId: "cbToggleOnTopButton",
        onTopAttr: "cbOnTop",
        naAttr: "cbOnTopNA",
        styleId: "cbToggleOnTopStyle",
        get btnTip() {
            var locale = (function() {
                if("Services" in window && "locale" in Services) {
                    var locales = Services.locale.requestedLocales // Firefox 64+
                        || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales();
                    if(locales)
                        return locales[0];
                }
                var prefs = "Services" in window && Services.prefs
                    || Components.classes["@mozilla.org/preferences-service;1"]
                        .getService(Components.interfaces.nsIPrefBranch);
                function pref(name, type) {
                    return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined;
                }
                if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390
                    var locale = pref("general.useragent.locale", "Char");
                    if(locale && locale.substr(0, 9) != "chrome://")
                        return locale;
                }
                return Components.classes["@mozilla.org/chrome/chrome-registry;1"]
                    .getService(Components.interfaces.nsIXULChromeRegistry)
                    .getSelectedLocale("global");
            })().match(/^[a-z]*/)[0];
            if(locale == "ru")
                return "Поверх всех окон (Ctrl+T)";
            return "Always on top (Ctrl+T)";
        },

        REASON_STARTUP: 1,
        REASON_SHUTDOWN: 2,
        REASON_WINDOW_LOADED: 3,
        REASON_WINDOW_CLOSED: 4,

        get obs() {
            delete this.obs;
            return this.obs = Components.classes["@mozilla.org/observer-service;1"]
                .getService(Components.interfaces.nsIObserverService);
        },
        get ww() {
            delete this.ww;
            return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
                .getService(Components.interfaces.nsIWindowWatcher);
        },
        get wm() {
            delete this.wm;
            return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                .getService(Components.interfaces.nsIWindowMediator);
        },
        init: function(reason) {
            this.obs.addObserver(this, "quit-application-granted", false);
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.initWindow(ws.getNext(), reason);
            this.ww.registerNotification(this);
        },
        destroy: function(reason) {
            this.obs.removeObserver(this, "quit-application-granted");
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.destroyWindow(ws.getNext(), reason);
            this.ww.unregisterNotification(this);
        },
        initWindow: function(window, reason) {
            if(!this.isTargetWindow(window))
                return;
            window.addEventListener("keypress", this, true);
            if(this.hasSizeModeChangeEvent)
                window.addEventListener("sizemodechange", this, false);
            else {
                window.addEventListener("resize", this, false); // Can detect only maximize/restore
                this.legacySizeModeChange(window);
            }

            var document = window.document;
            this.removeStyle(document);
            this.addStyle(document);
            var box = document.getElementById(this.boxId);
            box && box.parentNode.removeChild(box);
            box = document.createXULElement("hbox");
            box.id = this.boxId;
            var btn = document.createXULElement(this.btnStyle);
            btn.id = this.btnId;
            if(this.btnChecked) {
                btn.setAttribute("type", "checkbox");
                btn.setAttribute("autoCheck", "false");
            }
            btn.tooltipText = this.btnTip;
            btn.addEventListener("command", this, false);
            box.appendChild(btn);
            switch(this.btnPos) {
                default:
                    box.setAttribute("cbOnTopFloat", "true");
                    document.documentElement.appendChild(box);
                break;
                case 1:
                    box.setAttribute("align", "right");
                    let tabbox = document.getElementById("custombuttons-editbutton-tabbox");
                    let tabs = tabbox.getElementsByTagName("tabs")[0];
                    tabs.parentNode.insertBefore(box, tabs);
                    box.style.marginBottom = -btn.boxObject.height + "px";
                break;
                case 2:
                    box.setAttribute("align", "center");
                    let btnBox = document.documentElement.getButton("accept").parentNode;
                    let insPos = btnBox.firstChild;
                    for(let node = insPos; node; node = node.nextSibling) {
                        if(node.localName == "spacer") {
                            insPos = node;
                            break;
                        }
                    }
                    btnBox.insertBefore(box, insPos);
            }
            this.checkWindowStatus(window, box);
        },
        destroyWindow: function(window, reason) {
            if(reason == this.REASON_WINDOW_CLOSED)
                window.removeEventListener("DOMContentLoaded", this, false); // Window can be closed before DOMContentLoaded
            if(!this.isTargetWindow(window))
                return;
            window.removeEventListener("keypress", this, true);
            if(this.hasSizeModeChangeEvent)
                window.removeEventListener("sizemodechange", this, false);
            else
                window.removeEventListener("resize", this, false);
            var document = window.document;
            var btn = document.getElementById(this.btnId);
            btn.removeEventListener("command", this, false);
            if(reason == this.REASON_SHUTDOWN) {
                let box = btn.parentNode;
                box.parentNode.removeChild(box);
                this.removeStyle(document);
                let xulWin = this.getXulWin(window);
                xulWin.zLevel = xulWin.normalZ;
            }
        },
        isTargetWindow: function(window) {
            return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul";
        },
        observe: function(subject, topic, data) {
            if(topic == "quit-application-granted")
                this.destroy();
            else if(topic == "domwindowopened")
                subject.addEventListener("DOMContentLoaded", this, false);
            else if(topic == "domwindowclosed")
                this.destroyWindow(subject, this.REASON_WINDOW_CLOSED);
        },
        handleEvent: function(e) {
            var trg = e.originalTarget || e.target;
            var window;
            switch(e.type) {
                case "DOMContentLoaded":
                    window = trg.defaultView;
                    window.removeEventListener("DOMContentLoaded", this, false);
                    this.initWindow(window, this.REASON_WINDOW_LOADED);
                break;
                case "keypress":
                    if(
                        !(
                            (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey
                            && String.fromCharCode(e.charCode).toLowerCase() == "t"
                        )
                    )
                        break;
                    e.preventDefault();
                    e.stopPropagation();
                case "command":
                    window = trg.ownerDocument.defaultView.top;
                    this.toggleOnTop(window);
                break;
                case "sizemodechange":
                case "resize":
                    window = trg;
                    this.checkWindowStatus(window);
            }
        },
        get hasSizeModeChangeEvent() {
            var appinfo = "Services" in window && Services.appinfo;
            delete this.hasSizeModeChangeEvent;
            return this.hasSizeModeChangeEvent = appinfo && (
                appinfo.name == "Pale Moon"
                || parseFloat(appinfo.platformVersion) >= 8
            );
        },
        legacySizeModeChange: function(window) {
            var lastState = window.windowState;
            window.setInterval(function(window, _this) {
                var state = window.windowState;
                if(state != lastState)
                    _this.checkWindowStatus(window);
                lastState = state;
            }, 150, window, this);
        },
        checkWindowStatus: function(window, box) {
            if(!box)
                box = window.document.getElementById(this.boxId);
            var na = String(window.windowState != window.STATE_NORMAL);
            if(box.getAttribute(this.naAttr) == na)
                return;
            box.setAttribute(this.naAttr, na);
            //LOG("Set n/a: " + na);
            this.setOnTop(box.firstChild);
        },
        addStyle: function(document) {
            var style = '\
                %box%[cbOnTopFloat] {\n\
                    position: fixed !important;\n\
                    top: 0 !important;\n\
                    right: 0 !important;\n\
                }\n\
                %btn%, %btn% * {\n\
                    margin: 0 !important;\n\
                    padding: 0 !important;\n\
                }\n\
                %btn% > .button-box > .button-icon {\n\
                    margin: -3px -1px !important;\n\
                }\n\
                toolbarbutton%btn% {\n\
                    padding: 0 2px !important;\n\
                }\n\
                %btn% {\n\
                    position: relative !important;\n\
                    z-index: 2147483647 !important;\n\
                    list-style-image: url("%icon%") !important;\n\
                    -moz-user-focus: ignore !important;\n\
                    min-height: 0 !important;\n\
                    min-width: 0 !important;\n\
                }\n\
                %btn%[%onTopAttr%="true"] {\n\
                    list-style-image: url("%iconPinned%") !important;\n\
                }\n\
                %box%[%naAttr%="true"] image {\n\
                    opacity: 0.75 !important;\n\
                }'
                .replace(/%box%/g, "#" + this.boxId)
                .replace(/%btn%/g, "#" + this.btnId)
                .replace(/%onTopAttr%/g, this.onTopAttr)
                .replace(/%icon%/g, this.icon)
                .replace(/%iconPinned%/g, this.iconPinned)
                .replace(/%naAttr%/g, this.naAttr);

            document.insertBefore(document.createProcessingInstruction(
                "xml-stylesheet",
                'id="' + this.styleId + '" href="' + "data:text/css,"
                    + encodeURIComponent(style) + '" type="text/css"'
            ), document.documentElement);
        },
        removeStyle: function(document) {
            var mark = 'id="' + this.styleId + '"';
            for(var child = document.documentElement; child = child.previousSibling; ) {
                if(
                    child.nodeType == child.PROCESSING_INSTRUCTION_NODE
                    && child.data.substr(0, mark.length) == mark
                ) {
                    document.removeChild(child);
                    break;
                }
            }
        },
        getXulWin: function(window) {
            return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                .getInterface(Components.interfaces.nsIWebNavigation)
                .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                .treeOwner
                .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                .getInterface(Components.interfaces.nsIXULWindow);
        },
        
        setOnTop: function(btn, toggle) {
            var document = btn.ownerDocument;
            var root = document.documentElement;
            var onTop = root.getAttribute(this.onTopAttr) == "true";
            var xs = Components. classes ["@mozilla.org/xul/xulstore;1"].
        getService (Components. interfaces. nsIXULStore);
            if(toggle) {
                onTop = !onTop;
                root.setAttribute(this.onTopAttr, onTop);
                if(root.id) {
                    if (!("persist" in document)) {
                    if (!("persist" in xs))
            xs = ChromeUtils. import ("resource://gre/modules/Services.jsm"). Services. xulStore;

                document.persist = function (id, attrr){ 
                
            var node = document. getElementById (root.id);
            if (node) xs. persist (root.id, this.onTopAttr);
                 } 
                         
                    }    
                }
            }
            
            else if(!onTop) // Just opened or restored window always have zLevel == normalZ
                return;
            var window = document.defaultView;
            var state = window.windowState;
            var restore = onTop && state == window.STATE_MINIMIZED;
            if(restore || state == window.STATE_NORMAL) {
                if(restore)
                    onTop = false;
                let xulWin = this.getXulWin(window);
                xulWin.zLevel = onTop ? xulWin.raisedZ : xulWin.normalZ;
            }
            this.checkButton(btn, onTop);
        },
        toggleOnTop: function(window) {
            this.setOnTop(window.document.getElementById(this.btnId), true);
        },
        checkButton: function(btn, onTop) {
            btn.setAttribute(this.onTopAttr, onTop);
            this.btnChecked && btn.setAttribute("checked", onTop);
        }
    };
    storage.set(watcherId, watcher);
    watcher.init(watcher.REASON_STARTUP);
}
function destructor(reason) {
    if(reason == "update" || reason == "delete") {
        watcher.destroy(watcher.REASON_SHUTDOWN);
        storage.set(watcherId, null);
    }
}
if(
    typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
    && addDestructor != ("addDestructor" in window && window.addDestructor)
)
    addDestructor(destructor, this);
else
    this.onDestroy = destructor;


Выдает
скрытый текст
TypeError: btn is null button.js:187:4
destroyWindow chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button58@init line 1 > Function:187
    observe chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button58@init line 1 > Function:205

В кнопке
скрытый текст

Выделить код

Код:

// https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Source_Editor
// http://infocatcher.ucoz.net/js/cb/cbSourceEditor.js
// (c) Infocatcher 2012-2019
// version 0.1.0a9 - 2019-03-01

var options = {
    cssInHelp: true,
    codeMirror: {
        lineNumbers: true,
        enableCodeFolding: true,
        showTrailingSpace: true,
        lineWrapping: false,
        autocomplete: true,
        fontSize: 14
    },
    orion: {
        lineNumbers: true
    }
};
const watcherId = "customButtonsSourceEditor_" + this.id;
var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older
var storage = (function() {
    if(!("Services" in window)) // Firefox 3.6 and older
        return Application.storage;
    var global = Components.utils.import("resource://gre/modules/Services.jsm", {});
    var ns = "_cbSourceEditorStorage";
    var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null));
    return {
        get: function(key, defaultVal) {
            if(key in storage)
                return storage[key];
            return defaultVal;
        },
        set: function(key, val) {
            if(key === null)
                delete storage[key];
            else
                storage[key] = val;
        }
    };
})();
var watcher = storage.get(watcherId, null);
if(!watcher) {
    watcher = {
        REASON_STARTUP: 1,
        REASON_SHUTDOWN: 2,
        REASON_WINDOW_LOADED: 3,
        REASON_WINDOW_CLOSED: 4,

        get obs() {
            delete this.obs;
            return this.obs = Components.classes["@mozilla.org/observer-service;1"]
                .getService(Components.interfaces.nsIObserverService);
        },
        get ww() {
            delete this.ww;
            return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
                .getService(Components.interfaces.nsIWindowWatcher);
        },
        get wm() {
            delete this.wm;
            return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                .getService(Components.interfaces.nsIWindowMediator);
        },
        get platformVersion() {
            delete this.platformVersion;
            return this.platformVersion = parseFloat(Services.appinfo.platformVersion);
        },
        get hasCodeMirror() {
            delete this.hasCodeMirror;
            return this.hasCodeMirror = Services.appinfo.name == "Pale Moon" //~ todo: test
                || this.platformVersion >= 27;
        },
        init: function(reason) {
            if(!this.hasCodeMirror) {
                this.isBrowserWindow = function() {
                    return false;
                };
            }
            this.obs.addObserver(this, "quit-application-granted", false);
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.initWindow(ws.getNext(), reason);
            this.ww.registerNotification(this);
        },
        destroy: function(reason) {
            this.obs.removeObserver(this, "quit-application-granted");
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.destroyWindow(ws.getNext(), reason);
            this.ww.unregisterNotification(this);
        },
        initWindow: function(window, reason, isFrame) {
            if(this.isBrowserWindow(window)) {
                this.initBrowserWindow(window, reason);
                return;
            }
            if(!this.isEditorWindow(window))
                return;
            _log("initWindow(): isFrame: " + isFrame);
            var document = window.document;
            if(isFrame)
                window.addEventListener("unload", this, false);

            Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
                .getService(Components.interfaces.mozIJSSubScriptLoader)
                .loadSubScript("chrome://global/content/globalOverlay.js", window);

            var isCodeMirror = false;
            try { // See chrome://browser/content/devtools/scratchpad.js
                Components.utils.import("resource:///modules/source-editor.jsm", window);
            }
            catch(e) {
                var loader = this.platformVersion >= 44 // See https://bugzilla.mozilla.org/show_bug.cgi?id=912121
                    ? "resource://devtools/shared/Loader.jsm"
                    : "resource://gre/modules/devtools/Loader.jsm";
                var g = Components.utils.import(loader, {});
                var require = (g.devtools || g).require;
                [
                    "devtools/sourceeditor/editor",
                    "devtools/client/sourceeditor/editor", // Firefox 44+
                    "devtools/client/shared/sourceeditor/editor" // Firefox 68+
                ].some(function(path) {
                    try {
                        return window.SourceEditor = require(path);
                    }
                    catch(e) {
                    }
                    return null;
                });
                isCodeMirror = true;
            }
            var SourceEditor = window.SourceEditor;

            // See view-source:chrome://browser/content/devtools/scratchpad.xul
            // + view-source:chrome://browser/content/devtools/source-editor-overlay.xul
            var psXUL = (isCodeMirror
            ? '<!DOCTYPE popupset [\
                <!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">\
                %editMenuStrings;\
                <!ENTITY % sourceEditorStrings SYSTEM "' + (
                    Services.appinfo.name == "Pale Moon" || Services.appinfo.name == "Basilisk"
                        ? this.platformVersion >= 4.1
                            ? "chrome://devtools/locale/sourceeditor.dtd"
                            : "chrome://global/locale/devtools/sourceeditor.dtd"
                        : this.platformVersion >= 45
                            ? "chrome://devtools/locale/sourceeditor.dtd"
                            : "chrome://browser/locale/devtools/sourceeditor.dtd"
                ) + '">\
                %sourceEditorStrings;\
            ]>\
            <popupset id="sourceEditorPopupset"\
                xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\
                <menupopup id="sourceEditorContext"\
                    onpopupshowing="goUpdateSourceEditorMenuItems()">\
                    <menuitem id="menu_undo" label="&undoCmd.label;" accesskey="&undoCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_undo\')" />\
                    <menuitem id="menu_redo" label="&redoCmd.label;" accesskey="&redoCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_redo\')" />\
                    <menuseparator/>\
                    <menuitem id="menu_cut" label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_cut\')" />\
                    <menuitem id="menu_copy" label="&copyCmd.label;" accesskey="&copyCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_copy\')" />\
                    <menuitem id="menu_paste" label="&pasteCmd.label;" accesskey="&pasteCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_paste\')" />\
                    <menuitem id="menu_delete" label="&deleteCmd.label;" accesskey="&deleteCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_delete\')" />\
                    <menuseparator/>\
                    <menuitem id="menu_selectAll" label="&selectAllCmd.label;" accesskey="&selectAllCmd.accesskey;"\
                        oncommand="goDoCommand(\'cmd_selectAll\')" />\
                    <menuseparator/>\
                    <menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\
                    <menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\
                    <menuseparator/>\
                    <menuitem id="se-menu-gotoLine"\
                        label="&gotoLineCmd.label;"\
                        accesskey="&gotoLineCmd.accesskey;"\
                        key="key_gotoLine"\
                        oncommand="goDoCommand(\'cmd_gotoLine\')"/>\
                </menupopup>\
            </popupset>'
            : '<popupset id="sourceEditorPopupset"\
                xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">\
                <menupopup id="sourceEditorContext"\
                    onpopupshowing="goUpdateSourceEditorMenuItems()">\
                    <menuitem id="se-menu-undo"/>\
                    <menuitem id="se-menu-redo"/>\
                    <menuseparator/>\
                    <menuitem id="se-menu-cut"/>\
                    <menuitem id="se-menu-copy"/>\
                    <menuitem id="se-menu-paste"/>\
                    <menuitem id="se-menu-delete"/>\
                    <menuseparator/>\
                    <menuitem id="se-menu-selectAll"/>\
                    <menuseparator/>\
                    <menuitem id="se-menu-find"/>\
                    <menuitem id="se-menu-findAgain"/>\
                    <menuseparator/>\
                    <menuitem id="se-menu-gotoLine"/>\
                </menupopup>\
            </popupset>'
            ).replace(/>\s+</g, "><");

            var ps = this.parseXULFromString(psXUL);
            document.documentElement.appendChild(ps);

            window.setTimeout(function() {
                function appendNode(nodeName, id) {
                    var node = document.createElementNS(xulns, nodeName);
                    node.id = id;
                    document.documentElement.appendChild(node);
                }
                appendNode("commandset", "editMenuCommands");
                appendNode("commandset", "sourceEditorCommands");
                appendNode("keyset", "sourceEditorKeys");
                appendNode("keyset", "editMenuKeys");

                this.loadOverlays(
                    window,
                    function done() {
                        window.setTimeout(function() {
                            var mp = document.getElementById("sourceEditorContext");
                            if(mp.state == "closed")
                                return;
                            Array.prototype.forEach.call(
                                mp.getElementsByAttribute("command", "*"),
                                function(mi) {
                                    var cmd = mi.getAttribute("command");
                                    var controller = document.commandDispatcher
                                        .getControllerForCommand(cmd);
                                    if(controller && !controller.isCommandEnabled(cmd))
                                        mi.setAttribute("disabled", "true");
                                }
                            );
                        }, 0);
                        if(!isCodeMirror)
                            return;
                        // See view-source:chrome://browser/content/devtools/scratchpad.xul in Firefox 27.0a1
                        window.goUpdateSourceEditorMenuItems = function() {
                            goUpdateGlobalEditMenuItems();
                            var commands = ["cmd_undo", "cmd_redo", "cmd_cut", "cmd_paste", "cmd_delete"];
                            commands.forEach(goUpdateCommand);
                        };
                        var cmdsMap = {
                            "se-menu-undo":   "cmd_undo",
                            "se-menu-redo":   "cmd_redo",
                            "se-menu-cut":    "cmd_cut",
                            "se-menu-copy":   "cmd_copy",
                            "se-menu-paste":  "cmd_paste",
                            "se-menu-delete": "cmd_delete",
                            __proto__: null
                        };
                        for(var id in cmdsMap) {
                            var mi = document.getElementById(id);
                            mi && mi.setAttribute("command", cmdsMap[id]);
                        }
                        // We can't use command="cmd_selectAll", menuitem will be wrongly disabled sometimes
                        var enabledCmdsMap = {
                            "se-menu-selectAll": "cmd_selectAll",
                            "se-menu-findAgain": "cmd_findAgain",
                            __proto__: null
                        };
                        for(var id in enabledCmdsMap) {
                            var mi = document.getElementById(id);
                            if(mi) {
                                mi.removeAttribute("command");
                                mi.removeAttribute("disabled");
                                mi.setAttribute("oncommand", "goDoCommand('" + enabledCmdsMap[id] + "');");
                            }
                        }
                        // Workaround: emulate keyboard shortcut
                        var keyCmdsMap = {
                            "menu_find":      { keyCode: KeyboardEvent.DOM_VK_F, charCode: "f".charCodeAt(0), ctrlKey: true },
                            "menu_findAgain": { keyCode: KeyboardEvent.DOM_VK_G, charCode: "g".charCodeAt(0), ctrlKey: true },
                            __proto__: null
                        };
                        var _key = function() {
                            var e = this._keyData;
                            var evt = document.createEvent("KeyboardEvent");
                            evt.initKeyEvent(
                                "keydown", true /*bubbles*/, true /*cancelable*/, window,
                                e.ctrlKey || false, e.altKey || false, e.shiftKey || false, e.metaKey || false,
                                e.keyCode || 0, e.charCode || 0
                            );
                            document.commandDispatcher.focusedElement.dispatchEvent(evt);
                        };
                        for(var id in keyCmdsMap) {
                            var mi = document.getElementById(id);
                            if(mi) {
                                mi.removeAttribute("command");
                                mi.removeAttribute("disabled");
                                mi.setAttribute("oncommand", "this._key();");
                                mi._keyData = keyCmdsMap[id];
                                mi._key = _key;
                            }
                        }
                        // Fix styles for autocomplete tooltip
                        function css(uri) {
                            document.insertBefore(document.createProcessingInstruction(
                                "xml-stylesheet",
                                'href="' + uri + '" type="text/css"'
                            ), document.documentElement);
                        }
                        css("resource://devtools/client/themes/variables.css");
                        css("resource://devtools/client/themes/common.css");
                        css("chrome://devtools/skin/tooltips.css");
                    },
                    ["chrome://global/content/editMenuOverlay.xul", function check(window) {
                        return window.document.getElementById("editMenuCommands").hasChildNodes();
                    }],
                    ["chrome://browser/content/devtools/source-editor-overlay.xul", function check(window) {
                        return window.document.getElementById("sourceEditorCommands").hasChildNodes();
                    }]
                );
            }.bind(this), 500); // We should wait to not break other extensions with document.loadOverlay()

            var tabs = document.getElementById("custombuttons-editbutton-tabbox");
            var selectedPanel = tabs.selectedPanel;
            Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) {
                if("__sourceEditor" in cbEditor)
                    return;
                var code = cbEditor.value;
                var isCSS = options.cssInHelp && cbEditor.id == "help";
                if(isCodeMirror) {
                    var opts = {
                        mode: isCSS
                            ? SourceEditor.modes.css
                            : SourceEditor.modes.js,
                        value: code,
                        lineNumbers: true,
                        enableCodeFolding: true,
                        showTrailingSpace: true,
                        autocomplete: true,
                        contextMenu: "sourceEditorContext"
                    };
                    var optsOvr = options.codeMirror;
                    for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt))
                        opts[opt] = optsOvr[opt];
                    var se = new SourceEditor(opts);
                    if("codeMirror" in se) window.setTimeout(function() {
                        if("insertCommandsController" in se)
                            se.insertCommandsController(); // Pale Moon and Basilisk
                        else
                            this.insertCommandsController(se);
                    }.bind(this), 200);
                }
                else {
                    var se = new SourceEditor();
                }
                se.__isCodeMirror = isCodeMirror;
                var seElt = document.createElementNS(xulns, "hbox");
                if(cbEditor.id)
                    seElt.id = "sourceEditor-" + cbEditor.id;
                seElt.className = "sourceEditor";
                seElt.setAttribute("flex", 1);
                seElt.__sourceEditor = se;
                cbEditor.parentNode.insertBefore(seElt, cbEditor);
                //cbEditor.setAttribute("hidden", "true");
                cbEditor.setAttribute("collapsed", "true");
                cbEditor.parentNode.appendChild(cbEditor);
                cbEditor.__sourceEditor = se;
                cbEditor.__sourceEditorElt = seElt;
                cbEditor.__defineGetter__("value", function() {
                    if("__sourceEditor" in this) {
                        var se = this.__sourceEditor;
                        if(!se.__initialized)
                            return se.__value;
                        return se.getText().replace(/\r\n?|\n\r?/g, "\n");
                    }
                    return this.textbox.value;
                });
                cbEditor.__defineSetter__("value", function(v) {
                    if("__sourceEditor" in this) {
                        var se = this.__sourceEditor;
                        if(!se.__initialized) {
                            var _this = this;
                            se.__onLoadCallbacks.push(function() {
                                _this.value = v;
                            });
                            return se.__value = v;
                        }
                        return se.setText(v.replace(/\r\n?|\n\r?/g, "\n"));
                    }
                    return this.textbox.value = v;
                });
                cbEditor.selectLine = function(lineNumber) {
                    if("__sourceEditor" in this) {
                        var se = this.__sourceEditor;
                        if(!se.__initialized) {
                            var _this = this, args = arguments;
                            se.__onLoadCallbacks.push(function() {
                                _this.selectLine.apply(_this, args);
                            });
                            return undefined;
                        }
                        if(se.__isCodeMirror) {
                            //se.focus();
                            //se.setCursor({ line: lineNumber - 1, ch: 0 });
                            //~ todo: optimize
                            var val = this.value;
                            var lines = val.split("\n");
                            var line = Math.min(lineNumber - 1, lines.length);
                            var ch = lines[line].length;
                            se.focus();
                            return se.setSelection({ line: line, ch: 0 }, { line: line, ch: ch });
                        }
                        else {
                            var selStart = se.getLineStart(lineNumber - 1);
                            var selEnd = se.getLineEnd(lineNumber - 1, false);
                            se.focus();
                            return se.setSelection(selStart, selEnd);
                        }
                    }
                    return this.__proto__.selectLine.apply(this, arguments);
                };

                // For edit_button() from chrome://custombuttons/content/editExternal.js
                seElt.__cbEditor = cbEditor;
                seElt.__defineGetter__("localName", function() {
                    return "cbeditor";
                });
                seElt.__defineGetter__("value", function() {
                    return this.__cbEditor.value;
                });
                seElt.__defineSetter__("value", function(val) {
                    this.__cbEditor.value = val;
                });

                se.__initialized = false;
                se.__onLoadCallbacks = [];
                se.__value = code;
                var onTextChanged = se.__onTextChanged = function() {
                    window.editor.changed = true;
                };
                var isLoaded = reason == this.REASON_WINDOW_LOADED;
                function done() {
                    se.__initialized = true;
                    se.__onLoadCallbacks.forEach(function(fn) {
                        try {
                            fn();
                        }
                        catch(e) {
                            Components.utils.reportError(e);
                        }
                    });
                    delete se.__onLoadCallbacks;
                    delete se.__value;
                }
                if(isCodeMirror) {
                    se.appendTo(seElt).then(function() {
                        try {
                            se.setupAutoCompletion();
                        }
                        catch(e) {
                            Components.utils.reportError(e);
                        }
                        if("setFontSize" in se) try {
                            se.setFontSize(options.codeMirror.fontSize);
                        }
                        catch(e) {
                            Components.utils.reportError(e);
                        }
                        window.setTimeout(function() {
                            window.editor.changed = false; // Strange...
                            window.setTimeout(function() { // Workaround for unexpected onTextChanged() calls
                                if(window.editor.changed && cbEditor.value == code)
                                    window.editor.changed = false;
                            }, 100);
                            se.on("change", onTextChanged);
                            if(isLoaded) {
                                if("clearHistory" in se)
                                    se.clearHistory();
                                else {
                                    var seGlobal = Components.utils.getGlobalForObject(SourceEditor.prototype);
                                    // Note: this is resource://app/modules/devtools/gDevTools.jsm scope in Firefox 34+
                                    var cm = seGlobal.editors.get(se);
                                    cm.clearHistory();
                                }
                            }
                        }, isFrame ? 50 : 15); // Oh, magic delays...
                        done();

                        // See resource:///modules/devtools/sourceeditor/editor.js
                        // doc.defaultView.controllers.insertControllerAt(0, controller(this, doc.defaultView));
                        var controllers = window.controllers; // nsIControllers
                        var controller = se.__cmdController = controllers.getControllerAt(0);
                        if("__cmdControllers" in tabs)
                            tabs.__cmdControllers.push(controller);
                        else {
                            tabs.__cmdControllers = [controller];
                            var onSelect = tabs.__onSelect = function() {
                                var seElt = tabs.selectedPanel;
                                if(!seElt || !("__sourceEditor" in seElt))
                                    return;
                                var se = seElt.__sourceEditor;
                                var curController = se.__cmdController;
                                tabs.__cmdControllers.forEach(function(controller) {
                                    try {
                                        if(controller == curController)
                                            controllers.insertControllerAt(0, controller);
                                        else
                                            controllers.removeController(controller);
                                    }
                                    catch(e) {
                                    }
                                });
                            };
                            tabs.addEventListener("select", onSelect, false);
                            window.setTimeout(onSelect, 0); // Activate controller from selected tab
                        }
                    });
                }
                else {
                    var opts = {
                        mode: isCSS
                            ? SourceEditor.MODES.CSS
                            : SourceEditor.MODES.JAVASCRIPT,
                        showLineNumbers: true,
                        initialText: code,
                        placeholderText: code, // For backward compatibility
                        contextMenu: "sourceEditorContext"
                    };
                    var optsOvr = options.orion;
                    for(var opt in optsOvr) if(optsOvr.hasOwnProperty(opt))
                        opts[opt] = optsOvr[opt];
                    se.init(seElt, opts, function callback() {
                        done();
                        isLoaded && se.resetUndo && se.resetUndo();
                        se.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, onTextChanged);

                        // Hack to use selected editor
                        var controller = se.ui._controller;
                        controller.__defineGetter__("_editor", function() {
                            var seElt = tabs.selectedPanel;
                            var se = seElt && seElt.__sourceEditor
                                || document.getElementsByTagName("cbeditor")[0].__sourceEditor;
                            return se;
                        });
                        controller.__defineSetter__("_editor", function() {});
                    });
                }
            }, this);
            // Force select correct panel (prevent bugs, if selected "Button settings" tab)
            tabs.selectedPanel = selectedPanel.__sourceEditorElt || selectedPanel;

            var origExecCmd = window.editor.execute_oncommand_code;
            window.editor.execute_oncommand_code = function() {
                var cd = document.commandDispatcher;
                var cdFake = {
                    __proto__: cd,
                    get focusedElement() {
                        var selectedTab = tabs.selectedTab;
                        if(selectedTab && selectedTab.id == "code-tab")
                            return document.getElementById("code").textbox.inputField;
                        return cd.focusedElement;
                    }
                };
                document.__defineGetter__("commandDispatcher", function() {
                    return cdFake;
                });
                try {
                    var ret = origExecCmd.apply(this, arguments);
                }
                catch(e) {
                    Components.utils.reportError(e);
                }
                // document.hasOwnProperty("commandDispatcher") == false, so we cat just delete our fake property
                delete document.commandDispatcher;
                return ret;
            };

            window.addEventListener("load", function ensureObserversAdded() {
                window.removeEventListener("load", ensureObserversAdded, false);
                window.setTimeout(function() { window.editor.removeObservers(); }, 0);
                window.setTimeout(function() { window.editor.addObservers();    }, 0);
            }, false);
            // Fix for Ctrl+S hotkey (catched by CodeMirror)
            var hke = this.handleKeyEvent;
            window.addEventListener("keydown",  hke, true);
            window.addEventListener("keypress", hke, true);
            window.addEventListener("keyup",    hke, true);
            
             if(this.platformVersion >= 68) (function(events, win) {
                var listener = function(e) {
                    if(e.type == "unload") return destroy();
                    var sheets = win.document.styleSheets;
                    for(var ind = sheets.length - 1; ind; ind--) {
                        var sheet = sheets.item(ind);
                        if(sheet.href != "resource://devtools/client/themes/common.css")
                            continue;
                        destroy();
                        for(let ind = 0, len = sheet.cssRules.length; ind < len; ind++) {
                            var rule = sheet.cssRules.item(ind);
                            if(rule.selectorText && rule.selectorText == "::selection")
                                return sheet.deleteRule(ind);
                        }
                    }
                }
                var destroy = function() {
                    events.forEach(function(type) {
                        win.removeEventListener(type, listener, false);
                    });
                }
                events.forEach(function(type) {
                    win.addEventListener(type, listener, false);
                });
            })(["mousedown", "keydown", "unload"], window);
            
        },
        insertCommandsController: function(se) {
            this.insertCommandsController = insertCommandsController;
            return insertCommandsController(se);
            // devtools/client/sourceeditor/editor-commands-controller in Pale Moon/Basilisk
            function createController(ed) {
                return {
                    supportsCommand: function (cmd) {
                        switch (cmd) {
                            case "cmd_find":
                            case "cmd_findAgain":
                            case "cmd_gotoLine":
                            case "cmd_undo":
                            case "cmd_redo":
                            case "cmd_delete":
                            case "cmd_selectAll":
                                return true;
                        }

                        return false;
                    },

                    isCommandEnabled: function (cmd) {
                        let cm = ed.codeMirror;

                        switch (cmd) {
                            case "cmd_find":
                            case "cmd_gotoLine":
                            case "cmd_selectAll":
                                return true;
                            case "cmd_findAgain":
                                return cm.state.search != null && cm.state.search.query != null;
                            case "cmd_undo":
                                return ed.canUndo();
                            case "cmd_redo":
                                return ed.canRedo();
                            case "cmd_delete":
                                return ed.somethingSelected();
                        }

                        return false;
                    },

                    doCommand: function (cmd) {
                        let cm = ed.codeMirror;

                        let map = {
                            "cmd_selectAll": "selectAll",
                            "cmd_find": "find",
                            "cmd_undo": "undo",
                            "cmd_redo": "redo",
                            "cmd_delete": "delCharAfter",
                            "cmd_findAgain": "findNext"
                        };

                        if (map[cmd]) {
                            cm.execCommand(map[cmd]);
                            return;
                        }

                        if (cmd == "cmd_gotoLine") {
                            ed.jumpToLine();
                        }
                    },

                    onEvent: function () {}
                };
            }
            function insertCommandsController(sourceEditor) {
                let input = sourceEditor.codeMirror.getInputField();
                let controller = createController(sourceEditor);
                input.controllers.insertControllerAt(0, controller);
            }
        },
        destroyWindow: function(window, reason, isFrame) {
            if(reason == this.REASON_WINDOW_CLOSED)
                window.removeEventListener("DOMContentLoaded", this, false); // Window can be closed before DOMContentLoaded
            if(this.isBrowserWindow(window)) {
                this.destroyBrowserWindow(window, reason);
                return;
            }
            if(!this.isEditorWindow(window) || !("SourceEditor" in window))
                return;
            _log("destroyWindow(): isFrame: " + isFrame);
            var document = window.document;
            if(isFrame)
                window.removeEventListener("unload", this, false);

            var tabs = document.getElementById("custombuttons-editbutton-tabbox");
            if("__onSelect" in tabs) {
                tabs.removeEventListener("select", tabs.__onSelect, false);
                delete tabs.__onSelect;
                delete tabs.__cmdControllers;
            }

            Array.prototype.slice.call(document.getElementsByTagName("cbeditor")).forEach(function(cbEditor) {
                if(!("__sourceEditor" in cbEditor))
                    return;
                var se = cbEditor.__sourceEditor;
                var isCodeMirror = se.__isCodeMirror;
                if(isCodeMirror)
                    se.off("change", se.__onTextChanged);
                else
                    se.removeEventListener(window.SourceEditor.EVENTS.TEXT_CHANGED, se.__onTextChanged);
                delete se.__onTextChanged;
                if(reason == this.REASON_SHUTDOWN) {
                    var val = cbEditor.value;
                    delete cbEditor.value;
                    delete cbEditor.selectLine;

                    var seElt = cbEditor.__sourceEditorElt;
                    seElt.parentNode.insertBefore(cbEditor, seElt);
                    seElt.parentNode.removeChild(seElt);
                    delete cbEditor.__sourceEditorElt;
                    delete cbEditor.__sourceEditor;
                    delete seElt.__sourceEditor;
                    delete seElt.__cbEditor;

                    cbEditor.value = val;
                    window.setTimeout(function() {
                        cbEditor.removeAttribute("collapsed");
                    }, 0);
                }
                se.destroy();
                if("__cmdController" in se) {
                    try {
                        window.controllers.removeController(se.__cmdController);
                    }
                    catch(e) {
                    }
                    delete se.__cmdController;
                }
            }, this);

            if(reason == this.REASON_SHUTDOWN) {
                delete window.editor.execute_oncommand_code;
                [
                    "sourceEditorPopupset",
                    "editMenuCommands",
                    "sourceEditorCommands",
                    "sourceEditorKeys",
                    "editMenuKeys"
                ].forEach(function(id) {
                    var node = document.getElementById(id);
                    node && node.parentNode.removeChild(node);
                });
                [
                    "closeWindow", "canQuitApplication", "goQuitApplication", "goUpdateCommand", "goDoCommand",
                    "goSetCommandEnabled", "goSetMenuValue", "goSetAccessKey", "goOnEvent", "visitLink",
                    "setTooltipText", "NS_ASSERT",
                    "goUpdateGlobalEditMenuItems", "goUpdateUndoEditMenuItems", "goUpdatePasteMenuItems"
                ].forEach(function(p) {
                    delete window[p];
                });
                for(var child = document.documentElement; child = child.previousSibling; ) {
                    if(
                        child.nodeType == child.PROCESSING_INSTRUCTION_NODE
                        && child.data.indexOf("://devtools/") != -1
                    ) {
                        setTimeout(function(child) {
                            child.parentNode.removeChild(child);
                        }, 0, child);
                    }
                }
                delete window.SourceEditor;
            }
            var hke = this.handleKeyEvent;
            window.removeEventListener("keydown",  hke, true);
            window.removeEventListener("keypress", hke, true);
            window.removeEventListener("keyup",    hke, true);
            //~ todo: we have one not removed controller!
            //LOG("getControllerCount(): " + window.controllers.getControllerCount());
        },
        initBrowserWindow: function(window, reason) {
            _log("initBrowserWindow()");
            window.addEventListener("DOMContentLoaded", this, false);
            Array.prototype.forEach.call(window.frames, function(frame) {
                this.initWindow(frame, reason, true);
            }, this);
        },
        destroyBrowserWindow: function(window, reason) {
            _log("destroyBrowserWindow()");
            window.removeEventListener("DOMContentLoaded", this, false);
            Array.prototype.forEach.call(window.frames, function(frame) {
                this.destroyWindow(frame, reason, true);
            }, this);
        },
        isEditorWindow: function(window) {
            return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul";
        },
        isBrowserWindow: function(window) {
            var loc = window.location.href;
            return loc == "chrome://browser/content/browser.xhtml"
                || loc == "chrome://navigator/content/navigator.xul";
        },
        observe: function(subject, topic, data) {
            if(topic == "quit-application-granted")
                this.destroy();
            else if(topic == "domwindowopened")
                subject.addEventListener("DOMContentLoaded", this, false);
            else if(topic == "domwindowclosed")
                this.destroyWindow(subject, this.REASON_WINDOW_CLOSED);
        },
        handleEvent: function(e) {
            switch(e.type) {
                case "DOMContentLoaded":
                    var window = e.target.defaultView || e.target;
                    window.removeEventListener(e.type, this, false);
                    var isFrame = window != e.currentTarget;
                    this.initWindow(window, this.REASON_WINDOW_LOADED, isFrame);
                break;
                case "unload":
                    //var window = e.currentTarget;
                    var window = e.target.defaultView || e.target;
                    window.removeEventListener(e.type, this, false);
                    this.destroyWindow(window, this.REASON_WINDOW_CLOSED, true);
            }
        },
        handleKeyEvent: function(e) {
            if(
                (e.keyCode == e.DOM_VK_S || String.fromCharCode(e.charCode).toUpperCase() == "S")
                && e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey
            ) {
                e.preventDefault();
                e.stopPropagation();
                if(e.type == "keydown") {
                    var window = e.currentTarget;
                    window.editor.updateButton();
                }
            }
        },
        loadOverlays: function() {
            this.runGenerator(this.loadOverlaysGen, this, arguments);
        },

        get loadOverlaysGen() {
            var fn = this._loadOverlaysGen.toString()
                .replace(/__yield/g, "yield");
            try {
                new Function("function test() { yield 0; }");
            }
            catch(e) { // Firefox 58+: SyntaxError: yield expression is only valid in generators
                fn = fn.replace("function", "function*"); // Firefox 26+
            }
            delete this.loadOverlaysGen;
            return this.loadOverlaysGen = eval("(" + fn + ")");
        },
        _loadOverlaysGen: function loadOverlaysGen(window, callback/*, overlayData1, ...*/) {
            var gen = loadOverlaysGen.__generator;
            for(var i = 2, l = arguments.length; i < l; ++i) {
                var overlayData = arguments[i];
                this.loadOverlay(window, overlayData[0], overlayData[1], function() {
                    gen.next();
                });
                __yield(0);
            }
            callback();
            __yield(0);
        },
        loadOverlay: function(window, uri, check, callback) {
            var document = window.document;
            var stopWait = Date.now() + 4500;
            window.setTimeout(function load() {
                _log("loadOverlay(): " + uri);
                var tryAgain = Date.now() + 800;
                try {
                    document.loadOverlay(uri, null);
                }
                catch(e) {
                    window.setTimeout(callback, 0);
                    return;
                }
                window.setTimeout(function ensureLoaded() {
                    if(check(window))
                        window.setTimeout(callback, 0);
                    else if(Date.now() > stopWait)
                        return;
                    else if(Date.now() > tryAgain)
                        window.setTimeout(load, 0);
                    else
                        window.setTimeout(ensureLoaded, 50);
                }, 50);
            }, 0);
        },
        runGenerator: function(genFunc, context, args) {
            var gen = genFunc.apply(context, args);
            genFunc.__generator = gen;
            gen.next();
        },
        parseXULFromString: function(xul) {
            xul = xul.replace(/>\s+</g, "><");
            try {
                return new DOMParser().parseFromString(xul, "application/xml").documentElement;
            }
            catch(e) {
                var dummy = document.createElement("dummy");
                dummy.innerHTML = xul.trimLeft();
                return dummy.firstChild;
            }
        }
    };
    storage.set(watcherId, watcher);
    setTimeout(function() {
        watcher.init(watcher.REASON_STARTUP);
    }, 50);
}
function destructor(reason) {
    if(reason == "update" || reason == "delete") {
        watcher.destroy(watcher.REASON_SHUTDOWN);
        storage.set(watcherId, null);
    }
}
if(
    typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
    && addDestructor != ("addDestructor" in window && window.addDestructor)
)
    addDestructor(destructor, this);
else
    this.onDestroy = destructor;

function ts() {
    var d = new Date();
    var ms = d.getMilliseconds();
    return d.toTimeString().replace(/^.*\d+:(\d+:\d+).*$/, "$1") + ":" + "000".substr(("" + ms).length) + ms + " ";
}
function _log(s) {
    Services.console.logStringMessage("[Custom Buttons :: Source Editor] " + ts() + s);
}


при редактировании во вкладке выдает
скрытый текст
ecurityError: The operation is insecure. button.js:219
    initWindow chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button57@init line 1 > Function:219
    handleEvent chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button57@init line 1 > Function:835

Просто при редактировании работает, но выдает
SecurityError: The operation is insecure. button.js:219
    initWindow chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button57@init line 1 > Function:219
    handleEvent chrome://custombuttons-context/content/button.js?windowId=Firefox&id=custombuttons-button57@init line 1 > Function:835
И последннее в кнопке
скрытый текст

Выделить код

Код:

// https://github.com/Infocatcher/Custom_Buttons/tree/master/Add_New_Buttons_After_This_Button

// Add New Buttons After This Button button for Custom Buttons
// (c) Infocatcher 2012, 2014
// version 0.1.2 - 2014-01-25 

var cbs = custombuttons.cbService;
var windowId = cbs.getWindowId(document.documentURI);
var notificationPrefix = cbs.getNotificationPrefix(windowId);

this.toggleEnabled = function() {
    this.checked = !this.checked;
    if("persist" in document)
        document.persist(this.id, "checked");
    else // Firefox 63+
        Services.xulStore.persist(this, "checked");
};
this.setAttribute("oncommand", "this.toggleEnabled();");

var observer = {
    button: this,
    observe: function(button, topic, data) {
        if(topic != notificationPrefix + "installButton")
            return;
        if(!this.button.checked)
            return;
        var toolbar = this.button.parentNode;
        toolbar.insertBefore(button, this.button.nextSibling);
        custombuttons.persistCurrentSets(toolbar.id, this.button.id, button.id || button.getAttribute("id"));
    }
};
var os = Components.classes["@mozilla.org/observer-service;1"]
    .getService (Components.interfaces.nsIObserverService);
os.addObserver(observer, notificationPrefix + "installButton", false);
var hasObserver = true;

this.onDestroy = function(reason) {
    if(hasObserver) {
        hasObserver = false;
        os.removeObserver(observer, notificationPrefix + "installButton");
    }
    if(reason == "delete" && this.checked)
        this.toggleEnabled();
};


не создается кнопка рядом с текущей
Не могли бы Вы глянуть?

Отредактировано Andrey_Krropotkin (16-12-2019 12:52:47)

Отсутствует

 

№8917-12-2019 19:46:20

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

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

CB_Editor_Toggle_on_Top

Эта та кнопка, которой я пользуюсь сам, и там много чего уже накопилось.
Всё собирался написать Infocatcher'у, но так и не собрался.
А теперь уже страшно даже и подумать, там целый трактат нужен,
и далеко не всё и обосновать бы смог.
Давай скопирую у себя из 73, но следует понимать, что это будет
гораздо хуже, чем если бы правил сам Автор, так что просто на всякий случай.

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

Выделить код

Код:

// https://forum.mozilla-russia.org/viewtopic.php?id=56040
// http://infocatcher.ucoz.net/js/cb/cbEditorToggleOnTop.js
// https://github.com/Infocatcher/Custom_Buttons/tree/master/CB_Editor_Toggle_on_Top

// Custom Buttons Editor: Toggle on Top button for Custom Buttons
// (code for "initialization" section)

// (c) Infocatcher 2012-2015
// version 0.1.11 - 2015-06-04

// Hotkey: Ctrl+T

const watcherId = "customButtonsToggleOnTop_" + this.id;
var {Components} = window; // Prevent garbage collection in Firefox 3.6 and older
var storage = (function() {
    if(!("Services" in window)) // Firefox 3.6 and older
        return Application.storage;
    // Simple replacement for Application.storage
    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1090880
    //var global = Components.utils.getGlobalForObject(Services);
    // Ensure, that we have global object (because window.Services may be overwritten)
    var global = Components.utils.import("resource://gre/modules/Services.jsm", {});
    var ns = "_cbEditorToggleOnTopStorage";
    // Note: Firefox 57+ returns NonSyntacticVariablesObject w/o .Object property
    var storage = global[ns] || (global[ns] = Components.utils.getGlobalForObject(global).Object.create(null));
    return {
        get: function(key, defaultVal) {
            if(key in storage)
                return storage[key];
            return defaultVal;
        },
        set: function(key, val) {
            if(key === null)
                delete storage[key];
            else
                storage[key] = val;
        }
    };
})();
var watcher = storage.get(watcherId, null);
if(!watcher) {
    watcher = {
        btnPos: 0, // 0 - at top right window corner, 1 - at end of tabs, 2 - before dialog buttons spacer
        btnStyle: "button", // "button" or "toolbarbutton"
        btnChecked: true, // use "checked" style: true or false

        // Fogue icons, http://p.yusukekamiyamane.com/
        // http://www.iconfinder.com/icondetails/12276/16/gps_location_pin_icon
        icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AgNBjAx4SevkwAAAjxJREFUKM+FUk1oE0EU/mZnRU0U6cFLIT1KKkkNpIcSWwUvVty2l142hZpDoQcPgYQKQkUEz6V6sHgR/KGQQwleQg/xEKRRsIEmga4NoZa2oRGKpJaWmp2Z52UX12Dxg4838+D73ps3jzUYQycIgDc7l0oNAkgqpZ4n5uc/NgHsEEHDKZB/X5OJRGJcSplemJ6+6SZPFStvJ0Ta4eEhTNMcE0I8fDsxcQsAdPwHc6nUoBRCOz4+Rr1eR39//+18Pn/h/cjIGea+eS6VegLgKoBfRPRdKbXGOf8GIBmPx8cty0Kz2YTf74ff70cmkynpNSIAwP7+/t2ZmZnowcGBPDo6+rm1tdWo1Wo7pmnesSwLtm2jWCx+EkJwKSUnoln2wWnv9eTkMBE9TafT0b29PbTbbXDO0Wq1YNs2lpaWVpVSj8ZyuWXhaPg953CtXK6v9fVtr6ys9A4NDXU3Gg24JoVC4fPJycnjsVxu2TtMzgCUAVQAUKVSrwDtzc3NQCQS6d7d3XU7EK1W62twY+ML84i1N4zB5TvgYrVaPTs1NRXNZDKlrq4u+Hw+BAKBy1LK6zYA2xE+6/gqzhgbXl9fnw+FQrPBYPCHlBKjo6NRIjpPRD3kEdbcJWGMgTF2Y3Fx8UE4HE4yxl70WtYCEc1ms9kS51wDcM4r/FOS87BhGK90XTc0TeNuPgggFosNG4axOjAw8PJKxwIxAD26rt9XShWVUtvOWosO2h1RAJAMwCUAPseInGG6UTlm6l/8DZ+nFuAjSdH0AAAAAElFTkSuQmCC",
        iconPinned: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AgNBjIpwH1VRwAAAgdJREFUKM+FkkFoU0EQhr/dtxFSquLBS8CAICISQci1oBWLKaaINL300psXDxH0ItSD4L21UKgUxV4aWnKyiIGaQwio2IQ0PQQpBaEhoaEk0dSQNsnb9WAepg+LPwz/7DD/7O7MiJIQuGEAV3QIiNowV4f0HlA0BskJsI8fo75YLHIEjw3ccIInivVxX1IqcXFu7l4Lnhq4BaD4P4Y6INsHB+zlcpwfH7+zG48PavCIvj8/B64CRxoqXdg8Bd+BqG9xMVJNpaiUy5zxehkcGCC2uppV28Y44rs3V1aCFIt2p15v/MzlSj/S6eKlmZnRairFoW2zmUx+boHVBsvAtEj+fV5Iw4vbS0tBe2uLw04H2+ulUy5zaNu8X17OdOGZgkTX3TADCRumP0xNZY3fz6/9fSr5PNVGg6/x+BfdE/Y3wxJAHtj6wzt5aHsSiQv+4WFfbWcHu9VCeDzdRq32DdgQfZMQom9JjDGngcn19fWF2shI9vrYWNBqNjFCND8mk+8MTDq5s65RWUKIUKFQmA0EAtP3pawdra0xGokE0dqrwe8kvgS2e1cjpURKORyLxTaUUg+UUuciUvIWQq8hU5uYMPOQmQcuu7fAsqxr4XD4jVIqLKW0nPgV4AmEFiDzCF65hQLwK6Ueaq0/aa13e2vddVnHxV3AFsBZYKBXyPSa6bDuFdP/st/BfOD54p3eIQAAAABJRU5ErkJggg==",

        boxId: "cbToggleOnTopBox",
        btnId: "cbToggleOnTopButton",
        onTopAttr: "cbOnTop",
        naAttr: "cbOnTopNA",
        styleId: "cbToggleOnTopStyle",
        get btnTip() {
            var locale = (function() {
                if("Services" in window && "locale" in Services) {
                    var locales = Services.locale.requestedLocales // Firefox 64+
                        || Services.locale.getRequestedLocales && Services.locale.getRequestedLocales();
                    if(locales)
                        return locales[0];
                }
                var prefs = "Services" in window && Services.prefs
                    || Components.classes["@mozilla.org/preferences-service;1"]
                        .getService(Components.interfaces.nsIPrefBranch);
                function pref(name, type) {
                    return prefs.getPrefType(name) != prefs.PREF_INVALID ? prefs["get" + type + "Pref"](name) : undefined;
                }
                if(!pref("intl.locale.matchOS", "Bool")) { // Also see https://bugzilla.mozilla.org/show_bug.cgi?id=1414390
                    var locale = pref("general.useragent.locale", "Char");
                    if(locale && locale.substr(0, 9) != "chrome://")
                        return locale;
                }
                return Components.classes["@mozilla.org/chrome/chrome-registry;1"]
                    .getService(Components.interfaces.nsIXULChromeRegistry)
                    .getSelectedLocale("global");
            })().match(/^[a-z]*/)[0];
            if(locale == "ru")
                return "Поверх всех окон (Ctrl+T)";
            return "Always on top (Ctrl+T)";
        },

        REASON_STARTUP: 1,
        REASON_SHUTDOWN: 2,
        REASON_WINDOW_LOADED: 3,
        REASON_WINDOW_CLOSED: 4,

        get obs() {
            delete this.obs;
            return this.obs = Components.classes["@mozilla.org/observer-service;1"]
                .getService(Components.interfaces.nsIObserverService);
        },
        get ww() {
            delete this.ww;
            return this.ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
                .getService(Components.interfaces.nsIWindowWatcher);
        },
        get wm() {
            delete this.wm;
            return this.wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                .getService(Components.interfaces.nsIWindowMediator);
        },
        init: function(reason) {
            this.obs.addObserver(this, "quit-application-granted", false);
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.initWindow(ws.getNext(), reason);
            this.ww.registerNotification(this);
        },
        destroy: function(reason) {
            this.obs.removeObserver(this, "quit-application-granted");
            var ws = this.wm.getEnumerator(null);
            while(ws.hasMoreElements())
                this.destroyWindow(ws.getNext(), reason);
            this.ww.unregisterNotification(this);
        },
        checkOnTopAttr: function(window) {
            if(this.version < 71)
                return this.checkOnTopAttr = function() {}
            var attr = this.onTopAttr;
            var id = window.document.documentElement.id;
            var xs = Cu.import("resource://gre/modules/Services.jsm", {})
                .Services.xulStore;
            (this.checkOnTopAttr = function(window) {
                var de = window.document.documentElement;
                if(de.hasAttribute(attr))
                    return;
                var url = window.location.href;
                if(xs.hasValue(url, id, attr))
                    de.setAttribute(attr, xs.getValue(url, id, attr));
            })(window);
        },
        initWindow: function(window, reason) {
            if(!this.isTargetWindow(window))
                return;
            window.addEventListener("keypress", this, true);
            if(this.hasSizeModeChangeEvent)
                window.addEventListener("sizemodechange", this, false);
            else {
                window.addEventListener("resize", this, false); // Can detect only maximize/restore
                this.legacySizeModeChange(window);
            }
            this.checkOnTopAttr(window);

            var document = window.document;
            this.removeStyle(document);
            this.addStyle(document);
            var box = document.getElementById(this.boxId);
            box && box.parentNode.removeChild(box);
            box = document.createElementNS(xulns, "hbox");
            box.id = this.boxId;
            var btn = document.createElementNS(xulns, this.btnStyle);
            btn.id = this.btnId;
            if(this.btnChecked) {
                btn.setAttribute("type", "checkbox");
                btn.setAttribute("autoCheck", "false");
            }
            btn.tooltipText = this.btnTip;
            btn.addEventListener("command", this, false);
            box.appendChild(btn);
            switch(this.btnPos) {
                default:
                    box.setAttribute("cbOnTopFloat", "true");
                    document.documentElement.appendChild(box);
                break;
                case 1:
                    box.setAttribute("align", "right");
                    let tabbox = document.getElementById("custombuttons-editbutton-tabbox");
                    let tabs = tabbox.getElementsByTagName("tabs")[0];
                    tabs.parentNode.insertBefore(box, tabs);
                    box.style.marginBottom = -(btn.boxObject || btn.getBoundingClientRect()).height + "px";

                break;
                case 2:
                    box.setAttribute("align", "center");
                    let btnBox = document.documentElement.getButton("accept").parentNode;
                    let insPos = btnBox.firstChild;
                    for(let node = insPos; node; node = node.nextSibling) {
                        if(node.localName == "spacer") {
                            insPos = node;
                            break;
                        }
                    }
                    btnBox.insertBefore(box, insPos);
            }
            this.checkWindowStatus(window, box);
            //this.setOnTop(btn);
        },
        destroyWindow: function(window, reason) {
            if(reason == this.REASON_WINDOW_CLOSED)
                window.removeEventListener("DOMContentLoaded", this, false); // Window can be closed before DOMContentLoaded
            if(!this.isTargetWindow(window))
                return;
            window.removeEventListener("keypress", this, true);
            if(this.hasSizeModeChangeEvent)
                window.removeEventListener("sizemodechange", this, false);
            else
                window.removeEventListener("resize", this, false);
            var document = window.document;
            var btn = this.shadow(document).getElementById(this.btnId);

            btn.removeEventListener("command", this, false);
            if(reason == this.REASON_SHUTDOWN) {
                let box = btn.parentNode;
                box.parentNode.removeChild(box);
                this.removeStyle(document);
                let xulWin = this.getXulWin(window);
                xulWin.zLevel = xulWin.normalZ;
            }
        },
        isTargetWindow: function(window) {
            return window.location.href.substr(0, 41) == "chrome://custombuttons/content/editor.xul";
        },
        observe: function(subject, topic, data) {
            if(topic == "quit-application-granted")
                this.destroy();
            else if(topic == "domwindowopened")
                subject.addEventListener("DOMContentLoaded", this, false);
            else if(topic == "domwindowclosed")
                this.destroyWindow(subject, this.REASON_WINDOW_CLOSED);
        },
        handleEvent: function(e) {
            var trg = e.originalTarget || e.target;
            var window;
            switch(e.type) {
                case "DOMContentLoaded":
                    window = trg.defaultView;
                    window.removeEventListener("DOMContentLoaded", this, false);
                    this.initWindow(window, this.REASON_WINDOW_LOADED);
                break;
                case "keypress":
                    if(
                        !(
                            (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey
                            && String.fromCharCode(e.charCode).toLowerCase() == "t"
                        )
                    )
                        break;
                    e.preventDefault();
                    e.stopPropagation();
                case "command":
                    window = trg.ownerDocument.defaultView.top;
                    this.toggleOnTop(window);
                break;
                case "sizemodechange":
                case "resize":
                    window = trg;
                    this.checkWindowStatus(window);
            }
        },
        version: 0,
        get hasSizeModeChangeEvent() {
            var appinfo = "Services" in window && Services.appinfo;
            delete this.hasSizeModeChangeEvent;
            return this.hasSizeModeChangeEvent = appinfo && (
                appinfo.name == "Pale Moon"
                || (this.version = parseFloat(appinfo.platformVersion)) >= 8
            );
        },
        legacySizeModeChange: function(window) {
            var lastState = window.windowState;
            window.setInterval(function(window, _this) {
                var state = window.windowState;
                if(state != lastState)
                    _this.checkWindowStatus(window);
                lastState = state;
            }, 150, window, this);
        },
        checkWindowStatus: function(window, box) {
            if(!box)
                box = this.shadow(window.document).getElementById(this.boxId);
            var na = String(window.windowState != window.STATE_NORMAL);
            if(box.getAttribute(this.naAttr) == na)
                return;
            box.setAttribute(this.naAttr, na);
            //LOG("Set n/a: " + na);
            this.setOnTop(box.firstChild);
        },
        addStyle: function(document) {
            var style = '\
                %box%[cbOnTopFloat] {\n\
                    display: block !important;\n\
                    position: fixed !important;\n\
                    top: 0 !important;\n\
                    right: 0 !important;\n\
                }\n\
                %btn%, %btn% * {\n\
                    margin: 0 !important;\n\
                    padding: 0 !important;\n\
                }\n\
                %btn% > .button-box > .button-icon {\n\
                    margin: -3px -1px !important;\n\
                }\n\
                toolbarbutton%btn% {\n\
                    padding: 0 2px !important;\n\
                }\n\
                %btn% {\n\
                    position: relative !important;\n\
                    z-index: 2147483647 !important;\n\
                    list-style-image: url("%icon%") !important;\n\
                    -moz-user-focus: ignore !important;\n\
                    min-height: 0 !important;\n\
                    min-width: 0 !important;\n\
                }\n\
                %btn%[%onTopAttr%="true"] {\n\
                    list-style-image: url("%iconPinned%") !important;\n\
                }\n\
                %box%[%naAttr%="true"] image {\n\
                    opacity: 0.75 !important;\n\
                }'
                .replace(/%box%/g, "#" + this.boxId)
                .replace(/%btn%/g, "#" + this.btnId)
                .replace(/%onTopAttr%/g, this.onTopAttr)
                .replace(/%icon%/g, this.icon)
                .replace(/%iconPinned%/g, this.iconPinned)
                .replace(/%naAttr%/g, this.naAttr);

            if(this.shadow(document, style))
                return;
            document.insertBefore(document.createProcessingInstruction(
                "xml-stylesheet",
                'id="' + this.styleId + '" href="' + "data:text/css,"
                    + encodeURIComponent(style) + '" type="text/css"'
            ), document.documentElement);
        },
        removeStyle: function(document) {
            if(this.shadow(document, false))
                return;
            var mark = 'id="' + this.styleId + '"';
            for(var child = document.documentElement; child = child.previousSibling; ) {
                if(
                    child.nodeType == child.PROCESSING_INSTRUCTION_NODE
                    && child.data.substr(0, mark.length) == mark
                ) {
                    document.removeChild(child);
                    break;
                }
            }
        },
        shadow: function(document, arg) {
            var sr = document.documentElement.shadowRoot;
            if(this.btnPos != 2 || !sr)
                return (this.shadow = function(document, arg) {
                    return arg === undefined ? document : false;
                })(document, arg);

            if(arg === undefined)
                return sr;
            var st = sr.querySelector("style"), id = this.styleId;
            if(arg) {
                st.append(arg);
                st.lastChild[id] = true;
            }
            else {
                var tn = Array.from(st.childNodes).find(function(node) {
                    return id in node;
                });
                tn && tn.remove();
            }
            return true;
        },
        getXulWin: function(window) {
            return (
                    window.docShell && window.docShell instanceof Components.interfaces.nsIDocShell
                        ? window.docShell
                        : window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                            .getInterface(Components.interfaces.nsIWebNavigation)
                            .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                )
                    .treeOwner
                    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                    .getInterface(Components.interfaces.nsIXULWindow || Ci.nsIAppWindow);
        },
        setOnTop: function(btn, toggle) {
            var document = btn.ownerDocument;
            var root = document.documentElement;
            var onTop = root.getAttribute(this.onTopAttr) == "true";
            if(toggle) {
                onTop = !onTop;
                root.setAttribute(this.onTopAttr, onTop);
                if(root.id) {
                    if("persist" in document)
                        document.persist(root.id, this.onTopAttr);
                    else // Firefox 63+
                        Services.xulStore.persist(root, this.onTopAttr);
                }
            }
            else if(!onTop) // Just opened or restored window always have zLevel == normalZ
                return;
            var window = document.defaultView;
            var state = window.windowState;
            // Strange glitches with minimized "raisedZ" window...
            var restore = onTop && state == window.STATE_MINIMIZED;
            if(restore || state == window.STATE_NORMAL) {
                if(restore)
                    onTop = false;
                let xulWin = this.getXulWin(window);
                xulWin.zLevel = onTop ? xulWin.raisedZ : xulWin.normalZ;
                //LOG("Set on top: " + onTop);
            }
            this.checkButton(btn, onTop);
        },
        toggleOnTop: function(window) {
            this.setOnTop(this.shadow(window.document).getElementById(this.btnId), true);
        },
        checkButton: function(btn, onTop) {
            btn.setAttribute(this.onTopAttr, onTop);
            this.btnChecked && btn.setAttribute("checked", onTop);
        }
    };
    storage.set(watcherId, watcher);
    watcher.init(watcher.REASON_STARTUP);
}
function destructor(reason) {
    if(reason == "update" || reason == "delete") {
        watcher.destroy(watcher.REASON_SHUTDOWN);
        storage.set(watcherId, null);
    }
}
if(
    typeof addDestructor == "function" // Custom Buttons 0.0.5.6pre4+
    && addDestructor != ("addDestructor" in window && window.addDestructor)
)
    addDestructor(destructor, this);
else
    this.onDestroy = destructor;


Остальными двумя не пользуюсь, но, похоже, здесь это пресловутое западло.
Задело многое, в своё время даже их дражайший Firefox Screenshots под раздачу угодил.
Вобщем, парочка не слишком оптимальных фиксов, чтоб проверить
для CB_Source_Editor

Выделить код

Код:

var ps = this.parseXULFromString(psXUL);

            if(isFrame && "parseFromSafeString" in window.DOMParser.prototype)
                ps = window.MozXULElement.parseXULToFragment(ps.outerHTML);

            document.documentElement.appendChild(ps);


для Add_New_Buttons_After_This_Button

Выделить код

Код:

//toolbar.insertBefore(button, this.button.nextSibling);
        toolbar.insertBefore(
            custombuttons.cbCloneNode(button),
            this.button.nextSibling
        );

Отсутствует

 

№9017-12-2019 20:01:12

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

Re: [CB]Attributes Inspector (для разработчиков)

Dumby да все работает, спасибо.

Отсутствует

 

№9119-12-2019 00:10:15

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Dumby
О! Спасибо!
Начал потихоньку внедрять: https://github.com/Infocatcher/Custom_B … 6e8a3ad252, пока только Toggle on Top (и то частично).

Добавлено 19-12-2019 00:11:24
P.S. И отдельное спасибо за оживленный DOMi – попробовать успел, но не отписался...

Отредактировано Infocatcher (19-12-2019 00:11:24)


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

№9206-01-2020 16:28:39

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

Re: [CB]Attributes Inspector (для разработчиков)

Infocatcher
Насчёт Source Editor'а и Firefox 73.
В нелокализированной версии покромсали editMenuOverlay.dtd
и там вместо <popupset>'а образуется <parsererror>, длиннющий такой,
больше двадцати тысяч пикселей.

По всему коду лазать не стал, записал всё про контекстное меню
отдельным блоком в if, а существующее задвинул в else.
Получилось не очень, «Найти ещё раз» находит не следующее,
а перескакивает через одно.

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

Выделить код

Код:

var SourceEditor = window.SourceEditor;

            if(this.platformVersion >= 73) {
                var psXUL = '<popupset id="sourceEditorPopupset">\
                    <linkset>\
                        <html:link rel="localization" href="toolkit/global/textActions.ftl" />\
                    </linkset>\
                    <menupopup id="sourceEditorContext"\
                        onpopupshowing="popupHandler(event.target)"\
                        oncommand="popupHandler(event.target)">\
\
                        <menuitem id="menu_undo" data-l10n-id="text-action-undo" />\
                        <menuitem id="menu_redo" data-l10n-id="text-action-redo" />\
                        <menuseparator/>\
                        <menuitem id="menu_cut" data-l10n-id="text-action-cut" />\
                        <menuitem id="menu_copy" data-l10n-id="text-action-copy" />\
                        <menuitem id="menu_paste" data-l10n-id="text-action-paste" />\
                        <menuitem id="menu_delete" data-l10n-id="text-action-delete" />\
                        <menuseparator/>\
                        <menuitem id="menu_selectAll" data-l10n-id="text-action-select-all" />\
                        <menuseparator/>\
                        <menuitem id="menu_find" label="&findCmd.label;" accesskey="&findCmd.accesskey;" />\
                        <menuitem id="menu_findAgain" label="&findAgainCmd.label;" accesskey="&findAgainCmd.accesskey;" />\
                        <menuseparator/>\
                        <menuitem id="se-menu-gotoLine" label="&gotoLineCmd.label;"\
                            accesskey="&gotoLineCmd.accesskey;" key="key_gotoLine" />\
                    </menupopup>\
                </popupset>';
                var ps = window.MozXULElement.parseXULToFragment(psXUL, [
                    "chrome://global/locale/editMenuOverlay.dtd",
                    "chrome://devtools/locale/sourceeditor.dtd"
                ]);
                if(!this.popupHandler) {
                    var commands = {module: {}};
                    ps.querySelectorAll("menuitem").forEach(function(menuitem) {
                        commands[menuitem.id] = menuitem.id.replace(/^(se-)?menu./, "cmd_");
                    });
                    Services.scriptloader.loadSubScript(
                        "resource://devtools/client/shared/sourceeditor/editor-commands-controller.js", commands
                    );
                    var createController = function(editor) {
                        var res = editor.popupCmdController = commands.createController(editor);
                        res.docShell = editor.container.contentWindow.docShell;
                        return res;
                    }
                    var getObj = function(cmd, controller) {
                        return controller.supportsCommand(cmd) ? controller: controller.docShell;
                    }
                    var setDisabled = function(menuitem) {
                        var cmd = commands[menuitem.id];
                        menuitem.disabled = !getObj(cmd, this).isCommandEnabled(cmd);
                    }
                    this.popupHandler = function(node) {
                        var ed = node.ownerDocument.activeElement.contentWindow.editor;
                        var controller = ed.popupCmdController || createController(ed);
                        var cmd = commands[node.id];
                        if(cmd) getObj(cmd, controller).doCommand(cmd);
                        else node.menuitems.forEach(setDisabled, controller);
                    }
                }
                var popup = ps.querySelector("menupopup");
                popup.menuitems = popup.querySelectorAll("menuitem");
                popup.popupHandler = this.popupHandler;

            } else {
                // See view-source:chrome://browser/content/devtools/scratchpad.xul
                // + view-source:chrome://browser/content/devtools/source-editor-overlay.xul
                var psXUL = (isCodeMirror

                // .......
            }
            document.documentElement.appendChild(ps);


Но я не об этом.

Лисе сделали XUL content type лоботомию, и теперь
документ CB-редактора это XMLDocument :usch:.
Скрипты не исполняются и кустомэлементщина окно игнорирует.
Приходится подгружать скриптлоадером вручную.

И вот здесь нарисовалась какая-то нестыковка.
При попытке открыть окно редактора, браузер зависает, грузит процессор,
и Windows дописывает ему в заголовок своё «(Не отвечает)».
Причём, если открыть во вкладке, то такого не происходит.

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

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

Выделить код

Код:

//initWindow: function(window, reason, isFrame) {
        initWindow: function(window, reason, isFrame, again) {
            if(this.isBrowserWindow(window)) {
                this.initBrowserWindow(window, reason);
                return;
            }
            if(!this.isEditorWindow(window))
                return;
            if(!again && !isFrame && window.document.contentType == "text/xml") {
                window.setTimeout(function(_this) {
                    _this.initWindow(window, reason, isFrame, true);
                }, 0, this);
                return;
            }
            _log("initWindow(): isFrame: " + isFrame);


P.S. Да, DOMi тоже ведь .xul
dom_inspector-7.0.6-fx-paxmod.xpi
dom_inspector-7.0.6-fx-bootstrap.xpi

Отсутствует

 

№9307-01-2020 23:08:25

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Dumby пишет

При попытке открыть окно редактора, браузер зависает, грузит процессор,
и Windows дописывает ему в заголовок своё «(Не отвечает)».
Причём, если открыть во вкладке, то такого не происходит.

Упс.
Я попробовал поиграться, еще помогает

Выделить код

Код:

if(!again && !isFrame && window.document.contentType == "text/xml") { // Firefox 73+
                //window.setTimeout(function(_this) {
                //    _this.initWindow(window, reason, isFrame, true);
                //}, 0, this);
                Services.tm.mainThread.dispatch(function() {
                    this.initWindow(window, reason, isFrame, true);
                }.bind(this), Components.interfaces.nsIThread.DISPATCH_NORMAL);
                return;
            }

Но на глаз все равно есть задержка (хотя она и от самого CodeMirror'а).
И еще перестает зависать после замены "DOMContentLoaded" -> "load", так что я пока такую распорку воткнул.


А с меню надо бы еще посмотреть, куда и как доотламывать будут. Хотя, наверное, это еще локализации не обновились. :sick:
Меня особенно удивили постоянные перепиливания бедного Eyedropper'а без каких бы то ни было приростов в возможностях: https://github.com/Infocatcher/Custom_B … 1358-L1397 А вы, друзья, как ни садитесь...

Отредактировано Infocatcher (07-01-2020 23:09:15)


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

№9408-01-2020 19:03:39

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

Re: [CB]Attributes Inspector (для разработчиков)

Infocatcher на 72 обновил кнопки с вашей страницы:
1. Undo Close Tabs - работает нормально, но показывает ошибку для
var label = document.getAnonymousElementByAttribute(tip, "class", "tooltip-label");  - document.getAnonymousElementByAttribute is not a function
2. Check for Addons Updates (использую в составе Toggle Restartless Add-ons) - постоянно крутится и выдает ошибку inProgress is null для btn.tooltipText = inProgress.getAttribute("value");
3. Source Editor - version 0.1.0a10 - 2019-12-25 работает нормально, но показывает ошибку - InvalidAccessError: A parameter or an operation is not supported by the underlying object для  for(var j = 0, len = sheet.cssRules.length; j < len; ++j)

Отредактировано Andrey_Krropotkin (08-01-2020 19:08:53)

Отсутствует

 

№9508-01-2020 23:20:00

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

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

3. Source Editor - version 0.1.0a10 - 2019-12-25 работает нормально, но показывает ошибку - InvalidAccessError: A parameter or an operation is not supported by the underlying object для  for(var j = 0, len = sheet.cssRules.length; j < len; ++j)

Там таймаут надо поднимать.
Или вот, ещё вариант. Вроде работает (как идея).

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

Выделить код

Код:

css("resource://devtools/client/themes/variables.css");
                        css("resource://devtools/client/themes/common.css");
                        css("chrome://devtools/skin/tooltips.css");
                        if(this.platformVersion >= 68) {
                            var eKey = "styleSheetChangeEventsEnabled";
                            var notVal = !document[eKey];
                            if(notVal)
                                document[eKey] = true;
                            document.addEventListener("StyleSheetApplicableStateChanged", function change(e) {
                                var sheet = e.stylesheet;
                                if(sheet.href != "resource://devtools/client/themes/common.css")
                                    return;
                                document.removeEventListener(e.type, change);
                                if(notVal && document[eKey])
                                    document[eKey] = false;
                                for(var i = 0, len = sheet.cssRules.length; i < len; ++i)
                                    if(sheet.cssRules[i].selectorText == "::selection") {
                                        sheet.deleteRule(i);
                                        break;
                                    }
                            });
                        }

Отсутствует

 

№9609-01-2020 00:08:58

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

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

1. Undo Close Tabs - работает нормально, но показывает ошибку для
var label = document.getAnonymousElementByAttribute(tip, "class", "tooltip-label");  - document.getAnonymousElementByAttribute is not a function

Решаемая в этом месте кода проблема с тултипом,
наверно уже давно потеряла актуальность после этого:
Bug 1461798 - Migrate <tooltip> away from XBL

Может так

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

Выделить код

Код:

//if(this.appVersion >= 61) {
        if(this.appVersion <= 63 && this.appVersion >= 61) {

Отсутствует

 

№9709-01-2020 00:14:38

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Andrey_Krropotkin пишет

1. Undo Close Tabs - работает нормально, но показывает ошибку для
var label = document.getAnonymousElementByAttribute(tip, "class", "tooltip-label");  - document.getAnonymousElementByAttribute is not a function

(Долго я писал, да...)
Вроде, распорка эта больше и не требуется... отключил: https://github.com/Infocatcher/Custom_B … 63b9ee2fe2

Andrey_Krropotkin пишет

2. Check for Addons Updates (использую в составе Toggle Restartless Add-ons) - постоянно крутится и выдает ошибку inProgress is null для btn.tooltipText = inProgress.getAttribute("value");

Там все печально, в браузере браузер (вкладочный) с браузером (с содержимым). Я начал делать, но все ссылки на элементы управления в менеджере дополнений отломались:

Какой-то неработающий черновик

Выделить код

Код:

--- a/checkForAddonsUpdates.js
+++ b/checkForAddonsUpdates.js
@@ -169,8 +169,6 @@
     }
 
     progressIcon.loading();
-    var inProgress = $("updates-progress");
-    btn.tooltipText = inProgress.getAttribute("value");
 
     var origIcon = tab.image;
     tab.image = image;
@@ -180,12 +178,36 @@
     if(!updEnabled)
         Services.prefs.setBoolPref(updEnabledPref, true);
 
-    var notFound = $("updates-noneFound");
-    var updated = $("updates-installed");
+    var fu = $("cmd_findAllUpdates");
+    if(!fu) { // Firefox 72+
+        var win = doc.defaultView;
+        var vb = doc.getElementById("html-view-browser");
+        if(!vb) {
+            win.setTimeout(processAddonsTab, 20, win);
+            return;
+        }
+        var vbDoc = vb.contentDocument;
+        fu = vbDoc.querySelector('[action="check-for-updates"]');
+    }
+
+    var notFound = $("updates-noneFound"); //~fixme
+    var updated = $("updates-installed"); //~fixme
     // Avoid getting false results from the past update check (may not be required for "noneFound")
-    notFound.hidden = updated.hidden = true;
+    //~fixme notFound.hidden = updated.hidden = true;
 
-    $("cmd_findAllUpdates").doCommand();
+    //fu.doCommand();
+    fu.click();
+
+    var inProgress = $("updates-progress");
+    if(!inProgress) { // Firefox 72+
+        var um = vbDoc.getElementById("updates-message");
+        inProgress = um.shadowRoot.querySelector('[data-l10n-id="addon-updates-updating"]');
+        if(!inProgress) {
+            win.setTimeout(processAddonsTab, 5, win);
+            return;
+        }
+    }
+    btn.tooltipText = inProgress.getAttribute("value") || inProgress.textContent;
 
     var waitTimer = setInterval(function() {
         if(!doc.defaultView || doc.defaultView.closed) {


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

№9809-01-2020 13:44:59

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

Re: [CB]Attributes Inspector (для разработчиков)

Dumby пишет

Или вот, ещё вариант. Вроде работает (как идея).

работает без ошибок

Infocatcher пишет

Вроде, распорка эта больше и не требуется

работает без ошибок

Infocatcher пишет

Какой-то неработающий черновик

если сначала нажимаю на кнопку выдает ошибки
1. TypeError: el.closest(...) is null дляview-source:chrome://mozapps/content/extensions/aboutaddons.js в строке
function getTelemetryViewName(el) {
  return el.closest("[current-view]").getAttribute("current-view");
}
2. TypeError: autoUpdate is nul для var autoUpdateChecked = autoUpdate.getAttribute("checked") == "true"; и зацикливается
При перезагрузке открывается вкладка Управление дополнениями - доступные обновления

Если сначала открываю вкладку Управление дополнениями и затем нажимаю на кнопку, то находит обновления, но все равно кнопка и вкладка зацикливаются и выдают только вторую ошибку, если после этого закрываю вкладку, то выскакивает сообщение "Tab with addon-manager was closed" и тогда кнопка перестает работать

Не знаю поможет Вам или нет - вот на www.camp-firefox.de нашел работающий кусок кода

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

Выделить код

Код:

let frameScript = function() {
      addEventListener('pageshow', function onPageshow(event) {
        let document = event.target;
        if (document.URL != 'about:addons')
          return;
        removeEventListener('pageshow', onPageshow);
        content.setTimeout(function() {
          content.getHtmlBrowser().contentDocument.querySelector('[action="check-for-updates"]').click();
          let item = document.getElementById('category-availableUpdates');
          item.click();
          let categories = item.parentNode;
          categories.addEventListener('mousedown', function onMousedown(event) {
            if (event.target != item && event.target.parentNode != item) {
              item.hidden = true;
              categories.removeEventListener('mousedown', onMousedown);
            };
          });
        }, 0);
      });
    };

    let frameScriptURI = 'data:,(' + frameScript.toString() + ')()';
    let window = event.target.ownerGlobal;
    window.openTrustedLinkIn('about:addons', 'tab');
    window.gBrowser.selectedBrowser.messageManager.loadFrameScript(frameScriptURI, true);

Отредактировано Andrey_Krropotkin (09-01-2020 14:40:20)

Отсутствует

 

№9909-01-2020 14:35:52

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

Re: [CB]Attributes Inspector (для разработчиков)

Хочу добавить про Toggle on Top, раз обсуждалось.
Это для btnPos: 1 (at end of tabs).

В Firefox 72 переписали использование [align="right"],
и кнопка съехала в противоположную сторону, влево.

Причём, переписали неправильно, затем исправили,
и даже в бету пришлось вмешиваться.

Таким образом, наверно так

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

Выделить код

Код:

case 1:
                    //box.setAttribute("align", "right");
                    if(this.platformVersion >= 72)
                        box.setAttribute("pack", "end");
                    else
                        box.setAttribute("align", "right");

Отсутствует

 

№10012-01-2020 23:24:54

Infocatcher
Not found
 
Группа: Extensions
Зарегистрирован: 24-05-2007
Сообщений: 4339
UA: Firefox 56.0

Re: [CB]Attributes Inspector (для разработчиков)

Dumby пишет

Хочу добавить про Toggle on Top, раз обсуждалось.
Это для btnPos: 1 (at end of tabs).

В Firefox 72 переписали использование [align="right"],
и кнопка съехала в противоположную сторону, влево.

Спасибо! Обновил.
У меня причем ощущение, что я проверял (на какой-то бэта-версии) – и было нормально. :sick:

Dumby пишет

Причём, переписали неправильно, затем исправили,
и даже в бету пришлось вмешиваться.

Чик-чик – и в продакшн! ©

Добавлено 12-01-2020 23:35:00
А в 73.0b3 новая напасть: упорно лезет нулевая высота у свежедобавленной кнопки даже после волшебного пинка таймаута:

Выделить код

Код:

tabs.parentNode.insertBefore(box, tabs);
                    LOG("xxx " + window.getComputedStyle(btn, null).height);
                    LOG("xxx " + btn.getBoundingClientRect().height);
                    setTimeout(function() {
                        LOG("xxx " + window.getComputedStyle(btn, null).height);
                        LOG("xxx " + btn.getBoundingClientRect().height);
                    }, 5);
                    box.style.marginBottom = -(btn.boxObject || btn.getBoundingClientRect()).height + "px";

Отредактировано Infocatcher (12-01-2020 23:35:00)


Прошлое – это локомотив, который тянет за собой будущее. Бывает, что это прошлое вдобавок чужое. Ты едешь спиной вперед и видишь только то, что уже исчезло. А чтобы сойти с поезда, нужен билет. Ты держишь его в руках. Но кому ты его предъявишь?
Виктор Пелевин. Желтая стрела

Отсутствует

 

Board footer

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