Добрался таки до разработки расширений - вот тренируюсь :)
Многие вопросы решились чтением статей (особенно помогла статья про создание тулбара здесь, что-то удалось найти в существующих расширениях.
Но вот что осталось:
1. Как лучше хранить на долговременной основе структуры типа списков, таблиц и деревьев? Если использовать свойства самого Лиса, то как лучше организовывать хранение? Есть ли в этом принципиальные отличия между 2-м и 3-м Лисами? Пробовал на эту тему смотреть код SessionSaver-а, но как-то там слишком запутано написано;
2. Есть где-нибудь полное описание всего JavaScript-а Лиса в одном месте? А еще лучше, чтобы все это было в какой-нибудь среде разработки (ну или туда можно было бы это подключить)?.. А то пробовал несколько: кучу расширений и Комодо - как-то все не то :(
3. Можно ли использовать локализованные ресурсы из DTD-файлов из JavaScript-а? Или  только открывая их как файлы и парся? Или через getByID()?

Хочу поделиться своей находкой (по крайней мере в статьях про это явно не нашел; пример правильного использования случайно нашел в одном из расширений (только вот запамятовал в каком :() - если открыл Америку - сильно не пинайте):
Столкнулся с проблемой использования ресурсов из DTD-файлов в вызовах функций. То есть использование такого ресурса в качестве значения поля проблемы не вызывает, а вот вызов функции уже не получается :(
Оказалось, что кавычки (их же можно использовать только как текстовые строки) вокруг вставленного идентификатора и вокруг его значения в DTD должны быть одинаковыми (либо обе ', либо обе ")! Если они разные, почему-то выдается сообщение об отсутствии ресурса (видимо это особенность парсера).
Отсюда следует, что в DTD-файлах имеет смысл использовать именно одинарные кавычки для обрамления значений ресурсов, так как практически везде в XML (и соответственно в XUL) по-умолчанию используются двойные кавычки - имхо проще переделать ресурсы.

1) Я храню там же, где настройки. Но можно, наверное, хранить при помощи SQLite или JSON.

2) Если я правильно понял вопрос, то здесь.

3) Локализация JavaScript производится при помощи properties-файлов.

homo_nudus
Спасибо, посмотрю :)
Только вот по поводу 3-го пункта возник вопрос - где размещать инициализацию текстовых переменных из properties-файлов?
Если делать ее непосредственно в общей части js-файлов - на тот момент данные еще не подгружены.
onLoad можно делать далеко не для всех сущностей - для тех же оверлеев нельзя.
Можно конечно отслеживать это самому и вызывать при первом вызове функций, которые используют эти данные, но неужели не предусмотрено для этого стандартных средств?

Вот еще вопрос возник:
4. Можно ли как-то настроить отображение в консоли утф-8 кириллицы? А то ведь все соотв файлы со строковыми данными должны быть в утф-8. Или только перекодировать перед выводом в консоль?

3) В xul-файле создаёте элемент stringbundleset c одноимённым идентификатором, в нём - элемент stringbundle, в свойстве src которого прописываете путь к файлу .properties:

Выделить код

Код:

<stringbundleset id="stringbundleset">
		<stringbundle id="myExtensionStrings" src="chrome://myExtension/locale/myExtension.properties"/>
	</stringbundleset>

В этом же  xul-файле создаёте такие скрипты:

Выделить код

Код:

<script type="application/x-javascript" src="путь к основному скрипту"/>
	<script type="application/x-javascript">
		<![CDATA[
			window.addEventListener("load", имя_функции_с_кодом_всех_нужных_инициализаций, false);
		]]>
	</script>

В основном файле скрипта, в функции инициализации определяете строковые переменные:

Выделить код

Код:

myExtensionStrbundle = document.getElementById("myExtensionStrings");
	myExtensionLoading = myExtensionStrbundle.getString("loading");
	...

Может, есть другие способы, но этот работает.


4) К сожалению, не знаю.

homo_nudus

В этом же  xul-файле создаёте такие скрипты:

Все, кроме этого у меня было.
А вот с ним как-то все равно не работает - более того - выдает сообщение об ошибке в консоль:

Ошибка: uncaught exception: [Exception... "Could not convert JavaScript argument"  nsresult: "0x80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)"  location: "JS frame :: chrome://formfiller2/content/toolbar.xul :: <TOP_LEVEL> :: line 10"  data: no]

Вот как я это все организовал:

Выделить код

Код:

<stringbundleset id="stringbundleset">
    <stringbundle id="stringbundle" src="chrome://formfiller2/locale/formfiller2.properties"/>
  </stringbundleset>
  <script type="application/x-javascript" src="chrome://formfiller2/content/main.js"/>
  <script type="application/x-javascript">
      <![CDATA[window.addEventListener("load", "onLoad( )", false);]]>
  </script>

+

Выделить код

Код:

function onLoad() {
    strBndl=document.getElementById("stringbundle");
    unknownError=strBndl.getString("unknownError");
	dump(strBndl+"\n1\n");
	dump(unknownError+"\n1\n");
    return true;
}

Строка:

Выделить код

Код:

<![CDATA[window.addEventListener("load", "onLoad( )", false);]]>

должна быть:

Выделить код

Код:

<![CDATA[window.addEventListener("load", onLoad, false);]]>

(второй аргумент addEventListener - ссылка на функцию, а не строка.)

по-моему проще так:

Выделить код

Код:

var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService).createBundle("<путь до properties-файла>"),
bundle.GetStringFromName("foo");

AllSeeingI, точно, только в этом ошибка. Проверил, выдаёт аналогичное сообщение.

Shutnik, спасибо. Так, наверное, элегантнее.

AllSeeingI

второй аргумент addEventListener - ссылка на функцию, а не строка

Спасибо, так работает :)

Вот бы еще консоль уникодофицировать?..:whistle:

Shutnik

по-моему проще так

Действительно так проще :)

Резюмируя по пункту 3:
Уж как-то больно много надо делать телодвижений (причем шаблонных) для использования параметров :(
Или как-то это все можно сделать проще?
Опять же и шаблоны бы не помешали - например задать строку для вывода динамического диапазона уже проблема - надо создавать для этого несколько параметров, либо парсить самостоятельно.
С обработкой незаданных параметров тоже как-то непонятно - у меня не получилось ее реализовать (я хотел вместо таких параметров выдавать стандартное сообщение, прописанное в коде).

А еще появились новые вопросы:
5. Где-нибудь есть справка по всем подобным вещам с их подробным описанием?

Выделить код

Код:

Components.classes["@mozilla.org/intl/stringbundle;1"]

6. Можно ли модифицировать стандартные диалоговые окна? А то я хочу убрать у prompt кнопку Отмена. Ну или как делать самому диалоги с возвращаемыми значениями?
7. Можно ли сделать многострочный тултип?

6) См. здесь (вообще этот маленький учебник хорошо бы просмотреть полностью).

7) При помощи элемента tooltip можно создавать сложные подсказки, вкладывая в элемент другие элементы.

Forest
у nsIStringBundleService есть метод formatStringFromName. передаём имя строки, массив с параметрами, количество параметров - получаем строку, где %S заменены на передаваемые параметры. вот вам и шаблоны

homo_nudus
В принципе какая-то версия всего этого у меня есть.
Но наверняка тут есть все.
Спасибо :)

Shutnik

у nsIStringBundleService есть метод formatStringFromName

Спасибо, посмотрю :)

Вот, кстати, очень полезную страницу нашел: Interfaces:)

Forest
У меня ссылки посмотри ещё:
http://fotoleto.ru/mozilla/dev.html

Правда год-другой не обновлял.-)

Что-то не могу найти инфу по тому, как сделать боковую панель :(
Нашел только ссылки на нечто 2002 года, и то недоступное.

vladmir

http://fotoleto.ru/mozilla/dev.html

Спасибо, интересная страница, только вот ссылки на сайдбары оттуда тоже не работают :(

Про сайдбары нашел :)

Вот кстати нашел еще одну очень полезную ссылку - XUL_Tutorials:cool:

И вот еще один вопрос:
У меня в массиве хранится табличная структура.
Я хочу отобразить ее текущую выбранную запись.
Есть готовые компоненты для такого? Или надо все руками делать?

Попробовал перенести кнопки с тулбара на сайдбар (с toolbarbutton на button) и обнаружил, что вещи типа

Выделить код

Код:

document.commandDispatcher.focusedWindow

и

Выделить код

Код:

document.commandDispatcher.focusedElement

перестали выдавать данные по текущему открытому сайты - стали ссылаться на окно сайдбара.
Прочитал, что это связано с тем, что панели инструментов не включаются в так называемый фокус ринг (то есть фокус на них не фиксируется).
Я правильно понимаю, что кнопку, которая должна получать фокус текущего выбранного элемента на сайте, можно сделать только из toolbarbutton? Или можно и обычную кнопку доработать?
Или может быть вообще можно получить историю изменения фокуса?

Еще возник вопрос, как сделать действительно глобальную переменную (и можно ли вообще ее сделать)?
А то в 2-х .xul файлах подключил один и тот же .js файл, однако после определения переменных в одном файле, в другом они не определились :(
Ну или мб дело в последовательности их обработки? Тогда как задать правильный порядок?

как сделать действительно глобальную переменную

Это здесь: http://developer.mozilla.org/en/docs/Working_with_windows_in_chrome_code#Advanced_data_sharing

Anton
Спасибо, познавательно :)
Учитывая, что под 2-ку - вариантов прямо скажем мало...

Почему в таком случае при вызове CKGFF2_CbImport() недоступен результат вызова onLoad?
Вроде все в одном файле?..

Выделить код

Код:

<overlay id="CKGFF2-Overlay"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <script type="application/x-javascript" src="chrome://formfiller2/content/main.js"/>
  <script type="application/x-javascript">
      <![CDATA[window.addEventListener("load", onLoad, false);]]>
  </script>
  
  <broadcasterset id="mainBroadcasterSet"> 
    <broadcaster id="CKGFF2-viewSidebar" 
                 label="&FormFiller2.sidebarTitle;"
                 autoCheck="false"
                 type="checkbox"
                 group="sidebar"
                 sidebartitle="&FormFiller2.sidebarTitle;"
                 oncommand="toggleSidebar('CKGFF2-viewSidebar');" >
        <button id="CKGFF2-Import" tooltiptext="&FormFiller2.tbImportTT;"
    label="&FormFiller2.tbImport;" default="true" 
    oncommand="CKGFF2_CbImport()" />
      </broadcaster>
  </broadcasterset>
  
 </overlay>

Вопрос по локализации:
Можно ли сделать дефолтную локаль такую, чтобы параметры, которые есть в ней, брались только оттуда?
А чтобы еще в отдельных локалях их можно было переписывать, но не во всех?

Можно ли сделать дефолтную локаль такую, чтобы параметры, которые есть в ней, брались только оттуда?

можно конечно. сунь её в content и подключай оттуда же, а не из каталога с локалями

на счёт перезаписать не уверен, скорее всего должно ругаться на уже объявленную сущность, но можно попробовать

Shutnik

можно конечно. сунь её в content и подключай оттуда же, а не из каталога с локалями

Имеется в виду, чтобы все такие сущности выносить в отдельный файл, который хранить вне local?
То есть стандартными средствами такое не предусмотрено?

Имеется в виду, чтобы все такие сущности выносить в отдельный файл, который хранить вне local?
То есть стандартными средствами такое не предусмотрено?

ну из всех locale из chrome.manifest всегда подключается только одна. если надо что-то общее для всех - выноси вне locale

Shutnik
Спасибо :)

А можно в своих расширениях использовать стандартные иконки?
И как?

Еще очень интересно, можно ли наследовать стандартные CSS стили?
Например я хочу сделать класс для toolbarbutton на основе класса для button.
Можно так сделать?

Forest
можно стандартные. тут думаю проблемы не должно быть, через dom inspector можно посмотреть css styel rules и cumputed style для любого элемента

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

Shutnik

Например я хочу сделать класс для toolbarbutton на основе класса для button.

Такое оказалось сделать просто:

Выделить код

Код:

-moz-appearance: button;

в описании стиля :cool:

Вот еще тройка вопросов:
1. Приводить типы можно?
А то из textbox-а значение беру в переменную, делаю +1, а получаю +1 как к строке.
Number(строка) не помогает.
Только шаманство типа недопустимой для строки операции (например -1+2).

2. Пробую создавать список (listitem-ы в listbox-е) по массиву, но почему-то при удалении с последующим созданием обнаруживаются пустые элементы. Это точно происходит при удалении.
Вот код:

Выделить код

Код:

// ссылка на listbox
    currentField = document.getElementById("CKGFF2-Current");
// удаление существующего списка (именно здесь что-то и не так)
        for (var i=0; i<currentField.getElementsByTagName("listitem").length; i++) currentField.removeItemAt(i);
// создание нового списка
        for (var i=0; i<curDepth; i++) currentField.appendItem('');

Вообще как-то подозрительно я их удаляю, но по другому не получается.
И что я вообще такое удаляю, что оно все равно работает?..

3. Как в groupbox-е отцентрировать заголовок?
Вот пример:

Выделить код

Код:

// .xul
  <groupbox orient="horizontal">
    <caption>
      <label class="label" value="&FormFiller2.lLink;" />
    </caption>

// .css
.label {
	text-align: center;	
}
Выделить код

Код:

align="center"

тоже не помогает :(

Добавлено Thu Jul 17 22:42:09 2008 :
На счет 2. - правильнее наверное было бы удаление сделать как-то так:

Выделить код

Код:

var list = currentField.getElementsByTagName("listitem");
        for (var i=0; i<list .length; i++) list .removeItemAt(i);

Но у list почему-то не оказывается метода removeItemAt.
Вообще в такой ситуации логично было бы вызвать removeAll, но для такого я его не нашел :(
Или плохо искал?

Forest
1. используй new Number или parseInt
2. не стоит с начала начинать, с конца удаляй, иначе у тебя количество элементов с каждой итерацией уменьшается :) либо используй while
3. ты уверен, что у тебя caption на всю ширину растянут? наверное нужно ещё flex добавить

Shutnik
1. Действительно, почему-то не смог найти сам :(
2. Так и сделал

Выделить код

Код:

while(currentField.getElementsByTagName("listitem").length>0) currentField.removeItemAt(0);

3. Растяжка помогла :) Да и label выносить оказалось лишним.
Так работает

Выделить код

Код:

<caption flex="1" class="label" label="&FormFiller2.lLink;" />

Спасибо :)

Forest

2. Так и сделал

.getElementsByTagName – довольно тормозная штука и не стоит лишний раз к ней обращаться.
Скажем,

Выделить код

Код:

while(parentElt.hasChildNodes())
	parentElt.removeChild(parentElt.lastChild);

