Форум программистов, компьютерный форум, киберфорум
diadiavova
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

CustomButtons часть 3-я. Взаимодействие с интерфейсом Firefox.

Запись от diadiavova размещена 27.02.2016 в 13:45
Показов 3705 Комментарии 0

  1. Откуда брать информацию о структуре интерфейса
  2. Контекстное меню
Ознакомившись с работой с файловой системой, буфером обмена, реестром и тому подобными вещами, можно уже делать много чего. Однако код с chrome-привилегиями может гораздо больше. И одной из таких возможностей является возможность взаимодействия с интерфейсом самого Firefox. Мы видели, что для создания меню кнопки требуются базовые знания DOM, но и все остальные элементы интерфейса браузера работают по тому же принципу, таким образом, используя те же приемы можно легко добавлять, удалять или изменять элементы интерфейса браузера по своему усмотрению. Вот этим мы сейчас и займемся.

Откуда брать информацию о структуре интерфейса

Для того, чтобы иметь возможность воздействовать на интерфейс необходимо знать его структуру, поскольку искать элементы интерфейса программно возможно только если знаешь что-то об элементе, на который собираешься воздействовать. Так откуда же все-таки черпать знания о том, как там все устроено?

Для того, чтобы сохранить документ нам доступна простая функция saveDocument, которая принимает объект документа, показывает пользователю окно сохранения файла, и сохраняет документ. Обычно она используется для сохранения HTML-документа активной страницы, но можно передать этой функции ссылку на XUL-документ и сохранить его.
JavaScript
1
saveDocument(document);
Другой способ основан на том, что в Firefox для отображения исходного кода страницы используется специальный протокол view-source, с помощью которого можно отображать не только веб-страницу. Конечно, XUL-документ не будет красиво подсвечен, как это бывает с HTML, но отображается в отформатированном виде, так что тоже вполне читабелен.
JavaScript
1
loadURI("view-source:" + document.location.href);
Кстати этот же подход можно использовать и для просмотра других типов документов: dtd, css, properties и т. д.

Но такой подход не всегда дает нужный результат. Например, когда мы видим какой-то текст - те же надписи пунктов меню - разумно предположить, что в документе мы найдем menuitem у которого атрибут label будет иметь значение именно такое каким мы его видим в интерфейсе программы. Но в полученном вышеописанным способом документе текста на русском языке нет вообще. Лейблы просто имеют ссылку на ресурс, файл ресурса выбирается в зависимости от локализации. Но когда мы видим работающую программу, все эти надписи уже загружены и хотелось бы просмотреть XML-код именно того окна, которое мы видим. Для решения этой проблемы можно воспользоваться такой штукой, как XMLSerializer.
JavaScript
1
2
3
var serializer = new XMLSerializer();
var code = serializer.serializeToString(document);
gClipboard.write(code);
Контекстное меню

Если мы немного пройдемся по коду страницы, то можно найти там элемент popupset. Внутри этого элемента есть уже, знакомые нам по меню кнопки, элементы menupopup, наполненные элементами меню. О назначении каждого такого элемента можно судить по значению атрибута id, обычно оно достаточно информативно. Например первый элемент имеет id="tabContextMenu". Нетрудно догадаться, что это контекстное меню, появляющееся в области вкладок. Нас сейчас больше интересует меню с id="contentAreaContextMenu". Как нетрудно догадаться, это контекстное меню области содержимого. В принципе, его код можно получить вышеописанным способом, если поискать menuitem с каким-нибудь значением label, которое мы видим в этом контекстном меню
JavaScript
1
2
3
4
var serializer = new XMLSerializer();
var menuel = document.querySelector("menuitem[label='Исходный код страницы']").parentElement
var code = serializer.serializeToString(menuel);
gClipboard.write(code);
Данный код в моем случае действительно скопировал в буфер обмена код контекстного меню, но так можно и ошибиться, поскольку пункт меню с таким текстом есть и в других меню. Для того, чтобы найти именно контекстное меню, лучше всего искать его именно по id.

