зеркало из https://github.com/mozilla/pjs.git
Bug 394522: architecture patch for SeaMonkey pref panes to use <preferences>;
r=Callek, sr=Neil
This commit is contained in:
Родитель
6b7772ddde
Коммит
442da8c4ba
|
@ -392,7 +392,8 @@
|
|||
<menuitem id="textfieldDirection-swap" hidden="true"/>
|
||||
|
||||
<menuseparator id="menu_PrefsSeparator"/>
|
||||
<menuitem id="menu_preferences" oncommand="goPreferences('navigator', 'chrome://communicator/content/pref/pref-navigator.xul', 'navigator')"/>
|
||||
<menuitem id="menu_preferences" oncommand="goPreferences('navigator_pane')"/>
|
||||
<menuitem label="(Legacy Prefwindow...)" oncommand="goPreferences('navigator', 'chrome://communicator/content/pref/pref-navigator.xul', 'navigator')"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
|
|
|
@ -188,7 +188,8 @@ function openPreferences()
|
|||
if (win)
|
||||
win.focus();
|
||||
else
|
||||
openWindow(null, "chrome://communicator/content/pref/pref.xul", "chrome,titlebar,dialog=no", "");
|
||||
openWindow(null, "chrome://communicator/content/pref/preferences.xul",
|
||||
"chrome,titlebar,dialog=no,resizable", "");
|
||||
}
|
||||
|
||||
function getMostRecentWindow(aType)
|
||||
|
|
|
@ -60,6 +60,22 @@
|
|||
navigation tree's top level. <treeitem>s can be nested as needed, but
|
||||
<treeitem>s without a related <prefpane> will be hidden.
|
||||
|
||||
Furthermore, if the <prefwindow> has attribute "autopanes" set to "true",
|
||||
non-existing <prefpane>s will be generated automatically from certain
|
||||
attributes of the <treeitem>:
|
||||
- "url" must contain the <prefpane>'s url
|
||||
- "prefpane" should contain the <prefpane>'s desired id,
|
||||
otherwise its url will be used as id
|
||||
- "helpTopic" may contain an index into SeaMonkey's help
|
||||
|
||||
Unlike in XPFE, where preferences panels were loaded into a separate
|
||||
iframe, <prefpane>s are an integral part of the <prefwindow> document,
|
||||
by virtue of loadOverlay. Hence <script>s will be loaded into the
|
||||
<prefwindow> scope and possibly clash. To avoid this, <prefpane>s should
|
||||
specify a "script" attribute with a whitespace delimited list of scripts
|
||||
to load into the <prefpane>'s context. The subscriptloader will take care
|
||||
of any internal scoping, so no this.* fest is necessary inside the script.
|
||||
|
||||
<prefwindow> users who want to share the very same file between SeaMonkey
|
||||
and other toolkit apps should hide the <tree> (set <tree>.hidden=true);
|
||||
this binding will then unhide the <tree> if necessary, ie more than just
|
||||
|
@ -67,7 +83,8 @@
|
|||
Also, the <tree> will get the class "prefnavtree" added, so that it may be
|
||||
prestyled by the SeaMonkey themes.
|
||||
Setting <prefwindow xpfe="false"> will enforce the application of just the
|
||||
basic toolkit <prefwindow> even in SeaMonkey.
|
||||
basic toolkit <prefwindow> even in SeaMonkey. The same "xpfe" attribute
|
||||
exists for <prefpane>, too.
|
||||
-->
|
||||
|
||||
<!DOCTYPE bindings [
|
||||
|
@ -83,9 +100,12 @@
|
|||
|
||||
<binding id="prefwindow"
|
||||
extends="chrome://global/content/bindings/preferences.xml#prefwindow">
|
||||
<resources>
|
||||
<stylesheet src="chrome://communicator/skin/preferences.css"/>
|
||||
</resources>
|
||||
|
||||
<!-- The only difference between the following <content> and its toolkit
|
||||
ancestor is the 'navTrees' <vbox> before the 'paneDeck'! -->
|
||||
ancestor is the help button and the 'navTrees' <vbox> before the 'paneDeck'! -->
|
||||
<content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
|
||||
closebuttonlabel="&preferencesCloseButton.label;"
|
||||
closebuttonaccesskey="&preferencesCloseButton.accesskey;"
|
||||
|
@ -135,7 +155,6 @@
|
|||
</content>
|
||||
|
||||
<implementation>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
// grab the first child tree and try to tie it to the prefpanes
|
||||
|
@ -162,34 +181,23 @@
|
|||
if (aTreeElement.parentNode != this)
|
||||
return;
|
||||
|
||||
// don't bother with a navigation tree if we only have one prefpane
|
||||
aTreeElement.hidden = (this.preferencePanes.length < 2);
|
||||
if (aTreeElement.hidden)
|
||||
return;
|
||||
this._navigationTree = aTreeElement;
|
||||
|
||||
// add the class "prefnavtree", so that themes can set defaults
|
||||
this._navigationTree.className += ' prefnavtree';
|
||||
|
||||
// tie the <treeitem>s to the corresponding <prefpane>s
|
||||
var treeitems = this._navigationTree.getElementsByTagName('treeitem');
|
||||
for (var i = 0; i < treeitems.length; ++i)
|
||||
// autogenerate <prefpane>s from <treecell>.url if requested
|
||||
var autopanes = (this.getAttribute('autopanes') == 'true');
|
||||
if (!autopanes)
|
||||
{
|
||||
var node = treeitems[i];
|
||||
var pane = document.getElementById(node.getAttribute('prefpane'));
|
||||
node.prefpane = pane;
|
||||
if (pane)
|
||||
pane.preftreeitem = node;
|
||||
// hide unused treeitems
|
||||
node.hidden = !pane;
|
||||
// without autopanes, we can return early: don't bother
|
||||
// with a navigation tree if we only have one prefpane
|
||||
aTreeElement.hidden = (this.preferencePanes.length < 2);
|
||||
if (aTreeElement.hidden)
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure that we have a tree body (before checking for columns)
|
||||
if (!this._navigationTree.body)
|
||||
this._navigationTree.appendChild(document.createElement('treechildren'));
|
||||
// ensure that we have a tree body
|
||||
if (!aTreeElement.getElementsByTagName('treechildren').length)
|
||||
aTreeElement.appendChild(document.createElement('treechildren'));
|
||||
|
||||
// ensure that we have a tree column
|
||||
if (!this._navigationTree.columns.count)
|
||||
if (!aTreeElement.getElementsByTagName('treecol').length)
|
||||
{
|
||||
var navcols = document.createElement('treecols');
|
||||
var navcol = document.createElement('treecol');
|
||||
|
@ -198,36 +206,134 @@
|
|||
navcol.setAttribute('flex', 1);
|
||||
navcol.setAttribute('hideheader', true);
|
||||
navcols.appendChild(navcol);
|
||||
this._navigationTree.appendChild(navcols);
|
||||
this._navigationTree.setAttribute('hidecolumnpicker', true);
|
||||
aTreeElement.appendChild(navcols);
|
||||
aTreeElement.setAttribute('hidecolumnpicker', true);
|
||||
}
|
||||
|
||||
// add the class "prefnavtree", so that themes can set defaults
|
||||
aTreeElement.className += ' prefnavtree';
|
||||
|
||||
// Do some magic with the treeitem ingredient:
|
||||
// - if it has a label attribute but no treerow child,
|
||||
// generate a treerow with a treecell child with that label
|
||||
// - if it has a prefpane attribute, tie it to that panel
|
||||
// - if still no panel found and a url attribute is present,
|
||||
// autogenerate the prefpane and connect to it
|
||||
var treeitems = aTreeElement.getElementsByTagName('treeitem');
|
||||
for (var i = 0; i < treeitems.length; ++i)
|
||||
{
|
||||
var node = treeitems[i];
|
||||
var label = node.getAttribute('label');
|
||||
if (label)
|
||||
{
|
||||
// autocreate the treecell?
|
||||
var row = node.firstChild;
|
||||
while (row && row.nodeName != 'treerow')
|
||||
row = row.nextSibling;
|
||||
if (!row)
|
||||
{
|
||||
var itemrow = document.createElement('treerow');
|
||||
var itemcell = document.createElement('treecell');
|
||||
itemcell.setAttribute('label', label);
|
||||
itemrow.appendChild(itemcell);
|
||||
node.appendChild(itemrow);
|
||||
}
|
||||
}
|
||||
var paneID = node.getAttribute('prefpane');
|
||||
var pane = paneID && document.getElementById(paneID);
|
||||
if (!pane && autopanes)
|
||||
{
|
||||
// if we have a url, create a <prefpane> for it
|
||||
var paneURL = node.getAttribute('url');
|
||||
if (paneURL)
|
||||
{
|
||||
// reuse paneID if present, else use the url as id
|
||||
pane = document.createElement('prefpane');
|
||||
pane.setAttribute('id', paneID || paneURL);
|
||||
pane.setAttribute('src', paneURL);
|
||||
pane.setAttribute('label', label || paneID || paneURL);
|
||||
var helpTopic = node.getAttribute('helpTopic');
|
||||
if (helpTopic)
|
||||
{
|
||||
pane.setAttribute('helpURI', 'chrome://communicator/locale/help/suitehelp.rdf');
|
||||
pane.setAttribute('helpTopic', helpTopic);
|
||||
}
|
||||
// add pane to prefwindow
|
||||
this.appendChild(pane);
|
||||
}
|
||||
}
|
||||
node.prefpane = pane;
|
||||
if (pane)
|
||||
pane.preftreeitem = node;
|
||||
// hide unused treeitems
|
||||
node.hidden = !pane;
|
||||
}
|
||||
|
||||
// now that the number of <prefpane>s is known, try to return early:
|
||||
// don't bother with a navigation tree if we only have one prefpane
|
||||
aTreeElement.hidden = (this.preferencePanes.length < 2);
|
||||
if (aTreeElement.hidden)
|
||||
return;
|
||||
this._navigationTree = aTreeElement;
|
||||
|
||||
// append any still unreferenced <prefpane>s to the tree's top level
|
||||
for (var i = 0; i < this.preferencePanes.length; ++i)
|
||||
for (var j = 0; j < this.preferencePanes.length; ++j)
|
||||
{
|
||||
// toolkit believes in fancy pane resizing - we don't
|
||||
var pane = this.preferencePanes[i];
|
||||
pane.setAttribute('flex', 1);
|
||||
if (!("preftreeitem" in pane))
|
||||
var lostpane = this.preferencePanes[j];
|
||||
lostpane.setAttribute('flex', 1);
|
||||
|
||||
if (!("preftreeitem" in lostpane))
|
||||
{
|
||||
var treebody = this._navigationTree
|
||||
.getElementsByTagName('treechildren')[0];
|
||||
var treeitem = document.createElement('treeitem');
|
||||
var treerow = document.createElement('treerow');
|
||||
var treecell = document.createElement('treecell');
|
||||
var label = pane.getAttribute('label');
|
||||
var label = lostpane.getAttribute('label');
|
||||
if (!label)
|
||||
label = pane.getAttribute('id');
|
||||
label = lostpane.getAttribute('id');
|
||||
treecell.setAttribute('label', label);
|
||||
treerow.appendChild(treecell);
|
||||
treeitem.appendChild(treerow);
|
||||
this._navigationTree.body.appendChild(treeitem);
|
||||
treeitem.prefpane = pane;
|
||||
pane.preftreeitem = treeitem;
|
||||
treebody.appendChild(treeitem);
|
||||
treeitem.prefpane = lostpane;
|
||||
lostpane.preftreeitem = treeitem;
|
||||
}
|
||||
}
|
||||
|
||||
// some of the toolkit base binding's select events fire before we
|
||||
// get here, so we may need to sync the tree manually now
|
||||
if (this.currentPane && this.currentPane.loaded)
|
||||
// Some of the toolkit base binding's select events fire before we
|
||||
// get here, so we may need to sync the tree manually now.
|
||||
// Furthermore, if the panel to load initially has just been created,
|
||||
// we need to load it first.
|
||||
// (This is a loose copy from the toolkit ctor.)
|
||||
if (!this.currentPane)
|
||||
{
|
||||
var lastPane = this.lastSelected &&
|
||||
document.getElementById(this.lastSelected);
|
||||
if (!lastPane)
|
||||
this.lastSelected = "";
|
||||
var paneToLoad = null;
|
||||
if ("arguments" in window && window.arguments[0])
|
||||
{
|
||||
var initialPane = document.getElementById(window.arguments[0]);
|
||||
if (initialPane && initialPane.nodeName == "prefpane")
|
||||
{
|
||||
paneToLoad = initialPane;
|
||||
this.lastSelected = paneToLoad.id;
|
||||
}
|
||||
}
|
||||
else if (lastPane)
|
||||
paneToLoad = lastPane;
|
||||
else if (this.preferencePanes.length > 0)
|
||||
paneToLoad = this.preferencePanes[0];
|
||||
if (paneToLoad)
|
||||
{
|
||||
this.showPane(paneToLoad);
|
||||
this.currentPane = paneToLoad;
|
||||
}
|
||||
}
|
||||
if (this.currentPane)
|
||||
this.syncTreeWithPane(this.currentPane);
|
||||
]]>
|
||||
</body>
|
||||
|
@ -265,9 +371,22 @@
|
|||
if ('prefpane' in treeitem)
|
||||
{
|
||||
pane = treeitem.prefpane;
|
||||
this.showPane(pane);
|
||||
if (pane && (this.currentPane != pane))
|
||||
{
|
||||
try
|
||||
{
|
||||
this.showPane(pane); // may need to load it first
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
dump('***** broken prefpane: ' + pane + '\n' + e + '\n');
|
||||
pane = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// don't show broken panels
|
||||
this._paneDeck.hidden = (pane == null);
|
||||
this.setPaneTitle(pane);
|
||||
]]>
|
||||
</body>
|
||||
|
@ -299,11 +418,9 @@
|
|||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
|
||||
<handler event="select">
|
||||
<![CDATA[
|
||||
// navigation tree select or deck change?
|
||||
|
@ -328,8 +445,60 @@
|
|||
this.syncTreeWithPane(event.originalTarget);
|
||||
]]>
|
||||
</handler>
|
||||
|
||||
</handlers>
|
||||
|
||||
</binding>
|
||||
|
||||
<binding id="prefpane"
|
||||
extends="chrome://global/content/bindings/preferences.xml#prefpane">
|
||||
<handlers>
|
||||
<handler event="paneload">
|
||||
<![CDATA[
|
||||
// Since all <prefpane>s now share the same global document, their
|
||||
// <script>s might clash. Thus we expect the "script" attribute to
|
||||
// contain a whitespace delimited list of script files to be loaded
|
||||
// into the <prefpane>'s context.
|
||||
var subScriptLoader = null;
|
||||
try
|
||||
{
|
||||
subScriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
var msg = 'prefpane.paneload: no mozIJSSubScriptLoader!\n' + e;
|
||||
Components.utils.reportError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// list of scripts to load
|
||||
var scripts = this.getAttribute('script').match(/\S+/g);
|
||||
if (!scripts)
|
||||
return;
|
||||
var count = scripts.length;
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var script = scripts[i];
|
||||
if (script)
|
||||
{
|
||||
try
|
||||
{
|
||||
subScriptLoader.loadSubScript(script, this);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
var msg = 'prefpane.paneload: loadSubScript("'
|
||||
+ script + '") failed:\n' + e;
|
||||
Components.utils.reportError(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a Startup method, call it
|
||||
if ('Startup' in this)
|
||||
this.Startup();
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
||||
|
|
|
@ -68,6 +68,10 @@ prefwindow[xpfe="false"] {
|
|||
-moz-binding: url("chrome://global/content/bindings/preferences.xml#prefwindow");
|
||||
}
|
||||
|
||||
prefpane[xpfe="false"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/preferences.xml#prefpane");
|
||||
}
|
||||
|
||||
/******* SeaMonkey XPFE *******/
|
||||
/* These bindings reflect SeaMonkey XPFE, modulo new toolkit features. */
|
||||
toolbox {
|
||||
|
@ -89,3 +93,7 @@ menubar {
|
|||
prefwindow {
|
||||
-moz-binding: url("chrome://communicator/content/bindings/prefwindow.xml#prefwindow");
|
||||
}
|
||||
|
||||
prefpane {
|
||||
-moz-binding: url("chrome://communicator/content/bindings/prefwindow.xml#prefpane");
|
||||
}
|
||||
|
|
|
@ -136,16 +136,22 @@ comm.jar:
|
|||
content/communicator/permissions/permissionsNavigatorOverlay.xul (permissions/permissionsNavigatorOverlay.xul)
|
||||
content/communicator/permissions/permissionsOverlay.js (permissions/permissionsOverlay.js)
|
||||
content/communicator/permissions/treeUtils.js (permissions/treeUtils.js)
|
||||
# preferences.xul will replace all the files marked below, once we have migrated all our pref panels
|
||||
# to toolkit style - begone, foul spirits of the past!
|
||||
content/communicator/pref/preferences.xul (pref/preferences.xul)
|
||||
# files deprecated by preferences.xul: begin
|
||||
content/communicator/pref/nsPrefWindow.js (pref/nsPrefWindow.js)
|
||||
content/communicator/pref/nsWidgetStateManager.js (/xpfe/global/resources/content/nsWidgetStateManager.js)
|
||||
content/communicator/pref/overrideHandler.js (pref/overrideHandler.js)
|
||||
content/communicator/pref/pref.xul (pref/pref.xul)
|
||||
content/communicator/pref/preftree.xul (pref/preftree.xul)
|
||||
content/communicator/pref/pref-help.js (pref/pref-help.js)
|
||||
# files deprecated by preferences.xul: end
|
||||
content/communicator/pref/pref-advanced.xul (pref/pref-advanced.xul)
|
||||
content/communicator/pref/pref-appearance.xul (pref/pref-appearance.xul)
|
||||
content/communicator/pref/pref-applications.xul (pref/pref-applications.xul)
|
||||
content/communicator/pref/pref-applications.js (pref/pref-applications.js)
|
||||
content/communicator/pref/pref-applications-edit.xul (pref/pref-applications-edit.xul)
|
||||
content/communicator/pref/overrideHandler.js (pref/overrideHandler.js)
|
||||
content/communicator/pref/pref-cache.js (pref/pref-cache.js)
|
||||
content/communicator/pref/pref-cache.xul (pref/pref-cache.xul)
|
||||
content/communicator/pref/pref-charset.js (pref/pref-charset.js)
|
||||
|
@ -156,7 +162,6 @@ comm.jar:
|
|||
content/communicator/pref/pref-download.xul (pref/pref-download.xul)
|
||||
content/communicator/pref/pref-fonts.js (pref/pref-fonts.js)
|
||||
content/communicator/pref/pref-fonts.xul (pref/pref-fonts.xul)
|
||||
content/communicator/pref/pref-help.js (pref/pref-help.js)
|
||||
content/communicator/pref/pref-history.xul (pref/pref-history.xul)
|
||||
content/communicator/pref/pref-http.js (pref/pref-http.js)
|
||||
content/communicator/pref/pref-http.xul (pref/pref-http.xul)
|
||||
|
|
|
@ -237,31 +237,32 @@ function getBrowserURL() {
|
|||
|
||||
function goPreferences(containerID, paneURL, itemID)
|
||||
{
|
||||
var resizable;
|
||||
var pref = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
try {
|
||||
// We are resizable ONLY if in box debugging mode, because in
|
||||
// this special debug mode it is often impossible to see the
|
||||
// content of the debug panel in order to disable debug mode.
|
||||
resizable = pref.getBoolPref("xul.debug.box");
|
||||
}
|
||||
catch (e) {
|
||||
resizable = false;
|
||||
}
|
||||
|
||||
//check for an existing pref window and focus it; it's not application modal
|
||||
const kWindowMediatorContractID = "@mozilla.org/appshell/window-mediator;1";
|
||||
const kWindowMediatorIID = Components.interfaces.nsIWindowMediator;
|
||||
const kWindowMediator = Components.classes[kWindowMediatorContractID].getService(kWindowMediatorIID);
|
||||
var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:preferences");
|
||||
const kWindowMediator = Components.classes[kWindowMediatorContractID]
|
||||
.getService(kWindowMediatorIID);
|
||||
|
||||
// Bug 394522:
|
||||
// Until all our pref panels have been migrated to the toolkit way,
|
||||
// we need to distinguish between old and new methods of opening a specific
|
||||
// panel -> prefwindow only needs the prefpane id in window.arguments[0], so
|
||||
// this function here only needs to get one param passed in the future
|
||||
// -> we assume that a new style style pref panel is requested if only one
|
||||
// (the first) parameter is passed.
|
||||
var legacyPrefWindow = paneURL || itemID;
|
||||
var prefWindowFragment = legacyPrefWindow ? "pref" : "preferences";
|
||||
var lastPrefWindow = kWindowMediator.getMostRecentWindow("mozilla:" + prefWindowFragment);
|
||||
if (lastPrefWindow)
|
||||
lastPrefWindow.focus();
|
||||
else {
|
||||
var resizability = resizable ? "yes" : "no";
|
||||
var features = "chrome,titlebar,resizable=" + resizability;
|
||||
openDialog("chrome://communicator/content/pref/pref.xul","PrefWindow",
|
||||
features, paneURL, containerID, itemID);
|
||||
if (!legacyPrefWindow) {
|
||||
paneURL = containerID;
|
||||
containerID = null;
|
||||
}
|
||||
openDialog("chrome://communicator/content/pref/" + prefWindowFragment + ".xul",
|
||||
"PrefWindow", "chrome,titlebar,dialog=no,resizable",
|
||||
paneURL, containerID, itemID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ classic.jar:
|
|||
skin/classic/communicator/communicator.css (communicator/communicator.css)
|
||||
skin/classic/communicator/communicatorBindings.xml (communicator/communicatorBindings.xml)
|
||||
skin/classic/communicator/helpOverlay.css (communicator/helpOverlay.css)
|
||||
skin/classic/communicator/preferences.css (communicator/preferences.css)
|
||||
skin/classic/communicator/prefpanels.css (communicator/prefpanels.css)
|
||||
skin/classic/communicator/smileys.css (communicator/smileys.css)
|
||||
skin/classic/communicator/bookmarks/bookmark-folder-button.gif (communicator/bookmarks/bookmark-folder-button.gif)
|
||||
|
|
|
@ -7,6 +7,7 @@ modern.jar:
|
|||
% skin navigator modern/1.0 %skin/modern/navigator/
|
||||
skin/modern/communicator/brand.css (communicator/brand.css)
|
||||
skin/modern/communicator/prefpanels.css (communicator/prefpanels.css)
|
||||
skin/modern/communicator/preferences.css (communicator/preferences.css)
|
||||
skin/modern/communicator/tasksOverlay.css (communicator/tasksOverlay.css)
|
||||
skin/modern/communicator/button.css (communicator/button.css)
|
||||
skin/modern/communicator/toolbar.css (communicator/toolbar.css)
|
||||
|
|
Загрузка…
Ссылка в новой задаче