Или один раз сохранить в переменную .getElementsByTagName("listitem").length и удалять с конца (length - 1, length - 2, ... , 0)

А в HTML можно просто сделать

Выделить код

Код:

parentElt.innerHTML = ""

Вообще в такой ситуации логично было бы вызвать removeAll, но для такого я его не нашел sad

Можно попробовать сделать

var copy = parentElt.cloneNode(false); // копируем без дочерних элементов
parentElt.parentNode.replaceChild(copy, parentElt);

Но, как я понимаю (лень проверять), отвалятся все обработчики (addEventListener), «повешенные» на parentElt.
Например, запускаем из адресной строки:

Выделить код

Код:

javascript: var parentElt = document.documentElement.lastChild; var copy = parentElt.cloneNode(false); var copy = parentElt.cloneNode(false); alert("Childs count:\n" + parentElt.childNodes.length); parentElt.parentNode.replaceChild(copy, parentElt); void(0);
Infocatcher пишет

А в HTML можно просто сделать

Выделить код

Код:

parentElt.innerHTML = ""

ну а в XUL:

Выделить код

Код:

parentElt.textContent = ""

хотя я предпочитаю нормально удалять

Infocatcher

.getElementsByTagName – довольно тормозная штука и не стоит лишний раз к ней обращаться.
Скажем,
Код:

while(parentElt.hasChildNodes())
    parentElt.removeChild(parentElt.lastChild);

Уже нашел этот вариант в домовском хелпе - предыдущие действительно какой-то кривой был и не для всех вариантов работал:)

Можно попробовать сделать

    var copy = parentElt.cloneNode(false); // копируем без дочерних элементов
    parentElt.parentNode.replaceChild(copy, parentElt);

Да наверное проще написать свою удалялку (язык позволяет).
А такими финтами как-то не хочется заниматься - сборщик мусора - он конечно есть, но такого течения памяти имхо лучше избегать...

Я тут попробовал перейти от списка к дереву и столкнулся с некоторыми проблемами:
1. Почему-то для дерева не сработало присваивание treecell-у через label, хотя для listbox-а работало. Сделал через setAttribute("label", data) - заработало.
2. Однако с тултипом такой фокус не прошел - так и не получилось мне назначить его для treecell (для treecol назначается нормально). Ни setAttribute, ни пронисывание в xul-е, ни использование тега - ничего не помогает. Хотя в официальном источнике они (tooltip, tooltiptext) описаны как "Inherited from XUL element"...

Подскажите, в чем дело:)

Я правильно понимаю, что в 2-ке проблемы с определением выделения внутри дерева?
Сколько всего просмотрел - ничего не работает :(
Конечно работает currentIndex, но он выдает не абсолютный номер, а относительный.
То есть развернул ветку - номер выделенного после этой ветки изменился.
Может можно получить хотя бы абсолютный индекс, либо value?
Дерево двухуровневое.
Или подскажите расширение, которое работает в 2-ке с выделением в дереве.

Еще пара вопросов:
1. Заполняю menulist программно, программно же делаю выделение и сразу после этого хочу использовать значение выделенного элемента. Однако выдается undefind :( Как победить?
Выделяю через selectedIndex.
Если хоть раз руками выбрать - все работает.
2. Делаю getBranch(Path).getChildList("",{}), но получаю не только прямых потомков, но вообще всех. Как можно ограничиться только одним уровнем потомков?

По поводу первого вопроса предыдущего поста - инспектор DOM показал, что сразу после заполнения из кода до этого пустого списка все его элементы - листья.
А вот если после этого хоть раз выбрать руками элемент - в них появляются дочерние элементы: xul:hbox и xul:label.
Может их можно программно инициализировать?
Или я неправильно заполняю?

Ну вот, а .getAttribute("value") работает:dumb:
Кто бы еще объяснил (или ссылку дал, где почитать) разницу между .getAttribute("value") и просто .value ?..

Я правильно понимаю, что нельзя сохранить не все пользовательские настройки, а только часть через savePrefFile?
Например только определенную ветвь?
По крайней мере у меня getBranch("...").savePrefFile(...) говорит, что нет такого :(
Или только потом открывать как файл и удалять лишнее?

Если отредактировать сохраненный файл, то readUserPrefs отрабатывает нормально.

Я правильно понимаю, что нельзя сохранить не все пользовательские настройки, а только часть через savePrefFile?

savePrefFile(null) сохраняет все

По крайней мере у меня getBranch("...").savePrefFile(...) говорит, что нет такого sad

savePrefFile это метод nsIPrefService, а не nsIPrefBranch

Shutnik

savePrefFile(null) сохраняет все

Ясно, значит доработаем напильником :)

savePrefFile это метод nsIPrefService, а не nsIPrefBranch

Недоработка однако...


Еще раз наткнулся на проблему при работе с атрибутами через свойства - не отображалось ни в интерфейсе, ни в ДОМе, однако при попытке вывести объект в консоль - все выводилось правильно.
Переделал через .getAttribute("name", "value") - все заработало.
Мб это баг такой? Никто не в курсе? В 3-ке это тоже есть.
Надо будет в БагЗилле поискать...

Еще на один косяк натолкнулся - getElementsByTagName().length после удаления всех элементов все равно выдал то же кол-во, что и до удаления, однако при попытке доступа к элементам их отсутствие очевидно. Правда в 3-ке это не проверял...

Кто бы еще объяснил (или ссылку дал, где почитать) разницу между .getAttribute("value") и просто .value ?..

http://xpoint.ru/know-how/JavaScript/Atributyi

Infocatcher

http://xpoint.ru/know-how/JavaScript/Atributyi

Спасибо, очень познавательно :)

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

Forest

Но когда в цикле устанавливаешь 15 однотипных значений, но устанавливаются они не все - это как минимум странно - притомился Лис что ли?..

Лично не встречал – пример бы.
А про tree можно посмотреть тут: http://xpoint.ru/know-how/Articles/Dina … %27yaNaXUL

Infocatcher

Лично не встречал – пример бы.

Целиком расширение пока выложить не могу, но вот 2 выдержки из кода:
1. Заполняем menulist (его id = CKGFF2-Mappings) из mList, где хранятся пары label+value, а потом делаем текущим первый элемент:

Выделить код

Код:

currentMappings = document.getElementById("CKGFF2-Mappings");
        for (var i = 0; i < mList.length; i++)
              currentMappings.appendItem(mList[i][0], mList[i][1]);
        currentMappings.selectedIndex = 0;

Если после этого не трогая мышью этот menulist попробовать получить value выделенного элемента через свойство - получим undefind, а вот если через атрибут - работает.

Выделить код

Код:

// не работает
currentMappings.selectedItem.value;
// работает
currentMappings.selectedItem.getAttribute("value");

2. Заполняем listbox (его id = CKGFF2-Current). curDepth - положительное целое, posPhoneCount - неотрицательное целое. data - массив строк:

Выделить код

Код:

currentField = document.getElementById("CKGFF2-Current");
// сначала удаляем старые элементы
        currentFields = currentField.getElementsByTagName("listitem");
        var nListitem = currentFields.length;
        for (var i = nListitem-1; i>=0; i--) 
            currentField.removeChild(currentFields[i]);
// потом добавляем новые
        for (var i=0; i<(curDepth+2+4*posPhoneCount); i++) currentField.appendItem('');
// потом заполняем их
    var cf = 0;
    for (var i=0; i<curDepth; i++) {
        if ((posName3-1)==i) {
            currentFields[cf++].setAttribute("label", "/ "+data[recordNumber][i]);            
            var delim = data[recordNumber][i].indexOf(" ");
            currentFields[cf++].setAttribute("label", " - "+data[recordNumber][i].substring(0,delim));
            currentFields[cf++].setAttribute("label", " - "+data[recordNumber][i].substring(delim+1));
        } else if ((pp=posPhone.indexOf(i+1))>=0) {
            currentFields[cf++].setAttribute("label", "/ "+data[recordNumber][i]);            
            currentFields[cf++].setAttribute("label", " -  "+data[recordNumber][i].substring(0,3));
            var phoneNumber = data[recordNumber][i].substring(3).split(/[ -]/).join();
            currentFields[cf++].setAttribute("label", " -/ "+phoneNumber);
            currentFields[cf++].setAttribute("label", "   - "+phoneNumber.substring(0,3));
            currentFields[cf++].setAttribute("label", "   - "+phoneNumber.substring(3));
        } else {
            currentFields[cf++].setAttribute("label", "  "+data[recordNumber][i]);            
        }
    }

В таком варианте все работает.
А вот если все

Выделить код

Код:

.setAttribute("label", value)

заменить на просто

Выделить код

Код:

.label=value

может работать польностью, а может и не полностью (то есть до определенного индекса заполнится нормально, а после - нет). Исследований, зависит ли это именно от индекса, я не проводил.
При этом даже ДОМ-инспектор показывает, что там все пусто.
Однако если сделать что-то вроде

Выделить код

Код:

currentFields = currentField.getElementsByTagName("listitem");
        var nListitem = currentFields.length;
        for (var i = nListitem-1; i>=0; i--) 
            dump("listitem["+i+"] = "+currentFields[i].label);

- выводится все, как и должно быть:dumb:

Такие вот пироги...

Ну хотя бы замечания по коду выскажите (если есть конечно) ;)

Если у устанавливаю value у поля со списком - могу я проконтролировать, что значение подошло?
value то в любом случае меняется, а вот попал ли я в список значений?..
Или это только если достать этот список и по нему проверять каждое значение?

Если у устанавливаю value у поля со списком - могу я проконтролировать, что значение подошло?

Если

Выделить код

Код:

<menulist id="ml01" editable="true">
    <menupopup>
        <menuitem label="1" value="xyzt"/>
        <menuitem label="2" value="abcd"/>
    </menupopup>
</menulist>

то должно помочь

Выделить код

Код:

if (document. getElementById ("ml01"). getElementsByAttribute ("value", "xyz"). length) ...

Anton

то должно помочь...

Спасибо :)
Но это тоже из разряда

Или это только если достать этот список и по нему проверять каждое значение?

.
Хотя наверное этого должно быть достаточно?..

Но это тоже из разряда

это не "из того же разряда"

Anton

это не "из того же разряда"

Это почему это?
Твой пример проверяет, есть ли в списке вариантов поля со списком значение, которое мы хотим присвоить полю.
То, про что я писал - фактически оптимизация по времени того же самого действа в случае частых проверок (хотя конечно не могу гарантировать, что это будет быстрее - не проверял).
В обоих случаях результат получится одинаковый: либо оно там есть, либо нет.
Но вообще говоря положительный ответ не гарантирует успешности присваивания, так как в принципе между проверкой и присваиванием список может измениться.
Но наверное если такое и возможно, то пренебрежимо маловероятно...

То, про что я писал - фактически оптимизация по времени того же самого действа в случае частых проверок

Неужели ?

Вообще, непонятно, зачем оптимизировать по времени доступ к menulist, но вариант с getElementsByAttribute не единственный, можешь попробовать хэш типа "значение":"индекс" или ещё что-нибудь, а насколько каждый вариант будет быстрым покажет только эксперимент.

Но вообще говоря положительный ответ не гарантирует успешности присваивания, так как в принципе между проверкой и присваиванием список может измениться.

Я уже думаю, и не только список. Даже уверен. Не пойму только, в чём проблема. Поставь проблему понятней.

Anton

Поставь проблему понятней.

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

Forest  пишет

Если у устанавливаю value у поля со списком - могу я проконтролировать, что значение подошло?

Хотя наверное не очень понятно.
То есть речь о следующем:
Я установил значение поля со списком.
В процессе этого/сразу после этого или через какое-то время - могу я понять, что у меня там сейчас правильное значение не проверяя, принадлежит ли мое значение тому, что написано в value списка вариантов?
Мб исключение какое бросается?..
Или обработчик события туда можно повесить?..
Или единственный способ - варианты того как ты написал ?

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

Ну и где там про оптимизацию по времени ?

Факт изменения value можешь проверять обработчиками onchange, oninput, onselect.
Проверка правильности "автоматом", afaik, не делается, кроме случая отсутствия атрибута editable.

Про оптимизацию было сказано в сравнительном качестве.
В общем вопрос исчерпан, спасибо :)

Anton

то должно помочь
Код:
if (document. getElementById ("ml01"). getElementsByAttribute ("value", "xyz"). length) ...

Я правильно понимаю, что getElementsByAttribute работает только для XUL?
Мне просто надо все это делать для элементов html-страницы.

Я правильно понимаю, что getElementsByAttribute работает только для XUL?

Нет, не правильно.

p.s. для html, насколько мне известно - собственная реализация (в т. ч. и getElementsByAttribute) через xpath, перебор или строчный поиск в innerHTML.

Anton

Нет, не правильно.

p.s. для html, насколько мне известно - собственная реализация (в т. ч. и getElementsByAttribute) через xpath, перебор или строчный поиск в innerHTML.

Тогда почему у меня Лис (2-я версия) на вызов getElementsByAttribute говорит, что он не является методом?
То есть getElementById (точнее у меня getElementByName, но это по идее должно быть без разницы) выполняется, а вот на getElementsByAttribute такое говорится :(

Добавлено Sun Aug  3 11:47:58 2008 :
Опять же в DOM:element тоже отсутствует описание этого метода :(
Правда там написано

While these interfaces are generally shared by most HTML and XML elements, there are more specialized interfaces for particular objects listed in the DOM HTML Specification—for example the HTML Table Element and HTML Form Element interfaces.

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

Forest

Тогда почему у меня Лис (2-я версия) на вызов getElementsByAttribute говорит, что он не является методом?

Так ты же его, скорее всего, не определил. Напрямую он определён только в XUL. Если добавить код, типа

ml. getElementsByAttribute = function (attrName, attrValue) { ... }

то getElementsByAttribute будет работать и в xml и в html.
Я именно так и сказал.

Anton

Выделить код

Код:

ml. getElementsByAttribute = function (attrName, attrValue) { ... }

Прямо так в коде и написать (включая ... в теле)?
А ml - это что? Или вместо него просто надо поставить переменную с объяктом от которого он будет вызываться?

Прямо так в коде и написать (включая ... в теле)?
А ml - это что? Или вместо него просто надо поставить переменную с объяктом от которого он будет вызываться?

А сам-то как думаешь ? )

Anton

А сам-то как думаешь ? )

То есть ты предлагаешь мне самому реализовать getElementsByAttribute?

Добавлено Sun Aug  3 13:26:36 2008 :
Если можно как-то шаблонным образом переносить реализацию с XUL на HTML - дай пожалуйста ссылку на описание как это делается.

Если можно как-то шаблонным образом переносить реализацию с XUL на HTML - дай пожалуйста ссылку на описание как это делается.

Насколько мне известно - нельзя.

Anton
Ну просто огромное спасибо за неоценимую помощь в лице двух примеров неработающего кода :(
Тогда тем более полемика на тему

Anton  пишет

это не "из того же разряда"

была совершенно пустой, так как я именно про реализацию этой фичи фактически и писал!
Только время потерял - давно бы уж сделал, если бы не мысль, что "возможно я плохо искал" :(

Forest

Ну просто огромное спасибо за неоценимую помощь

Всегда пожалуйста. Надеюсь, мне удалось положительно повлиять на твой способ постановки вопросов...

в лице двух примеров неработающего кода

... хотя и не в полной мере. Что ж, на то они и примеры.

Anton

Надеюсь, мне удалось положительно повлиять на твой способ постановки вопросов...

И не надейся!
Если не нравился вопрос - надо было так сразу и писать чем (кстати еще не поздно)!
А сейчас это больше похоже на оправдание.

Forest

И не надейся!

Жаль.

Если не нравился вопрос - надо было так сразу и писать чем (кстати еще не поздно)!

Хорошо. Вопрос был такой:

Если у устанавливаю value у поля со списком - могу я проконтролировать, что значение подошло?
value то в любом случае меняется, а вот попал ли я в список значений?..
Или это только если достать этот список и по нему проверять каждое значение?

и я ответил: "...Если <menulist...".
Как скоро после этой пары вопрос-ответ выяснилось, что код требуется для html ? Вот это мне очень не понравилось. Перед этим точно так же вопрос об оптимизации был поставлен постфактум, когда я просил о более точной формулировке. Во второй уже раз решил - раз вопросы задаются неопределённо, ну я и отвечать буду в той же манере.

Anton

Жаль.

Я умею учиться и критически отношусь к себе, но в данном случае считаю претензию необоснованной.

и я ответил: "...Если <menulist...".
Как скоро после этой пары вопрос-ответ выяснилось, что код требуется для html ?

1. Да, я забыл указать про html! Хотя у меня есть подозрение, что произошло нечто другое - я "забыл" про html потому, что знал про то, как это делается для XUL, и неосознанно счел это очевидным.
2. Я не сразу проверил все мне предложенное. Я вообще стараюсь избегать ситуаций, когда срочно нужен ответ. Я задал вопрос и стал делать другую часть, в которой знал как все делать.
Поэтому и свою оплошность я понял не сразу.
Однако прошу отметить, что:
а. Я поблагодарил за помощь
б. Я никому не предъявлял претензия за свою забывчивость
в. Я просто задал уточняющий вопрос
В контексте всего этого изменение линии поведения я принял как обиду на то, что помощь оказалась невостребованной (типа я тут стараюсь-пишу-помогаю, а всякие чайники не могут сразу вопрос поставить - вот не буду больше писать!).
Как мне в таких случаях в детстве говорила тетушка "На обиженных воду возят", за что ей огромное спасибо.

А теперь о том, чего не было:

Перед этим точно так же вопрос об оптимизации был поставлен постфактум

- вопрос об оптимизации не ставился!
Если в этом есть сомнения - рекомендую перечитать заново.
Хотя в первую очередь мы видим (в том числе и в тексте) то, что хотим увидеть.

для html встроенного getElementsByAttribute нет.
пробуем в chrome и в обычном документе

Выделить код

Код:

alert("getElementsByAttribute" in window.document)

если уже действительно нужно, то можно сделать самому.

Shutnik

alert("getElementsByAttribute" in window.document)

Как и ожидалось, false :(
В моем случае полная реализация такого метода не нужна - сделал простым перебором "option".
Но как делать в принципе понятно (рекурсией по всему древу ДОМа).
Спасибо за интересный способ определения наличия/отсутствия фич:)

Возникла задача - реализовать копирование (ctrl+c например) для контролов xul-а (конкретно это был листбокс).
Поискал инфу на эту тему, но нашел только про меню, да и то там как-то обойден стороной вопрос про реализацию самих обработчиков.
Попробовал сделать по-аналогии - не получилось.
Вот что пробовал:

Выделить код

Код:

...
  <keyset id="sidebarKeyset">
    <key id="copy_key" oncommand="CKGFF2_GetSelected(event);"
        modifiers="accel" key="C" />
  </keyset>
...
    <listbox id="CKGFF2-Current" flex="1" key="copy_key" />
...

Не смог получить в обработчике CKGFF2_GetSelected(event) контекст listbox-а - везде только keyset.
Другой вариант вообще не заработал (нажатия не ловил).

В принципе установкой обработчика в сам listbox проблема решается, но тогда приходится отслеживать то ли нажато.
А хотелось именно привязать обработчики к хоткеям и использовать при необходимости.
Или мое желание не соответствует идеологии разработки и работающий вариант - единственно верный, а keyset - только для меню?

Пробуй event.explicitOriginalTarget

Anton

Пробуй event.explicitOriginalTarget

Спасибо, помогло :)

Только вот я почитал доку на developer.mozilla.org и как-то не уверен, что это допустимый вариант использования (правда там вообще дока неполная).
И как оно вообще работает, когда таких хоткеев определяется много (десятки например)? Или справляется?

или document. commandDispatcher. focusedElement

Anton

или document. commandDispatcher. focusedElement

Да, это тоже должно подойти, спасибо :)

Добавлено Mon Sep  1 16:04:21 2008 :
Я правильно понимаю, что в АПИ Лиса нет работы с консолью?
Просто понадобилось  получить stdout консольного приложения, а ничего подходящего не нашел :(
Пришлось делать через перенаправление в файл.
Вот что получилось (нужна была только первая строка):

Выделить код

Код:

// временный файл создаем в папке tmp
    var tmpFile = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("TmpD", Components.interfaces.nsIFile);
    var tmpPath = tmpFile.path;
    tmpFile.append("TmpFile");
    var tmpFullPath = tmpFile.path;

// Запускаем наш скрипт с перенаправлением вывода во временный файл
    var runFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
    runFile.initWithPath("c:\\script.bat");
    var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
    process.init(runFile);
    var args = [">", tmpFullPath];
    process.run(false, args, args.length);

// Получаем данные из временного файла
    var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
    istream.init(tmpFile, 0x01, 0444, 0);
    istream.QueryInterface(Components.interfaces.nsILineInputStream);
    
    var line = {}, hasmore;
    hasmore = istream.readLine(line);

Оно работает, но как-то кривовато выглядит :(
Опять же не получилось удалить этот временный файл:

Выделить код

Код:

tmpFile.remove(false)

не работает, а попытка работать с файлом через nsIFile (а не через nsILocalFile) успехом пока не увенчалась.

Вообще или я еще не до конца разобрался с этим, либо все таки АПИ работы с файловой системой у Лиса хромает?..

От ссылочки на правильную документацию про это/пример не отказался бы (особенно с удалением).
Инфу копал в основном на оффсайте, но мб недостаточно глубоко?..

Или нормально это все можно только через XPCOM сделать?

Что-то похоже либо я чего-то не понимаю, либо с многоплатформенностью у Лиса есть проблемы :(
По крайней мере приведенный мною пример в Линуксе работает иначе - перенаправления в файл не происходит, а вместо этого результат печатается прямо в консоли (файл при этом не создается) :(
С этим вообще что-то можно сделать?
И баг ли это?

Еще кстати указанный код почему-то не работает с ехе-файлами?..

Продолжая тему горячих клавиш и их обработчиков:
Как-то странно тут все сделано: есть обработчики команд command, есть возможность их использования с контролах через одноименный атрибут, однако почему-то с хоткеями они так не работают - нету у key атрибута command! :(
Мб конечно они как-то вместе и работают, но у меня складывается впечатление, что не работают они вместе :(
Я понимаю, что все можно делать через onCommand, но тогда как минимум перестает работать фича, что если задизейблить описание command - через все контролы она тоже станет недоступна, но почему-то через хоткей эта функциональность останется доступной (ну или надо и его тоже дизейблить).
Да и некрасиво как-то (и не логично):dumb:

Вот пример:

Выделить код

Код:

<command id="SF_Fill_CMD" oncommand="SF_Fill();" />
    <key id="SF_Fill_Key" keycode="VK_F4" oncommand="SF_Fill();" />
    <toolbarbutton id="SF-Fill" tooltiptext="&ScriptFilling.bFillTT;"
            label="&ScriptFilling.bFill;" command="SF_Fill_CMD" />

Кстати, этот пример под 2-й версией не работает вообще: command ладно, а вот то, что key не работает - уже неприятно...
Причём как-то я не заметил, чтобы какие-то из этих элементов были помечены на оффсайте как относящиеся только к 3-ке :(

И вообще никто не в курсе, этот бардак на девелоперском оффсайте устранять вообще будут (или в чем его смысл хотя бы)?
А то например и здесь, и и здесь (разница в урлах на docs/) - практически одно и то же?..

нету у key атрибута command!

проверял на XUL Runner'е, вроде есть:

Выделить код

Код:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

    <!-- your code here -->
<commandset id="cs01">
<command id="c01" oncommand="alert('xyz')"/>
</commandset>

<keyset id="ks01">
<key id="k01" key="a" command="c01"/>
</keyset>

<button id="b01" label="do command" command="c01" key="k01"/>
<button id="b02" label="disable command" oncommand="document.getElementById('c01').setAttribute('disabled','true');"/>
<button id="b03" label="enable command" oncommand="document.getElementById('c01').removeAttribute('disabled');"/>

</window>

Forest
http://developer.mozilla.org/En/XUL/Key#Attributes

Shutnik

http://developer.mozilla.org/En/XUL/Key#Attributes

Там действительно есть :)
Наверное я как-то неправильно ищу :(

Anton

Выделить код

Код:

<button id="b01" label="do command" command="c01" key="k01"/>

Так действительно в 3-ке работает, спасибо :)

Но все равно смущает тот факт, что недостаточно добавить key, а надо еще и command :(
То есть получается, что key добавляется только чтобы в элементе стал отображаться соотв хоткей.
Но при этом запросто можно указать разные command разным элементам при одинаковом значении key (а это потенциальный источник ошибок).

Теперь буду разбираться, как же прикрутить хоткей на Фх в 2-ке?..

недостаточно добавить key, а надо еще и command

key вполне достаточно. command там по другой причине.
Соврал ) Атрибут key в <button ... - лишний.

Anton
Спасибо за пример, он действительно везде работает :)

Только вот видимо у меня случай особый - кнопки на тулбаре.
И вот там не получается заставить работать :(
Сделал даже тестовое расширение, где нет ничего кроме тулбара и кнопок с различными вариантами - так работают только где явно oncommand прописан + хоткеи не работают вообще :(
Вот выложил.
Что я не так сделал?

26-09-2008 12:31:02
Ещё написал диалог (для изменения настроек расширения) - так не получается отменить нажатие на Ок в обработчике этой кнопки :(
То есть если я явно после вызова обработчика в xul-е допишу "return false;" - окно не закрывается!
А вот если у меня с обработчике произошло исключение и я в его обработчике сделал "return false;" - обработчик прерывается, но окно все равно закрывается :(
Пробовал даже переменную булеву заводить и выходить из обработчика всегда в одном месте по "return _переменная_;" - не помогает.
Куда копать?

Forest
в xul-файле нужно писать return foo(), в foo возвращать false, когда диалог закрываться не должен

Forest пишет

Что я не так сделал?

Пропустил самое главное : )
"Заверни" keyset и commandset в <window id="main-window"

И ещё, атрибуты key в <toolbarbutton - лишние.

Anton

Пропустил самое главное : )
"Заверни" keyset и commandset в <window id="main-window"
И ещё, атрибуты key в <toolbarbutton - лишние.

Вот и я тоже думаю, что что-то важное упускаю :(
Вечером дома попробую, спасибо :)

Anton

Пропустил самое главное : )
"Заверни" keyset и commandset в <window id="main-window"

И ещё, атрибуты key в <toolbarbutton - лишние.

Все проверил - работает - спасибо :)
Удивительно, почему в документации об этом ни слова + нет ни в одном примере?..

Shutnik

в xul-файле нужно писать return foo(), в foo возвращать false, когда диалог закрываться не должен

return действительно нужен, но у меня проблема оказалась в другом - промежуточный вызов-обертка, в котором я забыл сделать return :(
Спасибо за участие :)

На будущее - интересно, можно ли как-то смотреть возвращаемые такими обработчиками значения?..

Удивительно, почему в документации об этом ни слова + нет ни в одном примере?..

Есть об этом и в документации и в примерах.

Anton

Есть об этом и в документации и в примерах

Нисколько не сомневаюсь, что где-то оно есть.
Только вот признак качества документации - насколько быстро можно найти то, о существовании чего даже не догадываешься (ну разве что самую малость) ;)
Рассмотрим оффсайт:
В описании тубларов вообще ничего нет про command и key - исключительно oncommand. Пример.
В описании command и key (а так же в их туториалах: command и key) нет ни слова про

Выделить код

Код:

<window id="main-window"

(ссылок тоже нет).
Даже поиск по "main-window" не дает ничего относящегося к вопросу (по крайней мере на первой странице).

Так что у меня в очередной раз складывается впечатление, что кто-то из нас двоих неправильный (я или эта документация).

Есть об этом и в документации и в примерах

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

Forest пишет

В описании command и key (а так же в их туториалах: command и key) нет ни слова про

Выделить код

Код:

<window id="main-window"

(ссылок тоже нет).

XUL->XUL Reference->overlay

Each element within the overlay is inserted at a location in the master window, determined by matching id  attributes. For instance, if an element in an overlay has an id  of file_menu, the corresponding element with the id  file_menu in the master window that uses the overlay would be altered. Attributes declared in the overlay are added to that element and child elements are inserted into the window within that element. Elements directly inside the overlay element as children that do not have id  attributes are appended to the master window. This allows the addition of scripts to the master window from the overlay.

"Каждый элемент оверлея вставляется в позицию главного окна, определяемую соответствующими атрибутами id. Например, если элемент оверлея имеет атрибут id со значением "file_menu", соответствующий элемент (имеющий атрибут id со значением "file_menu") главного окна, использующего оверлей, будет изменён. Атрибуты и дочерние элементы элемента из оверлея будут добавлены в этот элемент главного окна. Дочерние элементы элемента overlay, не имеющие атрибутов id будут добавлены в главное окно. Это позволяет добавлять скрипты в главное окно из оверлея."
То есть, commandset и keyset особенными не являются: если они должны находиться в элементе window, значит и в оверлее они должны находиться в элементе window. Либо не иметь идентификаторов, но без идентификаторов они не работают - не работают их дочерние command или key.

Anton
Спасибо за исчерпывающий ответ :)

Но все таки примеров у них явно не хватает.
Например

То есть, commandset и keyset особенными не являются: если они должны находиться в элементе window, значит и в оверлее они должны находиться в элементе window. Либо не иметь идентификаторов, но без идентификаторов они не работают - не работают их дочерние command или key.

- это уже не перевод их текста, а собственные знания ;)


Вот ещё с какой проблемой столкнулся: у моей кнопки на тулбаре название сбоку, а не снизу + в Настройке панелей инструментов у неё нет картинки.
Вот кусок из .css:

Выделить код

Код:

#SF-Fill
{
  list-style-image: url("chrome://acfilling/skin/barcod.png");
}

и из .xul:

Выделить код

Код:

<toolbox id="navigator-toolbox">
    <toolbar id="SF-Toolbar" class="chromeclass-toolbar"
             context="toolbar-context-menu" toolbarname="&ACFilling.toolbarName;"
             hidden="false" persist="hidden">
      <toolbaritem flex="0">
        <toolbarbutton id="SF-Fill" tooltiptext="&ACFilling.bFillTT;"
                label="&ACFilling.bFill;" command="sfc_fill" />
      </toolbaritem>
    </toolbar>
  </toolbox>

  <toolbarpalette id="BrowserToolbarPalette">
        <toolbarbutton id="SF-Fill" tooltiptext="&ACFilling.bFillTT;"
                label="&ACFilling.bFill;" command="sfc_fill" />
  </toolbarpalette>

Смотрел готовые расширения (например для работы с HandyCache) - особой разницы не нашёл (ну или не там искал).
Вот разве что попробовал прописать

Выделить код

Код:

class="toolbarbutton-1"

- и сразу надпись стала под кнопкой, но вот только картинки в Настройке панелей инструментов теперь явно от стандартного тулбара, причем она там вся - все 5х14 картинок?..
Явно где-то должна прописываться эта информация.
Куда копать?

Forest

Явно где-то должна прописываться эта информация.
Куда копать?

Значит, при настройке тулбара видно только class="toolbarbutton-1".

В chrome.manifest нужно добавить примерно следующее:

Выделить код

Код:

style chrome://global/content/customizeToolbar.xul chrome://путь_до_стилей.css

Соответственно, в css должен описываться внешний вид кнопки.

Infocatcher

В chrome.manifest нужно добавить примерно следующее:

Да, спасибо, так заработало :)
Причем на 2-ке даже без

Выделить код

Код:

class="toolbarbutton-1"

. Но вот на 3-ке без него уже не работает.

А контекстное меню (contentcontextmenu) tabbrowser-ра - это что?
Это которое по правой мышке над пустым местом/кнопкой выпадающего списка табов?

Код из about Лиса не работает в Громоптице.

Выделить код

Код:

<text value="&tbae.creator;" class="url"
          tooltiptext="&tbae.creator.email;"
          onclick="window.open('mailto:&tbae.creator.email;');"/>

В Лисе при нажатии на такое открывается окно и пытается запуститься почтовый клиент.
А в Громоптице выдается ошибка:

Ошибка: uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMJSWindow.open]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: chrome://tbae/content/dialogs/about.xul :: onclick :: line 1"  data: no]

Forest
Попробуй

Выделить код

Код:

window. open ('mailt:&tbae.creator.email;', '_blank', 'chrome,dependent=yes,all');

или

Выделить код

Код:

window.location.href="mailto:&tbae.creator.email;";

Anton
Shutnik
Спасибо, работает :)
Но второй вариант предпочтительнее, так как первый порождает какое-то вырожденное окно, которое приходится закрывать, чтобы работать дальше.

Не подскажите, с чего начать, чтобы сделать самый простой работающий аддон для FF.
Пытался делать по https://developer.mozilla.org/en/Building_an_Extension, но в итоге то что получилось не работает. =(
На этом форуме нашел пример http://www.inode.ru/articles/programming/2005-10-04/85, но он еще на FF1 - хочется поновее что-то.

М.б. кто-то сможет что-то подсказать.

Snipe
в вики есть немного информации
http://forum.mozilla-russia.org/doku.php?id=development:extension:firefox
http://forum.mozilla-russia.org/doku.php?id=development:extension:mozilla
http://forum.mozilla-russia.org/doku.php?id=development:xul:app:part1

Snipe
прежде всего, элемент menu должен лежать в menubar
вместо appcontent, свои элементы надо размещать в browser-bottombox. рекомендую посмотреть через DOM Inspector на панель поиска

Еще раз спасибо. Сейчас попробую.

А пока еще ряд вопросов:
1. Что за DOM Inspector?
2. Как сделать простую ссылку? Ну т.е. чтоб нажимал на кнопку/ссылку в моем аддоне и вместо текущей страницы загружалась моя.
Нашел  <label href="http://www.ya.ru" class="text-link" value="Right click for popup"/> но такая строчка открывает новое окно браузера, а мне надо именно в текущем окне.
3. Возможно как-то открывать через <iframe> нужную мне страницу, и чтоб ссылки с нее тоже работали корректно? Пробовал в ссылках загружаемого html-документа писать onclick="top.window.location.href='http://ya.ru'" - но с таким вариантом у браузера ничего кроме экрана со страницей и не остается.
Над страницей, загружаемой в <iframe> имею полную власть и могу с ней делать все что захочу.
Смысл этой затеи - иногда менять ссылки и чтоб пользователь мог нормально ими пользоваться.


Посмотрел, если испольовать

Выделить код

Код:

<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <hbox id="browser-bottombox">

то получается что мой аддон появляется под статусбаром, а мне надо над.


2, 3 уже сам разобрался. window.content.location.href использовал.

Что за DOM Inspector?

Snipe
DOM Inspector

Z&N пишет

Что за DOM Inspector?

Snipe
DOM Inspector

Спасибо. Поставил - разбираюсь.
Это надо через File -> Inspect Chrome Document?

Пытаюсь работать с аттачами в приходящих письмах (ThunderBird 2).
Но только вот не очень понятно, как добраться до аттачей пришедшего письма.
Ну или до аттачей письма, Uri которого известен.

Вообще на developer.mozilla.org на эту тему информации кот наплакал :(
Конечно есть описания отдельных интерфейсов, но нужного не нашёл.

В принципе пытаюсь копать расширение attachment_extractor, но там как-то уж очень всё заморочено :(

Подскажите пожалуйста (лучше пример или ссылку на правильный сайт) :)

Forest
я тоже очень долго ковырял этот вопрос, но нормально пути решения не нашёл.
смотрел код attachment extractor: очень запутанный и непонятный код, так и не смог понять как оно работает, по-моему сделать можно было гораздо проще. нашёл кучу конструкций типа a=a+"" и других wtf, желание смотреть дальше отпало.
разговаривал с автором, он использует следующий костыль: создаёт свою скрытую область просмотра, затем открывает в ней письма как в обычном списке писем

Shutnik
Собственно я почти всё раскопал теперь надо только откуда-то взять ContentType, URL и Name атача.

Ну или можно попробовать выделить/открыть письмо - мб так и надо будет делать.

Я правильно понимаю, что полное АПИ можно достать только из исходников?

Про 3-ку кстати тоже такой информации не густо, хотя наверняка они апи расширяли?..

Собственно я почти всё раскопал теперь надо только откуда-то взять ContentType, URL и Name атача.

«почти всё» - это найти все письма с аттачами? это делает очень просто перебором списка писем.
проблема как раз в получении пути до аттача. без открытия письма его не получить, как я понял

Нашёл пример на оффсайте, который по описанию похож на то, что нужно - но при попытке его выполнить Птиц виснет :(
То есть как появляется внизу сообщение "INBOX Идёт загрузка заголовков сообщений: 1 из 1"  - так загрузка примерно на середине и останавливается.
Или такое нельзя вызывать в FolderListener-е?

MessageURI получен от загружающегося сообщения, а msgWindow - из примера по ссылке.

То есть вот:

Выделить код

Код:

var msgWindow = Components.classes["@mozilla.org/messenger/msgwindow;1"].createInstance(Components.interfaces.nsIMsgWindow);

    var content = "";
    var MsgService = messenger.messageServiceFromURI(mURI);
    var MsgStream =  Components.classes["@mozilla.org/network/sync-stream-listener;1"].createInstance();
    var consumer = MsgStream.QueryInterface(Components.interfaces.nsIInputStream);
    var ScriptInput = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance();
    var ScriptInputStream = ScriptInput.QueryInterface(Components.interfaces.nsIScriptableInputStream);
    ScriptInputStream.init(consumer);
    try {
      MsgService.streamMessage(mURI, MsgStream, msgWindow, null, false, null);
    } catch (ex) {
      alert("error: "+ex)
    }
    ScriptInputStream.available();
    while (ScriptInputStream.available()) {
      content = content + ScriptInputStream.read(512);
    }
    alert(content);

Проверил - виснет на

Выделить код

Код:

ScriptInputStream.available()

.

Forest пишет

Проверил - виснет на

Выделить код

Код:

ScriptInputStream.available()

.

У меня есть кнопка для TB с точно таким же кодом, не виснет. Может, с адресами что-то ?

Выделить код

Код:

var Cc = Components. classes;
var Ci = Components. interfaces;
function getDirectory ()
{
	var prefs = Cc ["@mozilla.org/preferences-service;1"].
		    getService (Ci. nsIPrefService).
		    getBranch ("custombuttons.buttons.saveSelected.");
	var fp = Cc ["@mozilla.org/filepicker;1"].
		 createInstance (Ci. nsIFilePicker);
	try
	{
		var folder = prefs. getComplexValue ("lastFolder", Ci. nsILocalFile);
		fp. displayDirectory = folder || null;
	} catch (e) {}
	fp. init (window, "", fp. modeGetFolder);
	var res = fp. show ();
	if (res != fp. returnOK)
		return null;
	prefs. setComplexValue ("lastFolder", Ci. nsILocalFile, fp. file);
	return fp. file;
}
function saveAsFile (uri, dir)
{
	var content = "";
	var subject = messenger. messageServiceFromURI (uri).
		      messageURIToMsgHdr (uri). mime2DecodedSubject;
	filename = GenerateValidFilename (subject, ".eml");
	var msgService = messenger. messageServiceFromURI (uri);
	var msgStream =  Cc ["@mozilla.org/network/sync-stream-listener;1"]. createInstance ();
	var consumer = msgStream. QueryInterface (Ci. nsIInputStream);
	var scriptInput = Cc ["@mozilla.org/scriptableinputstream;1"].
			  createInstance ();
	var scriptInputStream = scriptInput. QueryInterface(Ci. nsIScriptableInputStream);
	scriptInputStream. init (consumer);
	try
	{
		msgService. streamMessage (uri, msgStream, msgWindow, null, false, null);
	}
	catch (ex)
	{
		alert("error: "+ex)
	}
	scriptInputStream. available ();
	while (scriptInputStream. available ())
	{
		content = content + scriptInputStream. read (512);
	}
	var subject = msgService. messageURIToMsgHdr (uri).
		      mime2DecodedSubject;
	var fileName = GenerateValidFilename (subject, ".eml");
	var file = dir. clone ();
	file. append (fileName);
	if (file. exists ())
		file. createUnique (Ci. nsIFile. NORMAL_FILE_TYPE, 0664);
	var foStream = Cc ["@mozilla.org/network/file-output-stream;1"].
		       createInstance (Ci. nsIFileOutputStream);
	var flags = 0x02 | 0x08 | 0x20;
	foStream. init (file, flags, 0664, 0);
	foStream. write (content, content. length);
	foStream. close ();
}
var dir = getDirectory ();
if (!dir)
	return;
var messageArray = GetSelectedMessages();
for (var i = 0; i < messageArray. length; i++)
	saveAsFile (messageArray [i], dir);

Anton

У меня есть кнопка для TB с точно таким же кодом, не виснет

Я правильно понимаю, что этот код сохраняет все выбранные сообщения целиком в файлы?

А mime2DecodedSubject предпочтительнее использовать чем просто Subject?

А зачем кстати в коде 2 раза получается subject, причём на одном уровне и оба раза через var: до и после кода, который у меня не работает?

Forest пишет

Anton

У меня есть кнопка для TB с точно таким же кодом, не виснет

Я правильно понимаю, что этот код сохраняет все выбранные сообщения целиком в файлы?

Да.

А mime2DecodedSubject предпочтительнее использовать чем просто Subject?

Если речь идёт о nsIMsgDBHdr. subject vs nsIMsgDBHdr. mime2DecodedSubject, то да, для задачи сохранения сообщений в файлы - предпочтительнее.

А зачем кстати в коде 2 раза получается subject, причём на одном уровне и оба раза через var: до и после кода, который у меня не работает?

Видимо, такая у var subject судьба )

Собственно с вашей помощью осилил код Attachment Extractor-а, и даже смог написать свой работающий вариант.
Спасибо :)

Только вот новый ступор - можно как-то создать и отослать письмо полностью автоматом?
Причём желательно без эмуляции нажатия на кнопки.
Перерыл все АПИ - не нашёл :(
То есть создать письмо и открыть его проблем нет, а вот чтобы не открывалось, а сразу посылалось?..
Ещё почему-то у nsIMessenger не работают setWindow() и openURL()?..

Forest
Попробуй

Выделить код

Код:

try
{
	var gIOService = Components. classes ["@mozilla.org/network/io-service;1"].
			 getService (Components. interfaces. nsIIOService);
	var uri = gIOService. newURI ("mailto:recipient@mail.com", null, null);
	var sMsgComposeService = Components. classes ["@mozilla.org/messengercompose;1"].
				 getService (Components. interfaces. nsIMsgComposeService);
	var params = sMsgComposeService. getParamsForMailto (uri);
	params. composeFields. from = "user@mail.com";
	params. composeFields. subject = "any subject";
	params. composeFields. body = "\nany message";
	params. composeFields. forcePlainText = true;
	params. composeFields. useMultipartAlternative = true;
	var am = Components. classes ["@mozilla.org/messenger/account-manager;1"].
		 getService (Components. interfaces. nsIMsgAccountManager);
	var identity = am. createIdentity ();
	identity. fullName = "Full Name";
	identity. email = "user@mail.com";
	var smtpService = Components. classes ["@mozilla.org/messengercompose/smtp;1"].
			  getService (Components. interfaces. nsISmtpService);
	var ss = smtpService. createSmtpServer ();
	identity. smtpServerKey = ss. key;
	ss. hostname = "smtp.mail.com";
	ss. port = 25;
	ss. username = "user"; // *******************
	ss. password = "password"; // ***************
	var msgWindow = Components. classes ["@mozilla.org/messenger/msgwindow;1"].
			createInstance();
	msgWindow = msgWindow. QueryInterface (Components. interfaces. nsIMsgWindow);
	msgWindow. SetDOMWindow (window);
	msgWindow. rootDocShell. allowAuth = true;
	var compose = sMsgComposeService. InitCompose (window, params);
	compose. SendMsg (Components. interfaces. nsIMsgCompDeliverMode. Now, identity, "fakeAccount", msgWindow, null);
}
catch (e)
{
	alert (e);
}

Anton
Спасибо, попробую :)
Только вот надо будет ещё понять, как использовать штатный SMTP, хотя это уже мелочи.

Диалоговое окно в процессе работы меняет размер.
Как сделать, чтобы оно оставалось в центре?
Или только явно менять размер?

На centerWindowOnScreen() ругается, что нет такого.
Размер меняю через sizeToContent().

Forest пишет

На centerWindowOnScreen() ругается, что нет такого.
Размер меняю через sizeToContent().

sizeToContent вызывается из window, centerWindowOnScreen должен вызываться от элемента dialog
если размер меняется не сильно, то окно лучше не центрировать имхо, т.к. начинает прыгать

В XUL Explorer по alert(centerWindowOnScreen) из <dialog>...</dialog> выдаётся

Выделить код

Код:

function centerWindowOnScreen() {
    var xOffset = screen.availWidth / 2 - window.outerWidth / 2;
    var yOffset = screen.availHeight / 2 - window.outerHeight / 2;
    xOffset = xOffset > 0 ? xOffset : 0;
    yOffset = yOffset > 0 ? yOffset : 0;
    window.moveTo(xOffset, yOffset);
}

Shutnik

если размер меняется не сильно, то окно лучше не центрировать имхо, т.к. начинает прыгать

Похоже на то, но тут ситуация специфическая.

Anton

В XUL Explorer по alert(centerWindowOnScreen) из <dialog>...</dialog> выдаётся

Спасибо, работает :)

Похоже я нашёл баг в Attachment Extractor-е - опубликовал его на оффсайте. Вот: Multiple sequence extractions fail!.

Что-то похоже window.setTimeout в Птице 2 значение таймаута не воспринимает: ставлю 10000 - всё равно выходит по избыточности рекурсий через 1000 раз (а с таким таймаутом она должна была этот цикл крутить 3 часа - 10000 сек) :(

Forest пишет

10000 сек

Вообще-то, милисекунд.

Cristian

Вообще-то, милисекунд.

Я имею в виду суммарно.
10000 миллисекунд (которые я задаю как параметр метода) * 1000 (максимально допустимая глубина рекурсии - наверное равно размеру стека вызовов) как раз = 10000000 миллисекунд = 10000 секунд.

При этом используется следующий код для ожидания:

Выделить код

Код:

function wait4Load() {
	if(условие выхода из ожидания) {
		return true;
	} else {
		setTimeout(wait4Load(),10000);
	}
}

Я ведь вроде всё правильно написал?

Или эту задачу (ожидания события) можно решить как-то иначе?
В принципе можно конечно найти какое-нибудь более-менее регулярно происходящее событие и использовать для этой цели его обработчик, но как-то это неправильно...

Я ведь вроде всё правильно написал?

Разумеется, нет. У тебя при вычислении аргументов для setTimeout вызывается wait4Load, отсюда и переполнение стёка.

Или эту задачу (ожидания события) можно решить как-то иначе?

Использовать глобальные уведомления (nsIObserverService). Если ждёшь загрузку письма, может быть (точно не знаю) в TB на это уже есть глобальное уведомление.
Если нет - можно сделать своё.

Anton

Разумеется, нет. У тебя при вычислении аргументов для setTimeout вызывается wait4Load, отсюда и переполнение стёка.

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

На самом деле прочитал про это дело здесь - так там часы сделаны как с использованием setTimeout (собственно у меня также и сделано), так и setInterval.

08-12-2008 20:26:24
В общем наверное действительно в данной ситуации лучше использовать setInterval - сделал с ним - всё работает - всем спасибо за участие :)

А что надо вызывать?

setTimeout, что ты и пытаешься сделать, только этого не происходит, по причине того, что аргументы setTimeout перед передачей ей управления вычисляются.

Выделить код

Код:

setTimeout (wait4Load (), 10000);

Первым (а хотя бы и вторым) вычисляется первый аргумент "wait4Load ()", который есть вызов функции.
Получается
setTimeout (wait4Load { setTimeout (wait4Load { setTimeout ........... stack overflow.

в данной ситуации лучше использовать setInterval

не забудь скобки поставить )

Anton

Первым (а хотя бы и вторым) вычисляется первый аргумент "wait4Load ()"

Вот я тормоз - скобки поставил :(
Понял наконец-то свою ошибку, но вариант с setInterval конечно правильнее :)
Ещё такой момент - я правильно понимаю, что лишний вызов clearInterval ничем не навредит? А то не нашёл как можно отслеживать эти самые интервалы.

лишний вызов clearInterval ничем не навредит?

Если id интервала не будет достоянием кода из разных окон, то вряд ли.

Anton
Уж не знаю, в чём там дело, но пришлось заменить setInterval обратно на setTimeout - почему-то не получалось полностью его выключить через clearInterval.
С учётом пропуска мною () - это уже не очень удивляет, но вариант с setTimeout работает как задумано.

пришлось заменить setInterval обратно на setTimeout

Я предполагал, что может "не взлететь".
Везде есть свои грабли.

А как-то с cookies можно работать в XUL?
Обычно они ставятся на текущем домене, а в случае с приложением мы не имеем отношения к какому-то конкретному домену.
Есть какие-нибудь особенности и что-нибуь по данному поводу почитать?

А как-то с cookies можно работать в XUL?

https://developer.mozilla.org/En/Code_snippets/Cookies

Anton пишет

А как-то с cookies можно работать в XUL?

https://developer.mozilla.org/En/Code_snippets/Cookies

Спасибо, то что надо.

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

С одной частью сам разобрался, просто добавить в начальную страницу можно примерно так:

Выделить код

Код:

var Cc = Components.classes;
var Ci = Components.interfaces;

var url = "http://forum.mozilla-russia.org/";

var param = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
var str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
str.data = url;
param.setComplexValue("browser.startup.homepage", Ci.nsISupportsString, str);

Осталось только первый запуск и разрешение пользователя %)

Snipe

Осталось только первый запуск и разрешение пользователя

По первому запуску тут была целая тема.
Например можно проверять на наличие собственного параметра, и если его нет - значит первый запуск.
А спрашивать проще всего confirm-ом.

Такой вопрос возник про 2-ку (даже про Птицу, но не думаю, что там есть различия):
Как правильно включать одни файлы *.js в другие?
Сейчас пользуюсь вариантом, когда несколько *.js включаются в общий *.xul файл (или это единственный вариант?).

Или это всё появляется лишь в 3-ке?

Что значит "включать" ?
Если обычным текстом - то никак. Может быть, будет во 2-й версии ECMAScript.
Если нужен подгружаемый скрипт - используй mozISubscriptLoader.
Если просто в окне нужны определения из разных файлов - набор элементов <script> в оверлее - самый правильный вариант.

Anton

Если просто в окне нужны определения из разных файлов - набор элементов <script> в оверлее - самый правильный вариант.

Это именно тот вариант, про который я говорил - получается, что он единственный.

А действительно нельзя сделать окно настроек расширения окном с изменяемым размером?
Или это я плохо искал?

Ну всем хорошо сочетание (для того же окна настроек расширения)

Выделить код

Код:

sizeToContent();
	centerWindowOnScreen();

, но если размер содержимого начинает превышать размер окна - всё ломается :(

Подскажите, пожалуйста, нигде так и не смог найти ответ.

Пишу расширение, которое читает данные из файла и сравнивает их с тем, что на html странице. В текстовом файле может находиться текст как на русском, так и на английском языках.

Вот сейчас пытаюсь реализовать код, который бы читал данные из файла и выводил бы их алертом. Всё работает, за исключением того, что русские буквы в алерте выводятся коряво, а английские - нормально.
Код:

Выделить код

Код:

var mLocalFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
			var line = {};
			mLocalFile.initWithPath("C:\\1.txt");
			
			if(!mLocalFile.exists())
				return "";		
			
			var mFileInputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
-        	mFileInputStream.init(mLocalFile, 0x01, 0444, 0);
			var mInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
			mInputStream.init(mFileInputStream);
					
			var mn = mInputStream.read(mInputStream.available());
			alert(mn);

Примерно так:

Выделить код

Код:

var suc = Components. classes ["@mozilla.org/scriptableunicodeconverter;1"].
		  createInstance (Components. interfaces. nsIScriptableUnicodeConverter);
suc. charset = "windows-1251";
mn = suc. ConvertToUnicode (mn);

см. http://xulplanet.com/references/xpcomref/ifaces/nsIScriptableUnicodeConverter.html

Anton спасибо большое!

entropy пишет

что русские буквы в алерте выводятся коряво

Можно просто файл с текстом сохранить как utf8.

Forest пишет
entropy пишет

что русские буквы в алерте выводятся коряво

Можно просто файл с текстом сохранить как utf8.

Ошибаешься.

А подскажите, пожалуйста, ещё по кодировке.
Тот пример что Anton предложил работает только при чтении из файла. Когда я пытаюсь выполнить этот код:

Выделить код

Код:

function convert(data){
	var suc = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
	suc.charset = "windows-1251";
	return suc.ConvertToUnicode(data);
}

content.document.body.innerHTML = convert("Текст");

Опять получается коряво.

Насколько я помню, все строки в JS во время выполнения уже в Unicode, поэтому дополнительно еще раз конвертировать не стоит. Вопрос в том, правильно ли определяется кодировка самого JS-файла. Об этом здесь: International characters in XUL JavaScript. А вообще правильно не писать нелатинские буквы в коде и использовать локализацию.

Forest пишет

Такой вопрос возник про 2-ку (даже про Птицу, но не думаю, что там есть различия):
Как правильно включать одни файлы *.js в другие?
Сейчас пользуюсь вариантом, когда несколько *.js включаются в общий *.xul файл (или это единственный вариант?).

Или это всё появляется лишь в 3-ке?

А нельзя вот так? :

Выделить код

Код:

var scripteg = document.createElement('script');
scripteg.src = 'URL';
kakoi_nibud_el.appendChild(scripteg)

или так?:

Выделить код

Код:

document.write('<script src="url"></script>);

Честно говоря сам не пробовал. :blush:

А вот мой вопрос:
Есть у меня в аддоне ссылки, кнопки и прочая нажимаемая ерунда.
Сейчас она работает через window.content.location.href и все ссылки которые открываются, открываются в текущем окне, в текущей закладке.
А как мне сделать, чтоб после нажатия на них ссылка открывалась в новой закладке браузера?

Snipe пишет

А как мне сделать, чтоб после нажатия на них ссылка открывалась в новой закладке браузера?

Если я правильно понял, о чём речь, то window.open должен помочь.

Всем привет.
Использую <toolbarbutton type="menu" width="375">
Если подставляю ему короткий label - слово получается посередине кнопки:
93c907802f72.jpg

Как можно слово это выровнять по левому краю? align="left" не помогает.

Snipe
Наверное, проще будет через css

Выделить код

Код:

#tbid>.toolbarbutton-text {
  margin: 0 !important;
  text-align: left;
}

'tbid' - id toolbarbutton'а

Anton пишет

Snipe
Наверное, проще будет через css

Выделить код

Код:

#tbid>.toolbarbutton-text {
  margin: 0 !important;
  text-align: left;
}

'tbid' - id toolbarbutton'а

Ну и конструкция. :/
Спасибо, работает.

Хочу вызывать функцию при смене табов пользователем.
Сделал так:

Выделить код

Код:

window.addEventListener('select', 
  function(event) {
    if (event.originalTarget.tagName == 'xul:tabs') alert('test')
  }, 
false);

Вроде работает, но т.к. опыта мало..., вдруг есть какой-нибудь более правильный вариант?!

В контекстном меню Лисы есть такой пункт как "Получить исходный код выделенного фрагмента". Подскажите, пожалуйста, как произвести эту операцию программно, в коде расширения, и получить этот исходник в переменную.

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

Уверенное "НЕТ" тоже будет хорошим ответом. :D

Можно ли как-то в аддоне узнать локальный ip адрес пользователя?

Есть такой вариант:

Выделить код

Код:

var obj = Components.classes["@mozilla.org/network/dns-service;1"].
            getService(Components.interfaces.nsIDNSService);
var hip = obj. resolve (obj. myHostName, 0);
var ip;
var res = "";
while (hip. hasMore ())
{
	ip = hip. getNextAddrAsString ();
	res += ip + "\n";
}
alert (res);

Подскажите, а возможно ли сделать и как следуешее - встроить функцию в DOM сайта ? в смысле хочу вызывать с сайта функцию скажем document.myDom.myFunction(); возвращающую/устанавливающие некие сеттинги заданные в sqlite на стороне пользователя. Я что-то поискал и не нашел где это описано.

Eictol0n, Interaction between privileged and non-privileged pages

Anton пишет

Можно ли как-то в аддоне узнать локальный ip адрес пользователя?

Есть такой вариант:

Не знаю, что делаю не так, но не работает, а try/catch выдает
Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIDNSService.resolve]


И еще вопрос, как узнать IP сайта, на который пользователь зашел?

Еще вопрос. У меня в аддоне событие происходит по загрузке страницы:

Выделить код

Код:

window.addEventListener(
  'load',
  function () {
    gBrowser.addEventListener('load', pageLoaded, true);
  },
  false
);

А можно как-то сделать, чтоб событие происходило не по окончании загрузки, а при начале.
Т.е. УРЛ уже поменялся, но страница не догрузилась и вот в это время...

Не знаю, что делаю не так, но не работает, а try/catch выдает
Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIDNSService.resolve]

Скорее, я ошибся с решением.

А можно как-то сделать, чтоб событие происходило не по окончании загрузки, а при начале.

gBrowser.webProgress для всех табов или аналогично для конкретного browser

На всякий случай: есть еще DOMContentLoaded - когда загрузился только html, а картинки и т.д. - еще нет.

Crazy-EyE пишет

А можно как-то сделать, чтоб событие происходило не по окончании загрузки, а при начале.

gBrowser.webProgress для всех табов или аналогично для конкретного browser

На всякий случай: есть еще DOMContentLoaded - когда загрузился только html, а картинки и т.д. - еще нет.

C DOMContentLoaded понятно:
gBrowser.addEventListener('DOMContentLoaded', pageLoaded, true);

а с gBrowser.webProgress что-то никак не разберусь, м.б. есть где-то пример? :(

Добавлено:
Сделал так, вроде работает (тестирую):

Выделить код

Код:

var myProgressListener = {'onLocationChange': function(a, b, c, d){pageLoaded(a, b, c, d);}};
gBrowser.addProgressListener(myProgressListener);

м.б. есть где-то пример?

Progress Listeners

EDIT: исправил ссылку

Crazy-EyE пишет

м.б. есть где-то пример?

Progress Listeners

(There is currently no text in this page)

Но все равно спасибо, первый пост помог. Пока вроде работает, как выше писал.

Совсем нубский вопрос.
Если я ставлю аддон, могу я как-то через него заодно добавить поисковый плагин?

А зачем через аддон? Поисковики и так ставятся неплохо... Вот отсюда :P

ПротопопулуS пишет

А зачем через аддон? Поисковики и так ставятся неплохо... Вот отсюда :P

НУ сам по себе поисковик не нужен без аддона, а лишние действия для пользователя (поставить отдельно поисковик и отдельно аддон) - тоже не хотелось бы.

Snipe, упс, исправил.

НУ сам по себе поисковик не нужен без аддона, а лишние действия для пользователя (поставить отдельно поисковик и отдельно аддон) - тоже не хотелось бы.

Если внутри расширения сделать директорию /searchplugins и положить туда поисковик, думаю, будет работать (сам не пробовал). Application-specific Extension Files

В крайнем случае есть еще Multiple Item Packaging.

Crazy-EyE пишет

Если внутри расширения сделать директорию /searchplugins и положить туда поисковик, думаю, будет работать (сам не пробовал). Application-specific Extension Files

Спасибо, работает.

А можно как-то после установки расширения и соответственно поискового плагина с разрешения пользователя ставить плагин по умолчанию?

Как всегда, уверенное нет - тоже хороший ответ.

entropy

Вот код скриплета

Выделить код

Код:

javascript:function%20getSelSource()%20{%20x%20=%20document.createElement(%22div%22);%20x.appendChild(window.getSelection().getRangeAt(0).cloneContents());%20return%20x.innerHTML;%20}%20function%20makeHR()%20{%20return%20nd.createElement(%22hr%22);%20}%20function%20makeParagraph(text)%20{%20p%20=%20nd.createElement(%22p%22);%20p.appendChild(nd.createTextNode(text));%20return%20p;%20}%20function%20makePre(text)%20{%20p%20=%20nd.createElement(%22pre%22);%20p.appendChild(nd.createTextNode(text));%20return%20p;%20}%20nd%20=%20window.open().document;%20ndb%20=%20nd.body;%20if%20(!window.getSelection%20||%20!window.getSelection().rangeCount%20||%20window.getSelection().getRangeAt(0).collapsed)%20{%20nd.title=%22Generated%20Source%20of:%20%22%20+%20location.href;%20ndb.appendChild(makeParagraph(%22No%20selection,%20showing%20generated%20source%20of%20entire%20document.%22));%20ndb.appendChild(makeHR());%20ndb.appendChild(makePre(%22%3Chtml%3E\n%22%20+%20document.documentElement.innerHTML%20+%20%22\n%3C/html%3E%22));%20}%20else%20{%20nd.title=%22Partial%20Source%20of:%20%22%20+%20location.href;%20ndb.appendChild(makePre(getSelSource()));%20};%20void%200

Если интересен сам скриплет, то все должно быть в одну строчку без переносов, а так - готовое решение javascript

ipSlicer
Спасибо большое, сейчас попробую:)

Всем привет.
Сделал в аддоне поиск слова на странице и его выделение через nsIFind.
Но когда использую .Find() - можно ввести только одно слово.
Можно как-то сделать такой поиск не по одному слову, а по нескольким сразу? М.б. через RegExp или еще как-то?

Можно как-то через event, по событию load для нового таба получить document этого таба?
Когда загружаемый таб открыт поверх остальных - все просто:
var doc = getBrowser().contentDocument;

Но мне надо получить содержимое таба, который не текущий. Например как после нажатия колесом мышки на ссылку.

Можно как-то через event, по событию load для нового таба получить document этого таба?

Если сам таб не нужен, примерно так:

Выделить код

Код:

...
        if (event. originalTarget. nodeName == "#document")
        {
            var loc = event. originalTarget. location. href;
            if (loc. substr (0, 32) == "http://forum.mozilla-russia.org/")
            {
                var doc = event. originalTarget;
...

А как сделать настройки для расширения через кнопку "настройки", которая показывается под каждым расширением в списке расширений?
Условно говоря XUL-страница под настройки у меня уже есть, но я ее запускаю с интерфейса самого расширения. Не хочу чтоб кнопка под настройки место занимала.

А как сделать настройки для расширения через кнопку "настройки", которая показывается под каждым расширением в списке расширений?

optionsURL в install.rdf

Crazy-EyE пишет

А как сделать настройки для расширения через кнопку "настройки", которая показывается под каждым расширением в списке расширений?

optionsURL в install.rdf

Спасибо огромное, то что надо. Читал эту статью давным давно - пропустил и забыл этот пункт. :(

А у меня вот такой вопрос еще назрел.
Я на странице определенного сайта с помощью расширения добавляю ссылки, через DOM.
Можно как-то к этим ссылкам сделать всплывающие подсказки?
Title и tooltextbar не работают. :/

Я страницу верчу через DOM как угодно, и после любых перетасовок wz-tooltips работает без проблем :)

Можно как-то узнать, есть ли на данном сайте стили на определенный тег?

Т.е. где-нибудь в CSS написано .a {color:red;text-decoration:none} и т.п.
Можно как-то силами расширения узнать, что на данном сайте у тегов "а" есть прописанный стиль?

Snipe
можно, перебирайте свойство (не атрибут) style нужного объекта

window.getComputedStyle

можно, перебирайте свойство (не атрибут) style нужного объекта

window.getComputedStyle

Получается немного не то:
1. Если стили прописаны, но на странице нет ссылки - не смогу узнать.
2. Если стили прописаны для всех ссылок отдельно, а для классов (например меню) отдельно. Придется все это отсеивать.

Если совсем точно, мне нужно узнать, есть ли где-нибудь в CSS строчка А{...}

Как, например FireBug показывает?

Выделить код

Код:

a {                                                             mail-spl...h3.css?27 (line 8)
    color:#0857A6;
    text-decoration:underline;
}

Смотреть надо в сторону https://developer.mozilla.org/En/DOM/Document.styleSheets, я думаю.

Вот код, который собирает все правила из первого stylesheet текущего документа:

Выделить код

Код:

var doc = getBrowser (). contentDocument;
var sss = doc. styleSheets;
var cssrs = sss. item (0). cssRules;
var s = "";
for (var j = 0; j < cssrs. length; j++)
	s += cssrs. item (j). cssText + "\n";
alert (s);

Где-то среди cssRules. item (j) возможно, найдётся и "А{...}".

Anton пишет

Смотреть надо в сторону https://developer.mozilla.org/En/DOM/Document.styleSheets, я думаю.

Вот код, который собирает все правила из первого stylesheet текущего документа:
...
Где-то среди cssRules. item (j) возможно, найдётся и "А{...}".

Спасибо, попробую так.
Еще вопрос, ставлю куки примерно так:

Выделить код

Код:

var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
    var cookieUri = ios.newURI("http://.mysite.com", null, null);
    var cookieSvc = Components.classes["@mozilla.org/cookieService;1"].getService(Components.interfaces.nsICookieService);

    cookieSvc.setCookieString(cookieUri, null, "your_key=your_value;", null);

И на сайте ставлю куки (.mysite.com).
В итоге получается, две разные куки:
с сайта: "домен: .mysite.com"
с расширения: "узел: mysite.com"

Все что нашел на MDC:

If you do not explicitly specify a domain in the cookieString then the domain will be derived from the cookieUri object.  This may not always be what you expect.  For instance, if the url contains an initial dot (i.e., http://.example.com) the derived name will be example.com (without the initial dot).

Можно как-то в куке, которая с расширения ставится добавить эту точку?

Snipe пишет

...
Все что нашел на MDC:

If you do not explicitly specify a domain in the cookieString then the domain will be derived from the cookieUri object.  This may not always be what you expect.  For instance, if the url contains an initial dot (i.e., http://.example.com) the derived name will be example.com (without the initial dot).

Там же вроде есть нужный код, на процитированной странице ?

Anton пишет

Там же вроде есть нужный код, на процитированной странице ?

Разобрался, спасибо. %)

Теперь опять к настройкам.
Сделал настройки через меню всех аддонов.
И по сохранению мне надо обновить данные в аддоне.
В настройках вызываю функцию обновления через window.opener.opener., т.е. как раз попадаю в "окно" с аддоном, и эта функция обновляет мне всё что нужно.
Но работает так, только если настройки были открыты через меню, если как-то еще - обновление не происходит. Потому что opener = null.

Можно как-то получить доступ к функции обновления (т.е. к основному окну браузера из окна настроек) не через window.opener?

observer на preference или обычный observer на глобальное уведомление ?

Можно ли из плагина получить доступ к полю формы открытой веб-странички, на котором стоит курсор... и как?

Цель - вставить код смайлика в поле ввода на, допустим, форуме.

Цель - вставить код смайлика в поле ввода на, допустим, форуме.

Выделить код

Код:

var theBox = document.commandDispatcher.focusedElement;
theBox += ": )";

примерно так.

Anton, спасибо за совет, но оно не работает.
Наверное, при вызове меню плагина фокус элемента страницы переходит на кнопку плагинта. Хотел следать задержку для переноса фокуса, но

Выделить код

Код:

setTimeout('pasteSmile(":-)")',1000);

почему-то не срабатывает.

Alive
При обработке события mousedown фокус ещё не на элементе с обработчиком.
Кроме того, можно воспользоваться элементом, который не принимает фокус, например, toolbarbutton.
Или стилизовать элемент, принимающий фокус правилом { -moz-user-focus: ignore; }

Благодарю, toolbarbutton даже красивее смотрится

Есть такая задача - нужно в google notebook extension сделать строку поиска. Желательно чтобы данные формировались по ходу поиска. Сколько такая штука будет стоить? можно тут, можно в личку, можно в аську 99525нольдва

Возможно как-то из одного окна браузера получить доступ к JavaSctipt'у расширения другого окна?
Окна вообще никак не связаны, просто браузер два раза открыт.

Snipe

Возможно как-то из одного окна браузера получить доступ к JavaSctipt'у расширения другого окна?

Возможно. Способов реализации несколько:
1. nsIWindowMediator. getMostRecentWindow (...) / nsIWindowWatcher. getWindowByName (...) или
2. nsIObserverService. notifyObservers (...) или
3. собственная компонента для взаимодействия между скриптами, работающими в разных окнах

Какой выбрать лучше - зависит от задачи.

Anton пишет

Snipe

Возможно как-то из одного окна браузера получить доступ к JavaSctipt'у расширения другого окна?

Возможно. Способов реализации несколько:
1. nsIWindowMediator. getMostRecentWindow (...) / nsIWindowWatcher. getWindowByName (...) или
2. nsIObserverService. notifyObservers (...) или
3. собственная компонента для взаимодействия между скриптами, работающими в разных окнах

Какой выбрать лучше - зависит от задачи.

Спасибо, второй вариант отлично подошел.

Вопрос не по разработке, а по обновлению.
Sergeys паланируете ли Вы обновить Forum.mozilla-russia.org 1.8.1 до совместимости с 3.6a1pre и, если "да", то когда?

И снова здравствуйте.
У меня в аддоне есть погода. При нажатии хочу, чтоб появлялось окошко с погодой на несколько дней вперед. Решил сделать это через iframe, примерно так:

Выделить код

Код:

<menupopup id="wearherMenu" style="padding:-50px;">
     <iframe id="wearherIfr" src="http://" type="content" style="overflow:hidden;width:400px;height:200px;padding-left:-50px;"/>
</menupopup>


wBlock.setAttribute('popup', 'wearherMenu');

Можно как-то документ в ifram'e прокрутить на нужный кусок документа?

Snipe, метод scrollTo(

x

,

y

);

Al_H пишет

Snipe, метод scrollTo(

x

,

y

);

alert($('wearherIfr').scrollTo); выдает undefined

alert($('wearherIfr').scrollTo); выдает undefined

Это метод окна, а не iframe, соответственно iframe. contentWindow. scrollTo
Кстати, если верить http://www.xulplanet.com/references/xpcomref/ifaces/nsIDOMNSHTMLElement.html у DOM-элементов есть метод scrollIntoView - наверное, можно просто найти этот элемент в документе iframe и позвать этот метод.

Добрый день ! Хочу сделать плагин который будет собирать статистику по активности браузера на основе движка cnstat (думаю всем известный движок). В плагин требуется установить код который предоставляет cnstat
<!-- CNStats begin -->
<span id="cnstats_span"><script type="text/javascript">
cnsd=document;
cnst=escape(cnsd.title);
cnst=cnst.replace(/\+/g,'%2B');
cnsa=navigator.appName;
cnsn=(cnsa.substring(0,2)=='Mi')?0:1;
cnss=screen;cnspx=(cnsn==0)?cnss.colorDepth:cnss.pixelDepth;
if (cnsd.getElementById)
{
    var i=cnsd.createElement('img');
    var amp=String.fromCharCode(38);
    var iurl='http://stat/cnt-gif1x1.php?';
    iurl+='e='+cnss.width+'.'+cnss.height;
    iurl+=amp+'d='+cnspx+amp+'r='+escape(cnsd.referrer);
    iurl+=amp+'p='+escape(cnsd.location)+amp+'t='+cnst;
    i.src=iurl;
    i.width=1;i.height=1;i.border=0;
    cnsd.getElementById('cnstats_span').appendChild(i);
}
</script></span><noscript><img src="http://stat/cnt-gif1x1.php?468&amp;c=0" width="1" height="1" border="0" alt="" /></noscript>
<!-- CNStats end -->
Нужно чтоб скрипт срабатывал каждый раз как произойдет DOMContentLoaded. Не соображу как это сделать. Либо подключать в плагин удаленный html который будет лежать на сервере, либо как то это код внедрить в плагин....... оч буду благодарен за помощь.
Желательно решение с использованием события DOMContentLoaded

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

dima9111

dima9111 пишет

можно ли конвртировать Greasemonkey в независимый плагин?

В смысле? А сейчас он какой?
Или речь про написанный в нём скрипт?

dima9111, можно попробовать http://arantius.com/misc/greasemonkey/script-compiler

Crazy-EyE пишет

dima9111, можно попробовать http://arantius.com/misc/greasemonkey/script-compiler

Дружище выручил!!!! Респект и уважуха!!!

Каким способом лучше добавть ява код от гугл аналитик в firefox
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-9464160-1");
pageTracker._trackPageview();
} catch(err) {}</script>
п?

Хочу создать собственный журнал посещений с использованием sqlite. Но не могу разобраться с принципами работы с sqlite на javascript. Если есть инф-я по этому поводу, подскажите. буду очень признательна (какие именно ф-ции в коде мозилы отвечают за считывание/добавление даных в бд places.sqlite?)

Claire пишет

Хочу создать собственный журнал посещений с использованием sqlite. Но не могу разобраться с принципами работы с sqlite на javascript. Если есть инф-я по этому поводу, подскажите. буду очень признательна (какие именно ф-ции в коде мозилы отвечают за считывание/добавление даных в бд places.sqlite?)

https://developer.mozilla.org/en/Storage.
У меня вопрос из той же области (SQLite и JavaScript). Существует таблица (tree).

tagidparent_id
first_level10
first_level20
second_level32
second_level42

Нужно построить DOM дерево.

Выделить код

Код:

...
statement=connection.createStatement("select * from tree order by parent_id");
my_document=document.implementation.createDocument("http://www.w3.org/1999/xhtml","root",null);
my_document.documentElement.setAttribute("id","0");
while (statement.executeStep()){
   element=my_document.createElement(statement.row.tag);
   element.setAttribute("id",statement.row.id);
   my_document.getElementById(statement.row.parent_id).appendChild(element);
}
...

Успешно вставляет первые два элемента (что в корне), но потом их не находит для вставки остальных. Говорит: "TypeError: my_document.getElementById(statement.row.parent_id) is null".
И ещё (другой вопрос по XUL'у). Как заставить элемент "<menulist editable='true'>" выводить только пункты, которые соответствуют тексту, набранному пользователем (как в строке адреса обозревателя)? Нужно писать свою функцию или достаточно эту возможность где-то включить?

Рено Гринлиф

Успешно вставляет первые два элемента (что в корне), но потом их не находит для вставки остальных. Говорит: "TypeError: my_document.getElementById(statement.row.parent) is null".

Столбец в таблице называется parent_id
Наверное, надо писать my_document.getElementById(statement.row.parent_id).appendChild(element); вместо my_document.getElementById(statement.row.parent).appendChild(element); ?

Извиняюсь. Опечатку (в сообщении) исправил, ошибка осталась.

Рено Гринлиф

Извиняюсь. Опечатку (в сообщении) исправил, ошибка осталась.

Причина, как я понял, в том, что createElement создает элементы в namespace отличном от namespace элемента root.
И getElementById ищет элементы, атрибут id которых в том же namespace, что и root.

Так что должно работать

Выделить код

Код:

...createElementNS ("http://www.w3.org/1999/xhtml", ...);

Благодарю за помощь.
Чуть не устроил себе рекурсию.

Зравствуйте.
Я пишу первое свое расширение и с JavaSkript-ом только сейчас познаокмился.

Оно по действию пользователя будет анализировать текущую страницу и на другой тсранице выдавать результат.

Делаю это все на основе ReloadEvery 3.6.2 (https://addons.mozilla.org/en-US/firefox/addon/115)
так как с нуля создать пока не получилось.
Там в файле reloadeveryOverlay.xul я добавил
<menuitem id="test_id"  label="test_label;"  type="checkbox" oncommand="org.mozdev.reloadevery.ShowMainForm(document)"/>     

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

Я все никак не могу получить доступ к данным на текущей html странице.

Следующие команды нормально выдают заголовок, адресс текущей страницы
alert(navigator.appName);
alert(window.document.title);
alert(window.content.location);
   
Но вот все попытки получить доступ к BODY или каким другим элементам закончились ничем.

alert("document.body.className="+document.body.className); - прекращается выполнение скрипта

var elems = document.getElementsByTagName("img");
alert("elems.length ="+elems.length); - найдено 0 элементов, хотя на странице есть изображения и в исходном коде присутствуют

Так как будут анализироваться произвольные страници, то использовать getElementById() нельзя

window.document.childNodes - исследование показалдо наличие 11 узлов один из которых XULobject, у которого еще 42 узла(но для разных страниц это число одинаково, значит очень сомнительно, что это, то что мне нужно).

alert("window.document.body.innerhtml="+window.document.body.innerhtml); - прекращается выполнение скрипта
    
alert(window.document.innerhtml) - undefined
alert(window.document.body) - undefined

Подскажите пожалусто как мне получить доступ?
Может я что-то упустил из виду.

Оказывается я ломился в обьект который содержит выпадающее меню, а не страницу.

Для доступа к текущей странице можно использовать следующий код

var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIWebNavigation)
                   .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                   .rootTreeItem
                   .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIDOMWindow);

    var body = mainWindow.getBrowser().selectedBrowser.contentDocument.body;
    getSelection().selectAllChildren(body);
    var doc = window.getSelection().toString();/*Имя doc важно возможно это переход между страницами*/
       
    var elems = body.getElementsByTagName('td');/*Получаем все элементы где тег <td> */

Пока для меня это осталось магическим кодом.

эта ссылка мне знакома. но все равно спасибо)
по-поводу динамического формирования tree:
-создаешь сначала каркас компонента tree:

Выделить код

Код:

<tree flex="1">
  <treecols>
    <treecol id="sender" label="Sender" flex="1"/>
    <splitter class="tree-splitter"/>
    <treecol id="subject" label="Subject" flex="2"/>
  </treecols>
  <treechildren id="tc">
  <script type="application/x-javascript" src="chrome://<package_name>/content/script_name.js"/>  
    </treechildren>
</tree>

- файл script_name.js может быть таким:

Выделить код

Код:

const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var tr_ch=document.getElementById("tc");
var i;
for (i=0;i<10;i++)
{
var it=document.createElementNS(XUL_NS, "treeitem"); // create a new XUL treeitem
var r=document.createElementNS(XUL_NS, "treerow"); // create a new XUL treerow
var cel1=document.createElementNS(XUL_NS, "treecell"); // create a new XUL treecell
cel1.setAttribute("label","col1 row"+i);
var cel2=document.createElementNS(XUL_NS, "treecell"); // create a new XUL treecell
cel2.setAttribute("label","col2 row"+i);
tr_ch.appendChild(it);
it.appendChild(r);
r.insertBefore(cel1,r.cel);
r.appendChild(cel2);
}

Посмотри. может пригодится

28-01-2010 11:37:32
всем доброго времени суток.
мне интересно: какие события обрабатывает браузер при формировании истории посещений?
добавляет ли он адрес страницы если просто перейти с одной вкладки на другую? или он рассматривает только загрузку новых страниц, в том числе игнорируя событие перезагрузки (обновления) текущей страницы? как он проверяет: успешно ли загружена страница? и т.п. Если кто-то знает ответ или место, где он находится, напишите пожалуйста.
(можно на почту DSvetlanaP@ukr.net)

Нашла на сайте мозилы код:

Выделить код

Код:

var history = Cc["@mozilla.org/browser/nav-history-service;1"].
              getService(Ci.nsINavHistoryService);
let observer = {
  onBeginUpdateBatch: function() {
  },
  onEndUpdateBatch: function() {
  },
  onVisit: function(aURI, aVisitID, aTime, aSessionID, aReferringID, aTransitionType) {
  },
  onTitleChanged: function(aURI, aPageTitle) {
  },
  onDeleteURI: function(aURI) {
  },
  onClearHistory: function() {
  },
  onPageChanged: function(aURI, aWhat, aValue) {
  },
  onPageExpired: function(aURI, aVisitTime, aWholeEntry) {
  },
  QueryInterface: function(iid) {
    if (iid.equals(Components.interfaces.nsINavHistoryObserver) ||
        iid.equals(Components.interfaces.nsISupports)) {
      return this;
    }
    throw Cr.NS_ERROR_NO_INTERFACE;
  }
};

history.addObserver(observer, false);

пробовала вставлять alert("hi"); для проверки срабатывания события onVisit() - не работает.
Не понимаю, ведь observer -это как раз то что мне нужно, в его описании написано, что он используется как
наблюдатель за событиями (истории), а событие onVisit отвечает за посещение новой странички. ведь так?
если знаете в чем дело и понимаете - что я не так делаю, напишите, пож-та.

вот такой вопрос:
на сайте грузится яваскрипт. я хочу в своём расширении его перехватывать и изменять до того, как этот яваскрипт будет исполнен. для этого я использую код, который нашёл в расширении pirate questing. получаю ошибку:
dump is not defined (ошибка в строке 177 моего файла)
что не так? и вообще - в правильную ли сторону я копаю, или в коде должно быть что-то ещё?
browser.dom.window.dump.enabled установлено в true
(greasemonkey и foxreplace мне не подходят)

Выделить код

Код:

try {

    //largely from firebug. should refactor 
    if (typeof Cc == "undefined") {
        var Cc = Components.classes;
        var Ci = Components.interfaces;
    }
    if (typeof CCIN == "undefined") {
        function CCIN(cName, ifaceName){
            return Cc[cName].createInstance(Ci[ifaceName]);
        }
    }
    if (typeof CCSV == "undefined") {
        function CCSV(cName, ifaceName){
            if (Cc[cName]) 
                return Cc[cName].getService(Ci[ifaceName]); // if fbs fails to load, the error can be _CC[cName] has no properties
            else 
                dump("CCSV fails for cName:" + cName); 
        };
    }
     
    function TracingListener() {
        //this.receivedData = [];
    }
        
    TracingListener.prototype =
    {
        originalListener: null,
        receivedData: null,   // array for incoming data.
    
        onDataAvailable: function(request, context, inputStream, offset, count)
        {
           var binaryInputStream = CCIN("@mozilla.org/binaryinputstream;1",
                    "nsIBinaryInputStream");
            var storageStream = CCIN("@mozilla.org/storagestream;1", "nsIStorageStream");
            binaryInputStream.setInputStream(inputStream);
            storageStream.init(8192, count, null);
            
            var binaryOutputStream = CCIN("@mozilla.org/binaryoutputstream;1",
                    "nsIBinaryOutputStream");
               
            binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
    
            // Copy received data as they come.*/
            var data = binaryInputStream.readBytes(count);
            //var data = inputStream.readBytes(count);
            
            this.receivedData.push(data);
    
            binaryOutputStream.writeBytes(data, count);
            this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
        },
    
        onStartRequest: function(request, context) {
            this.receivedData = [];
            this.originalListener.onStartRequest(request, context);
        },
    
        onStopRequest: function(request, context, statusCode)
        {
            try {
                request.QueryInterface(Ci.nsIHttpChannel);
            dump(request.originalURI.path);
                if (request.originalURI && 
                        request.originalURI.path.indexOf("/api/json/getBootstrapData.do") == 0) {
                    
                    //for(opt in request) {
                    //    dump("\nrequest."+opt);
                    //}
                    //dump(request.responseText);
                    var data = null;
                    if(request.requestMethod.toLowerCase() == "post") {
                        var postText = this.readPostTextFromRequest(request,context);
                        if (postText)  
                            data = ((String)(postText)).parseQuery();
                            
                    }
                    //dump("\nProcessing: " + request.originalURI.spec + "\n");
                    var date = Date.parse(request.getResponseHeader("Date"));
                    var responseSource = this.receivedData.join();
                    //fix leading spaces bug
                    responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/,"$1");
                    responseSource = responseSource.replace(/\"testDelay\":8/gm,'"testDelay":0');
                }
            } catch(e) { dump(e);}
            this.originalListener.onStopRequest(request, context, statusCode);
        },
    
        QueryInterface: function (aIID) {
            if (aIID.equals(Ci.nsIStreamListener) ||
                aIID.equals(Ci.nsISupports)) {
                return this;
            }
            throw Components.results.NS_NOINTERFACE;
        },
        readPostTextFromRequest : function(request, context) {
            try
            {
                var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream;
                if (is)
                {
                    var ss = is.QueryInterface(Ci.nsISeekableStream);
                    var prevOffset;
                    if (ss)
                    {
                        prevOffset = ss.tell();
                        ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
                    }
        
                    // Read data from the stream..
                    var charset = "UTF-8";
                    var text = this.readFromStream(is, charset, true);
        
                    // Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
                    // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
                    if (ss && prevOffset == 0) 
                        ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
        
                    return text;
                }
                else {
                    dump("Failed to Query Interface for upload stream.\n");
                }
            }
            catch(exc)
            {
                dump(exc);
            }
        
            return null;
        },
        readFromStream : function(stream, charset, noClose)    {
            
            var sis = CCSV("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
            sis.setInputStream(stream);
        
            var segments = [];
            for (var count = stream.available(); count; count = stream.available())
                segments.push(sis.readBytes(count));
        
            if (!noClose)
                sis.close();
        
            var text = segments.join("");
            return text;
        }
        
    }


    hRO = {

        observe: function(request, aTopic, aData){
            try {
                if (aTopic == "http-on-examine-response") {
                    request.QueryInterface(Ci.nsIHttpChannel);
                    
                dump(request.originalURI.path);
                    if (request.originalURI && 
                            request.originalURI.path.indexOf("/api/json/getBootstrapData.do") == 0) {
                        var newListener = new TracingListener();
                        request.QueryInterface(Ci.nsITraceableChannel);
                        newListener.originalListener = request.setNewListener(newListener);
                    }
                }
            } catch (e) {
                dump(e);
            
            }
        },
        
        QueryInterface: function(aIID){
            if (aIID.equals(Ci.nsIObserver) ||
            aIID.equals(Ci.nsISupports)) {
                return this;
            }
            
            throw Components.results.NS_NOINTERFACE;
            
        },
    };
        

    var observerService = Cc["@mozilla.org/observer-service;1"]
        .getService(Ci.nsIObserverService);
    
    observerService.addObserver(hRO,
        "http-on-examine-response", false);
    
} catch (e) { dump(e);}

Claire

Подозреваю, в начале надо написать

Выделить код

Код:

var Cc = Components. classes;
var Ci = Components. interfaces;

CountZero

А если определить как-нибудь функцию dump ?

Выделить код

Код:

function dump () {}

Добрый день всем, никогда не создавал расширения для фф. Не знаю с чего начать. Хочу создать расширения в виде дополнительного меню. Аналог меню Закладки, это для одного форума, чтобы сделать навигации более быстрым.

Hella

Попробуйте в качестве точки отсчета взять это расширение.

Anton пишет

Claire

Подозреваю, в начале надо написать

Выделить код

Код:

var Cc = Components. classes;
var Ci = Components. interfaces;

CountZero

А если определить как-нибудь функцию dump ?

Выделить код

Код:

function dump () {}

Разумеется, я это сделала. Все равно не работает. не в этом дело.

Claire

У меня код работает, проверял на Firefox 3.5.6, 3.5.8, 3.6.

При добавлении в начало кода строк

Выделить код

Код:

var Cc = Components. classes;
var Ci = Components. interfaces;

а в метод onVisit строки

Выделить код

Код:

alert ("visit");

и открытия журнальной записи после выполнения кода, появляются два сообщения "visit".

Anton пишет

CountZero

А если определить как-нибудь функцию dump ?

Выделить код

Код:

function dump () {}

похоже, что у меня была ошибка в манифесте. сейчас всё работает почти нормально... но со странностями: если я перехватываю ответ на AJAX-запрос, html-документ или открытый в браузере яваскрипт - то расширение отрабатывает нормально. проблема в том, что мне надо перехватывать именно яваскрипт, определённый во внешнем файле через тэг <script type="test/javascript" src="http://www.example.com/example.js">. а при работе со внешними ресурсами почему-то нужные события не срабатывают :(

эта проблема тоже решилась, добавлением строки
observerService.addObserver(hRO, "http-on-examine-cached-response", false);
в скрипт

хочу подгружать в кэш  нужные мне страницы. я так понимаю, что нужно использовать кэш- memory cache device. мне нужен пример работы с ним. а еще понять чем отличается один кэш от другого (memory cache device и disk cache device), когда использовать stream based и no stream baset. описание некоторых интерфейсов я нашла, но когда какую функцию/ интерфейс использовать мне пока не понятно.. Если работали с кэшем объясните мне, пож-та, принцип работы самого кэша и работы с ним. может пример какой есть?

Скажите возможно ли из расширения вызывать метод из JS, который находится на конкретной странице?

Naozumi пишет

Скажите возможно ли из расширения вызывать метод из JS, который находится на конкретной странице?

Возможно. Вставьте скрипт (<srcipt>...</script>) в страницу, он сразу исполнится.

Elexander
Я так понимаю через createElement и innerHTML? Почему-то не выходит.

Naozumi пишет

Elexander
Я так понимаю через createElement и innerHTML? Почему-то не выходит.

Выделить код

Код:

var script = "<script>alert('');</script>";
var range = document.createRange();
range.selectNode(document.getElementsByTagName("div").item(0));
var documentFragment = range.createContextualFragment(script);
document.body.appendChild(documentFragment);

Elexander
Спасибо.
Есть еще вопрос, как вставить в документ (cp1251) строку в utf8, полученную посредством XMLHttpRequest?
В Firefox есть какие-то средства перекодировки?

Ребят, помогите найти спецификации и технические требования к компонентам расширений. Может я не там ищу, но в центре разработчика https://developer.mozilla.org/en-US/Add-ons не нашел такой инфы

Например требования к иконке (формат, размер, может ли меняться в зависимости от действия, содержать анимацию).
Какие ограничения, что плагину запрещено делать а что разрешено.

Сейчас вот надо ставить заказ дизайнеру для разработки дизайна, а я даже требования не могу сформулировать :(

А скажите пожалуйста!
Зачем нужны так называемые "расширения"?
Почему нельзя просто писать программы JavaScript?
Мне нужно просто написать одну программку, которая будет работать с содержимым веб-страниц (искать в тексте определенные фразы и сохранять их на диск) и я в замешательстве: на чем писать?

Скажите пожалуйста: какие преимущества оформления программы именно как расширения Firefox, а не просто JS-скрипта?

Доктор ТуамОсес пишет

Зачем нужны так называемые "расширения"?

Затем , чтобы те кто ваабче_нивзубногой в программировании и в JS в частности, могли поставить расширение и заиметь полезную плюшку.

Доктор ТуамОсес пишет

на чем писать?

CustomButtoms Готовые кнопки для Custom Buttons | Форум Mozilla Россия
scratch_one-s_head.gif

jars
Я не совсем точно выразился.
Я имел виду зачем писать приложения именно в формате расширения?
Почему нельзя сразу на JS?

кто ваабче_нивзубногой в программировании
Это не ко мне.
У меня в программировании большой опыт.
Просто я вебом не занимался

Ну чегож нипанятна-то :)  Расширение - это законченный "продукт". Для него не нужно доп.костылей

Доктор ТуамОсес пишет

Почему нельзя сразу на JS?

типа GreaseMonkey и др. подобных ибо сам бравзер не желает подключать юзерскрипты, нужна_прокладка. Упаковал в *.xpi и устанавливай сразу без танцев, а ежели еще и Restartless то вообще класс. + скорей всего у расширений есть какие-то спецфичские возможности в виде API-func недоступных из userJS, тут не знаю точно. Но для задачи "поиск текста на странице и действия с ним" подойдет любой способ - расширение, GM+JS, CB

jars
Вообще-то сам "бравзер" умеет подключать чистый javascript, если на странице выкладки выкладывать ещё и инструкцию как это сделать, то сработает.
https://github.com/firefoxForUser/esr38 … %82%D1%8B-
Аж 3 способа подключения скриптов без GreaseMonkey.

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

Доктор ТуамОсес
На чём расширения пишутся? Разве [только] на JS?
У подключаемых скриптов не везде доступ будет. Страницы — OK, а «кишки» браузера?

littleleshy
Т.е.  у аддонов больше возможностей пошерудить у юзверя на харддиске и в "кишках" самого браузера?

Доктор ТуамОсес
Да, у кода на javascript появляется доступ к дополнительным наборам функций, которыми можно сделать практически всё. Тогда как возможности javascript запускаемого на странице специально урезаны, чтобы ими не пользовались хакеры, и урезаны они с глубокой древности. Хотя вот сейчас с валом новых функций для стандартного javascript запускаемого на странице начали вылезать баги связанные с тем, что у скрипта много прав и хакеры этим пользуются. Но такие баги быстро исправляют.

Вот что может стандартный скрипт на странице https://wiki.mozilla.org/WebAPI

К тому же дополнение нужно правильно оформлять, с использованием xml, откуда берутся данные и на нём же рисуется менюшка дополнения. Но недавно Mozilla объявила о большой переделке, так что правила написания дополнений изменятся. Собираются её упростить, некоторые пишут, что Mozilla выкенет полезные функции, но Mozilla обещает, что всё будет хорошо.

lolipop пишет

К тому же дополнение нужно правильно оформлять, с использованием xml

Это, как я понимаю "МИНУС" расширений по сравнению с коддингом на чистом JS?

Доктор ТуамОсес
Это не минус, просто особенность.

А "плюсы"?
Они есть?

Доктор ТуамОсес
Уже же ответили уже.

А какие IDE и тулзы для разработки расширений посоветуете?

Привет. Я не занимался веб разработкой, только системщина и МК. Так что сильно не пинайте)) Инфы по разработке расширений как-то мало и она очень не полная. Так вот, наверно глупые вопросы, но все же. Смотрю исходники, практикуюсь, собираю пакеты и пр. Все круто! Но, имею такой код::

Выделить код

Код:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://helloworld/skin/overlay.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://helloworld/locale/overlay.dtd">
<overlay id="helloworld-overlay"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <!-- main element of overlay -->
  
  <script src="overlay.js"/>
  
  <menupopup id="menu_ToolsPopup">
    <menuitem id="helloworld-hello" label="&helloworld;"
        oncommand="alert(2);"/>
  </menupopup> 
  
  <toolbarpalette  id="BrowserToolbarPalette">
        <toolbarbutton  id="helloButton" label="&helloworld;" tooltiptext="111"
              oncommand="alert(1);"/>
  </toolbarpalette>

</overlay>

Вопрос. При каком событии выполниться это:

Выделить код

Код:

<script src="overlay.js"/>

И где этот файл сценария должен "лежать"? У меня его вообще не было :angry: Как понимаю это обычный js скрипт?

скрытый текст
будет еще много нубовских вопросов, не баньте))) Хочу познать как создаются расширения)))

Cesius
<overlay> вставит <script> внутрь <window> окна браузера (см. DOM Inspector), скрипт выполнится как в HTML, когда разбор DOM-дерева дойдет до него (то есть из скрипта будет видно только DOM выше и надо ждать события DOMContentLoaded/load).
И это обычный js скрипт, да.

Infocatcher пишет

Cesius
<overlay> вставит <script> внутрь <window> окна браузера (см. DOM Inspector), скрипт выполнится как в HTML, когда разбор DOM-дерева дойдет до него (то есть из скрипта будет видно только DOM выше и надо ждать события DOMContentLoaded/load).
И это обычный js скрипт, да.

Ок. Спасибо. Еще вопросы. Как запустить js-скрипт при нажатии на кнопку-иконку моего расширения? И скрипт будет выполняться только в пределах браузера (например, я смогу создать текстовый файл на диске в выбранном месте? Ну или хотя бы подготовить файл для загрузки) ?

Вообще задача моего будущего расширения такова:

  • Юзер нажимает на кнопку находясь на нужноем ему странице
  • Расширение парсит необходимую инфу
  • Далее сохраняет инфу в текстовый файл
Cesius пишет

Как запустить js-скрипт при нажатии на кнопку-иконку моего расширения?

В указанном примере примерно так:
в overlay.js

Выделить код

Код:

function xxxDoSomething() { // Все глобальные переменные видны другим расширениям, нужно какое-нибудь уникальное имя
    alert(1);
}

в *.xul изменить для <toolbarbutton>

Выделить код

Код:

oncommand="xxxDoSomething();"
Cesius пишет

И скрипт будет выполняться только в пределах браузера (например, я смогу создать текстовый файл на диске в выбранном месте?

Можно работать с файлами:
https://developer.mozilla.org/en-US/Add … s/File_I_O
https://developer.mozilla.org/en-US/doc … ain_thread

По поводу доступа к данным страниц грядет мультипроцессный режим... :sick:
https://developer.mozilla.org/en-US/Add … ss_Firefox
https://developer.mozilla.org/en-US/Fir … d_lifetime

Почитал вот это: https://forum.mozilla-russia.org/viewtopic.php?id=44234
Пытался использовать:

Выделить код

Код:

alert(document.documentElement.innerHTML);

Но получил что-то что повергло меня! Скрин прилагаю:

скрытый текст
Snimokekranaiz2016-02-2900-29-16.1456676982.png

Что не так? Как отлаживать код?
На данном этапе моей разработки, мне надо просто получить код страницы.

UpDate...
Так тоже не получаеться :(

Выделить код

Код:

<script>
function showHello(){
var d = document.load("http://dzeveloper.blogspot.ru/");
alert(d.innerHTML);
}
</script>

Прошу помощи, вопрос по прежнему открыт :(

Cesius пишет

Но получил что-то

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

Выделить код

Код:

alert(window.content.document.documentElement.innerHTML);
turbot пишет
Cesius пишет

Но получил что-то

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

Выделить код

Код:

alert(window.content.document.documentElement.innerHTML);

Ооо! Спасибо тебе! Это реально круто! Выручил! Теперь работает!

вставляю на обычном сайте ссылку с адресом chrome://blabla/content/page.html
если щелкнуть по этой ссылке, то page.html не открывается, в консоли ругань, что нельзя, security и всетакое.
как обойти это ограничение? мне нужно, чтобы page.html имело права расширения.
в blink есть web_accessible_resources, а в firefox я ничего не нашел.

CoolCmd
Можно попробовать https://developer.mozilla.org/en-US/doc … accessible
Хотя, возможно, ограничения распространяются на весь протокол целиком, тогда если только свой протокол реализовать и потом поиграть с флагами... Но это, конечно, сложно.

Я так понимаю старое API исчезнет? Сформировано ли новое API и можно ли его уже учить, чтобы потом не пришлось переучивать?

Infocatcher contentaccessible пробовал, не помогает.
протокол попробовал, работает. но нужно ковыряется, чтобы заработал в e10s. боже, какой геморрой этот xpcom...

Infocatcher, ты пробовал в restartless расширении использовать модули из sdk (нужно content script загрузить)? здесь пишут что можно, то чета я сомневаюсь, что все это барахло само выгрузится после отключения расширения.

sufakan у мозилы 100500 api и все недоделаны (как минимум для e10s) или недокументированы. ад.

CoolCmd
Меня интересует тот, который они копируют у Chrome. Я так понимаю на нём они надолго решили остаться. Он относительно готов для нормального использования?

sufakan
вроде в 48 (начало августа) планировали выкатить. но могут и отложить. здесь то что уже работает.
можно в firefox de щупать, он как раз 48.

CoolCmd пишет

протокол попробовал, работает. но нужно ковыряется, чтобы заработал в e10s. боже, какой геморрой этот xpcom...

Угу, нужен process script для регистрации.

CoolCmd пишет

Infocatcher, ты пробовал в restartless расширении использовать модули из sdk (нужно content script загрузить)? здесь пишут что можно, то чета я сомневаюсь, что все это барахло само выгрузится после отключения расширения.

SDK не применял, совсем. А сейчас уже и боязно, удалят еще нафиг. :D

Infocatcher пишет

А сейчас уже и боязно, удалят еще нафиг.

вроде есть планы грохнуть xpcom в конце 2017. так что еще не известно кто кого переживет. :)

Я начинающий программист. Стоит задача разработать расширение, которое будет построчно сверять URL из адресной строки с URL из БД/файла. Если такой URL есть - происходит одно событие, иначе - другое.
В связи с этим возник вопрос, как лучше это реализовать с помощью WebExtensions. Можно ли хранить такую БД/файл в папке с расширением и к нему обращаться? Или можно все URL занести в SQLite и к ним обращаться? Или же вообще лучше обращаться к удаленному серверу с запросом на сверку?

Я уже достаточно почитал о WebExtensions. Но чтобы уж точно не ошибиться задам вопрос.

Получается, что в WebExtensions скрипты content_scripts имеют те же ограничения, что и обычные скрипты на странице? То есть я не смогу отправить cross domain запрос в обход политики сайта?
И выходит, чтобы отправить такой запрос мне нужно написать 2 скрипта:
1. background скрипт с доступом к API браузера и повышенными привелегиями, но не имеющий доступа к обычным страницам. Он отправляет message при нажатии в content_scripts
2. content_scripts принимает сообщение. Вытаскивает данные из страницы и обрабатывает их.
3. content_scripts отправляет данные через message в background скрипт.
4. background имеет больше прав, он берёт полученные данные. Дополняет или меняет их через запрещенные в content_scripts функции. Выполняет кросс доменный запрос.
5. background отсылает данные назад в content_scripts. Потому что обработка данных требует промежуточных результатов, которые может дать только background со своими привелегиями. И в обработке учавствуют данные со страницы, которые может дать только content_scripts
6. content_scripts принимает вторую порцию данных, обрабатывает их и снова отправляет в background.
7. И так пока всё не обработается.

Другого способа кроме этой чехарды с сообщениями нет?

Такая проблема.
1. Есть элемент с img в base64
2. Беру её через как строку outerHTML
3. После вставки оказывается там ссылка <img src="..." вместо base64

В чем дело кто знает?