Сейчас мы будем добавлять новый элемент в контекстное меню области содержимого. Понадобится это может в тех случаях, когда некоторые действия надо выполнить над конкретным элементом страницы и лучшим способом указать такой элемент является как раз контекстное меню. Например: некоторые сайты, предоставляют ссылки, оставленные пользователями, в виде ссылок на свою специальную страницу, где адрес конечной ссылки передается как параметр. Таким образом сайты фильтруют ссылки, предупреждая пользователя о переходе на "ненадежный сайт". Иногда предупреждения бывают ну уж очень навязчивыми, то есть возможности перейти по этой ссылке сайт не дает. Например подобным образом ведет себя вконтактик. Ссылки там даются в таком виде
https://vk.com/away.php?to=Здесь реальный адрес в URL-кодировке&post=id поста
Причем не нравятся вконтактику зачастую совершенно безобидные, например новостные, сайты и он туда не пускает. Вот мы и создадим меню, исправляющее ссылку.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function addMenu()
{
    var menu = document.getElementById("contentAreaContextMenu");
    var item = document.createElement("menuitem");
    item.setAttribute("label", "Исправить ссылку vk");
    item.onclick = function (evt)
    {
        var ctx = menu.triggerNode;
        ctx = ctx.tagName == "A" ? ctx : ctx.parentElement
        var href = ctx.href;
        var startHref = "https://vk.com/away.php?to=";
 
        if (ctx.tagName == "A" && ctx.href.startsWith(startHref))
        {
            var startLen = startHref.length;
            var url = ctx.href.substring(startLen, ctx.href.indexOf("&"));
            ctx.href = decodeURIComponent(url);
        }
    }
    item.id = "correct_vk_outer_link";
    menu.appendChild(item);
}
 
 
function removeMenu()
{
    var menu = document.getElementById("contentAreaContextMenu");
    menu.removeChild(document.getElementById("correct_vk_outer_link"))
}
 
var myitem = document.getElementById("correct_vk_outer_link");
if (myitem)
{
    removeMenu();
}
addMenu();
Здесь сначала выполняется проверка на предмет существования элемента меню с таким id, если он есть, то сначала удаляется, после чего добавляется новый, чтобы можно было вносить изменения в код. Думаю, понятно, что таким образом можно добавлять и подменю и все что угодно.

Полагаю, большая часть кода здесь понятна без пояснений, пояснить надо только два момента
JavaScript
1
       var ctx = menu.triggerNode;
Данное свойство(triggerNode) menupopup возвращает элемент, для которого было вызвано контекстное меню. В нашем случае ожидается, что это должна быть ссылка, но некоторые внешние ссылки вконтактика содержат элементы span и в этих случаях будет возвращаться ссылка именно на этот элемент. Поэтому вставлена строка
JavaScript
1
        ctx = ctx.tagName == "A" ? ctx : ctx.parentElement
Если это не ссылка, то будет использован родительский элемент. Контекстное меню может быть вызвано для какого-нибудь другого элемента, но в этом случае он пройдет следующую проверку.

Можно обработать событие menupopup, которое называется popupshowing, выполнить все необходимые проверки там и, если элемент не подходит для нашего меню, то сделать меню недоступным или даже скрытым (атрибуты disabled и hidden соответственно). Примерно так
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*Initialization Code*/
 
function addMenu()
{
    var menu = document.getElementById("contentAreaContextMenu");
    var item = document.createElement("menuitem");
    item.setAttribute("label", "Исправить ссылку vk");
    item.onclick = function (evt)
    {
        var ctx = menu.triggerNode;
        ctx = ctx.tagName == "A" ? ctx : ctx.parentElement
        var startHref = "https://vk.com/away.php?to=";
 
        if (ctx.tagName == "A" && ctx.href.startsWith(startHref))
        {
            var startLen = startHref.length;
            var url = ctx.href.substring(startLen, ctx.href.indexOf("&"));
            ctx.href = decodeURIComponent(url);
        }
    }
    item.id = "correct_vk_outer_link";
    var onPopupShowing = function (evt)
    {
        var corItem = document.getElementById("correct_vk_outer_link");
        if (corItem)
        {
            var menu = document.getElementById("contentAreaContextMenu");
            var ctx = menu.triggerNode;
            ctx = ctx.tagName == "A" ? ctx : ctx.parentElement;
            var startHref = "https://vk.com/away.php?to=";
 
            if (ctx.tagName == "A" && ctx.href.startsWith(startHref))
            {
                corItem.setAttribute("hidden", "false");
            }
            else
            {
                corItem.setAttribute("hidden", "true");
            }
 
        }
 
    }
    menu.addEventListener("popupshowing", onPopupShowing, false);
    menu.appendChild(item);
    menu.correctVkOuterLink_OnPopupShowing = onPopupShowing;
}
 
 
function removeMenu()
{
    var menu = document.getElementById("contentAreaContextMenu");
    menu.removeChild(document.getElementById("correct_vk_outer_link"))
    menu.removeEventListener("popupshowing", menu.correctVkOuterLink_OnPopupShowing);
}
 
var myitem = document.getElementById("correct_vk_outer_link");
if (myitem)
{
    removeMenu();
}
addMenu();
Этот пример достаточно хорошо демонстрирует доступные нам возможности управления элементами интерфейса браузера.

>>
Размещено в CustomButtons
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru