зеркало из https://github.com/mozilla/pjs.git
Links toolbar. Bug 87428. r=bzbarsky, sr=hewitt. At last!
This commit is contained in:
Родитель
0d687d996b
Коммит
90ddf01f73
|
@ -0,0 +1,89 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Eric Hodel's <drbrain@segment7.net> code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Eric Hodel.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Hoess <choess@force.stwing.upenn.edu>
|
||||
* Tim Taylor <tim@tool-man.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* LanguageDictionary is a Singleton for looking up a language name
|
||||
* given its language code.
|
||||
*/
|
||||
function LanguageDictionary() {
|
||||
this.dictionary = null;
|
||||
}
|
||||
|
||||
LanguageDictionary.prototype = {
|
||||
lookupLanguageName: function(languageCode)
|
||||
{
|
||||
if (this.getDictionary()[languageCode])
|
||||
return this.getDictionary()[languageCode];
|
||||
else
|
||||
// XXX: handle non-standard language code's per
|
||||
// hixie's spec (see bug 2800)
|
||||
return "";
|
||||
},
|
||||
|
||||
getDictionary: function()
|
||||
{
|
||||
if (!this.dictionary)
|
||||
this.dictionary = LanguageDictionary.createDictionary();
|
||||
|
||||
return this.dictionary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LanguageDictionary.createDictionary = function()
|
||||
{
|
||||
var dictionary = new Array();
|
||||
|
||||
var e = LanguageDictionary.getLanguageNames().getSimpleEnumeration();
|
||||
while (e.hasMoreElements()) {
|
||||
var property = e.getNext();
|
||||
property = property.QueryInterface(
|
||||
Components.interfaces.nsIPropertyElement);
|
||||
dictionary[property.getKey()] = property.getValue();
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
LanguageDictionary.getLanguageNames = function()
|
||||
{
|
||||
return srGetStrBundle(
|
||||
"chrome://global/locale/languageNames.properties");
|
||||
}
|
||||
|
||||
const languageDictionary = new LanguageDictionary();
|
|
@ -0,0 +1,329 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Eric Hodel's <drbrain@segment7.net> code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Eric Hodel.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Hoess <choess@force.stwing.upenn.edu>
|
||||
* Tim Taylor <tim@tool-man.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* LinkToolbarHandler is a Singleton that displays LINK elements
|
||||
* and nodeLists of LINK elements in the Link Toolbar. It
|
||||
* associates the LINK with a corresponding LinkToolbarItem based
|
||||
* on it's REL attribute and the toolbar item's ID attribute.
|
||||
* LinkToolbarHandler is also a Factory and will create
|
||||
* LinkToolbarItems as necessary.
|
||||
*/
|
||||
function LinkToolbarHandler()
|
||||
{
|
||||
this.items = new Array();
|
||||
}
|
||||
|
||||
LinkToolbarHandler.prototype.handleLinks =
|
||||
function(nodeList)
|
||||
{
|
||||
if (!nodeList) return;
|
||||
|
||||
var len = nodeList.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
// optimization: weed out useless links here to avoid
|
||||
// the function call. More in depth checks are done
|
||||
// in this.handle
|
||||
var node = nodeList.item(i);
|
||||
if (node && (node.rel || node.rev) && node.href)
|
||||
this.handle(node);
|
||||
}
|
||||
}
|
||||
|
||||
LinkToolbarHandler.prototype.handle =
|
||||
function(element)
|
||||
{
|
||||
// XXX: if you're going to re-enable handling of anchor elements,
|
||||
// you'll want to change this to AnchorElementDecorator
|
||||
var linkElement = new LinkElementDecorator(element);
|
||||
|
||||
if (linkElement.isIgnored()) return;
|
||||
|
||||
var relAttributes = linkElement.rel.split(" ");
|
||||
for (var i = 0; i < relAttributes.length; i++) {
|
||||
var linkType = LinkToolbarHandler.getLinkType(relAttributes[i]);
|
||||
this.getItemForLinkType(linkType).displayLink(linkElement);
|
||||
}
|
||||
}
|
||||
|
||||
LinkToolbarHandler.getLinkType =
|
||||
function(relAttribute)
|
||||
{
|
||||
switch (relAttribute.toLowerCase()) {
|
||||
case "home":
|
||||
case "start":
|
||||
case "top":
|
||||
case "origin":
|
||||
return "top";
|
||||
|
||||
case "up":
|
||||
case "parent":
|
||||
return "up";
|
||||
|
||||
case "begin":
|
||||
case "first":
|
||||
return "first";
|
||||
|
||||
case "next":
|
||||
case "child":
|
||||
return "next";
|
||||
|
||||
case "prev":
|
||||
case "previous":
|
||||
return "prev";
|
||||
|
||||
case "end":
|
||||
case "last":
|
||||
return "last";
|
||||
|
||||
case "author":
|
||||
case "made":
|
||||
return "author";
|
||||
|
||||
case "contents":
|
||||
case "toc":
|
||||
return "toc";
|
||||
|
||||
default:
|
||||
return relAttribute.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
LinkToolbarHandler.prototype.getItemForLinkType =
|
||||
function(linkType) {
|
||||
if (!this.items[linkType])
|
||||
this.items[linkType] = LinkToolbarHandler.createItemForLinkType(linkType);
|
||||
|
||||
return this.items[linkType];
|
||||
}
|
||||
|
||||
LinkToolbarHandler.createItemForLinkType =
|
||||
function(linkType)
|
||||
{
|
||||
if (!document.getElementById("link-" + linkType))
|
||||
return new LinkToolbarTransientMenu(linkType);
|
||||
|
||||
// XXX: replace switch with polymorphism
|
||||
switch(document.getElementById("link-" + linkType).localName) {
|
||||
case "toolbarbutton":
|
||||
return new LinkToolbarButton(linkType);
|
||||
|
||||
case "menuitem":
|
||||
return new LinkToolbarItem(linkType);
|
||||
|
||||
case "menu":
|
||||
return new LinkToolbarMenu(linkType);
|
||||
|
||||
default:
|
||||
return new LinkToolbarTransientMenu(linkType);
|
||||
}
|
||||
}
|
||||
|
||||
LinkToolbarHandler.prototype.clearAllItems =
|
||||
function()
|
||||
{
|
||||
for (var linkType in this.items)
|
||||
this.items[linkType].clear();
|
||||
}
|
||||
|
||||
const linkToolbarHandler = new LinkToolbarHandler();
|
||||
|
||||
|
||||
function LinkElementDecorator(element) {
|
||||
/*
|
||||
* XXX: this is an incomplete decorator, because it doesn't implement
|
||||
* the full Element interface. If you need to use a method
|
||||
* or member in the Element interface, just add it here and
|
||||
* have it delegate to this.element
|
||||
*
|
||||
* XXX: would rather add some methods to Element.prototype instead of
|
||||
* using a decorator, but Element.prototype is no longer exposed
|
||||
* since the XPCDOM landing, see bug 83433
|
||||
*/
|
||||
|
||||
if (!element) return; // skip the rest on foo.prototype = new ThisClass calls
|
||||
|
||||
this.element = element;
|
||||
|
||||
this.rel = LinkElementDecorator.convertRevMade(element.rel, element.rev);
|
||||
this.rev = element.rev;
|
||||
this.title = element.title;
|
||||
this.href = element.href;
|
||||
this.hreflang = element.hreflang;
|
||||
this.media = element.media;
|
||||
this.longTitle = null;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.isIgnored =
|
||||
function()
|
||||
{
|
||||
if (!this.rel) return true;
|
||||
if (this.isStylesheet()) return true;
|
||||
if (this.isIcon()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.isStylesheet =
|
||||
function() {
|
||||
if (LinkElementDecorator.findWord("stylesheet", this.rel.toLowerCase()))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.isIcon =
|
||||
function() {
|
||||
if (LinkElementDecorator.findWord("icon", this.rel.toLowerCase()))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LinkElementDecorator.convertRevMade =
|
||||
function(rel, rev)
|
||||
{
|
||||
if (!rel && rev && LinkElementDecorator.findWord("made", rev.toLowerCase()))
|
||||
return rev;
|
||||
else
|
||||
return rel;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.getTooltip =
|
||||
function()
|
||||
{
|
||||
return this.getLongTitle() != "" ? this.getLongTitle() : this.href;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.getLabel =
|
||||
function()
|
||||
{
|
||||
return this.getLongTitle() != "" ? this.getLongTitle() : this.rel;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.getLongTitle =
|
||||
function()
|
||||
{
|
||||
if (this.longTitle == null)
|
||||
this.longTitle = this.makeLongTitle();
|
||||
|
||||
return this.longTitle;
|
||||
}
|
||||
|
||||
LinkElementDecorator.prototype.makeLongTitle =
|
||||
function()
|
||||
{
|
||||
var prefix = "";
|
||||
|
||||
// XXX: lookup more meaningful and localized version of media,
|
||||
// i.e. media="print" becomes "Printable" or some such
|
||||
// XXX: use localized version of ":" separator
|
||||
if (this.media
|
||||
&& !LinkElementDecorator.findWord("all", this.media.toLowerCase())
|
||||
&& !LinkElementDecorator.findWord("screen", this.media.toLowerCase()))
|
||||
prefix += this.media + ": ";
|
||||
if (this.hreflang)
|
||||
prefix += languageDictionary.lookupLanguageName(this.hreflang)
|
||||
+ ": ";
|
||||
|
||||
return this.title ? prefix + this.title : prefix;
|
||||
}
|
||||
|
||||
LinkElementDecorator.findWord =
|
||||
function(word, string)
|
||||
{
|
||||
var barePattern = eval("/^" + word + "$/");
|
||||
var middlePattern = eval("/[-\\W]" + word + "[-\\W]/");
|
||||
var startPattern = eval("/^" + word + "[-\\W]/");
|
||||
var endPattern = eval("/[-\\W]" + word + "$/");
|
||||
|
||||
if (string.search(barePattern) != -1)
|
||||
return true;
|
||||
if (string.search(middlePattern) != -1)
|
||||
return true;
|
||||
if (string.search(startPattern) != -1)
|
||||
return true;
|
||||
if (string.search(endPattern) != -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function AnchorElementDecorator(element) {
|
||||
this.constructor(element);
|
||||
}
|
||||
AnchorElementDecorator.prototype = new LinkElementDecorator;
|
||||
|
||||
AnchorElementDecorator.prototype.getLongTitle =
|
||||
function()
|
||||
{
|
||||
return this.title ? this.__proto__.getLongTitle.apply(this)
|
||||
: getText(this.element);
|
||||
}
|
||||
|
||||
AnchorElementDecorator.prototype.getText =
|
||||
function(element)
|
||||
{
|
||||
return condenseWhitespace(getTextRecursive(element));
|
||||
}
|
||||
|
||||
AnchorElementDecorator.prototype.getTextRecursive =
|
||||
function(node)
|
||||
{
|
||||
var text = "";
|
||||
node.normalize();
|
||||
if (node.hasChildNodes()) {
|
||||
for (var i = 0; i < node.childNodes.length; i++) {
|
||||
if (node.childNodes.item(i).nodeType == Node.TEXT_NODE)
|
||||
text += node.childNodes.item(i).nodeValue;
|
||||
else if (node.childNodes.item(i).nodeType == Node.ELEMENT_NODE)
|
||||
text += getTextRecursive(node.childNodes.item(i));
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
AnchorElementDecorator.prototype.condenseWhitespace =
|
||||
function(text)
|
||||
{
|
||||
return text.replace(/\W*$/, "").replace(/^\W*/, "").replace(/\W+/g, " ");
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Eric Hodel's <drbrain@segment7.net> code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Eric Hodel.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Hoess <choess@force.stwing.upenn.edu>
|
||||
* Tim Taylor <tim@tool-man.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* LinkToolbarItem and its subclasses represent the buttons, menuitems,
|
||||
* and menus that handle the various link types.
|
||||
*/
|
||||
function LinkToolbarItem (linkType) {
|
||||
this.linkType = linkType;
|
||||
this.xulElementId = "link-" + linkType;
|
||||
this.xulPopupId = this.xulElementId + "-popup";
|
||||
this.parentMenuButton = null;
|
||||
|
||||
this.getXULElement = function() {
|
||||
return document.getElementById(this.xulElementId);
|
||||
}
|
||||
|
||||
this.clear = function() {
|
||||
this.disableParentMenuButton();
|
||||
this.getXULElement().setAttribute("disabled", "true");
|
||||
this.getXULElement().removeAttribute("href");
|
||||
}
|
||||
|
||||
this.displayLink = function(linkElement) {
|
||||
if (this.getXULElement().hasAttribute("href")) return false;
|
||||
|
||||
this.setItem(linkElement);
|
||||
this.enableParentMenuButton();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.setItem = function(linkElement) {
|
||||
this.getXULElement().setAttribute("href", linkElement.href);
|
||||
this.getXULElement().removeAttribute("disabled");
|
||||
}
|
||||
|
||||
this.enableParentMenuButton = function() {
|
||||
if(this.getParentMenuButton())
|
||||
this.getParentMenuButton().removeAttribute("disabled");
|
||||
}
|
||||
|
||||
this.disableParentMenuButton = function() {
|
||||
if (!this.parentMenuButton) return;
|
||||
|
||||
this.parentMenuButton.setAttribute("disabled", "true");
|
||||
this.parentMenuButton = null;
|
||||
}
|
||||
|
||||
this.getParentMenuButton = function() {
|
||||
if (!this.parentMenuButton)
|
||||
this.parentMenuButton = getParentMenuButtonRecursive(
|
||||
this.getXULElement());
|
||||
|
||||
return this.parentMenuButton;
|
||||
}
|
||||
|
||||
function getParentMenuButtonRecursive(xulElement) {
|
||||
if (!xulElement) return null;
|
||||
|
||||
if (xulElement.tagName == "toolbarbutton")
|
||||
return xulElement;
|
||||
|
||||
return getParentMenuButtonRecursive(xulElement.parentNode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function LinkToolbarButton (linkType) {
|
||||
this.constructor(linkType);
|
||||
|
||||
this.clear = function() {
|
||||
this.__proto__.clear.apply(this);
|
||||
|
||||
this.getXULElement().removeAttribute("tooltiptext");
|
||||
}
|
||||
|
||||
this.setItem = function(linkElement) {
|
||||
this.__proto__.setItem.apply(this, [linkElement]);
|
||||
|
||||
this.getXULElement().setAttribute("tooltiptext", linkElement.getTooltip());
|
||||
}
|
||||
|
||||
this.enableParentMenuButton = function() { /* do nothing */ }
|
||||
this.disableParentMenuButton = function() { /* do nothing */ }
|
||||
}
|
||||
LinkToolbarButton.prototype = new LinkToolbarItem;
|
||||
|
||||
|
||||
function LinkToolbarMenu (linkType) {
|
||||
this.constructor(linkType);
|
||||
|
||||
this.knownLinks = null;
|
||||
|
||||
this.clear = function() {
|
||||
this.disableParentMenuButton();
|
||||
this.getXULElement().setAttribute("disabled", "true");
|
||||
clearPopup(this.getPopup());
|
||||
this.knownLinks = null;
|
||||
}
|
||||
|
||||
function clearPopup(popup) {
|
||||
while (popup.hasChildNodes())
|
||||
popup.removeChild(popup.lastChild);
|
||||
}
|
||||
|
||||
this.getPopup = function() {
|
||||
return document.getElementById(this.xulPopupId);
|
||||
}
|
||||
|
||||
this.displayLink = function(linkElement) {
|
||||
if (this.isAlreadyAdded(linkElement)) return false;
|
||||
|
||||
this.getKnownLinks()[linkElement.href] = true;
|
||||
this.addMenuItem(linkElement);
|
||||
this.getXULElement().removeAttribute("disabled");
|
||||
this.enableParentMenuButton();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.isAlreadyAdded = function(linkElement) {
|
||||
return this.getKnownLinks()[linkElement.href];
|
||||
}
|
||||
|
||||
this.getKnownLinks = function() {
|
||||
if (!this.knownLinks)
|
||||
this.knownLinks = new Array();
|
||||
return this.knownLinks;
|
||||
}
|
||||
|
||||
function match(first, second) {
|
||||
if (!first && !second) return true;
|
||||
if (!first || !second) return false;
|
||||
|
||||
return first == second;
|
||||
}
|
||||
|
||||
this.addMenuItem = function(linkElement) {
|
||||
this.getPopup().appendChild(this.createMenuItem(linkElement));
|
||||
}
|
||||
|
||||
this.createMenuItem = function(linkElement) {
|
||||
// XXX: clone a prototypical XUL element instead of hardcoding these
|
||||
// attributes
|
||||
var menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", linkElement.getLabel());
|
||||
menuitem.setAttribute("href", linkElement.href);
|
||||
menuitem.setAttribute("class", "menuitem-iconic bookmark-item");
|
||||
menuitem.setAttribute("rdf:type",
|
||||
"rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#linkType");
|
||||
|
||||
return menuitem;
|
||||
}
|
||||
}
|
||||
LinkToolbarMenu.prototype = new LinkToolbarItem;
|
||||
|
||||
|
||||
function LinkToolbarTransientMenu (linkType) {
|
||||
this.constructor(linkType);
|
||||
|
||||
this.getXULElement = function() {
|
||||
if (this.__proto__.getXULElement.apply(this))
|
||||
return this.__proto__.getXULElement.apply(this);
|
||||
else
|
||||
return this.createXULElement();
|
||||
}
|
||||
|
||||
this.createXULElement = function() {
|
||||
// XXX: clone a prototypical XUL element instead of hardcoding these
|
||||
// attributes
|
||||
var menu = document.createElement("menu");
|
||||
menu.setAttribute("id", this.xulElementId);
|
||||
menu.setAttribute("label", this.linkType);
|
||||
menu.setAttribute("disabled", "true");
|
||||
menu.setAttribute("class", "menu-iconic bookmark-item");
|
||||
menu.setAttribute("container", "true");
|
||||
menu.setAttribute("type", "rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
|
||||
|
||||
document.getElementById("more-menu-popup").appendChild(menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
this.getPopup = function() {
|
||||
if (!this.__proto__.getPopup.apply(this))
|
||||
this.getXULElement().appendChild(this.createPopup());
|
||||
|
||||
return this.__proto__.getPopup.apply(this)
|
||||
}
|
||||
|
||||
this.createPopup = function() {
|
||||
var popup = document.createElement("menupopup");
|
||||
popup.setAttribute("id", this.xulPopupId);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
this.clear = function() {
|
||||
this.__proto__.clear.apply(this);
|
||||
|
||||
// XXX: we really want to use this instead of removeXULElement
|
||||
//this.hideXULElement();
|
||||
this.removeXULElement();
|
||||
}
|
||||
|
||||
this.hideXULElement = function() {
|
||||
/*
|
||||
* XXX: using "hidden" or "collapsed" leads to a crash when you
|
||||
* open the More menu under certain circumstances. Maybe
|
||||
* related to bug 83906. As of 0.9.2 I it doesn't seem
|
||||
* to crash anymore.
|
||||
*/
|
||||
this.getXULElement().setAttribute("collapsed", "true");
|
||||
}
|
||||
|
||||
this.removeXULElement = function() {
|
||||
// XXX: stop using this method once it's safe to use hideXULElement
|
||||
if (this.__proto__.getXULElement.apply(this))
|
||||
this.__proto__.getXULElement.apply(this).parentNode.removeChild(
|
||||
this.__proto__.getXULElement.apply(this));
|
||||
}
|
||||
|
||||
this.displayLink = function(linkElement) {
|
||||
if(!this.__proto__.displayLink.apply(this, [linkElement])) return false;
|
||||
|
||||
this.getXULElement().removeAttribute("collapsed");
|
||||
showMiscellaneousSeperator();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LinkToolbarTransientMenu.prototype = new LinkToolbarMenu;
|
|
@ -0,0 +1,191 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Eric Hodel's <drbrain@segment7.net> code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Eric Hodel.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Hoess <choess@force.stwing.upenn.edu>
|
||||
* Tim Taylor <tim@tool-man.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* called on every page load
|
||||
*
|
||||
* FIXME: refresh isn't called until the entire document has finished loading
|
||||
* XXX: optimization: don't refresh when page reloaded if the page hasn't
|
||||
* been modified
|
||||
* XXX: optimization: don't refresh when toolbar is compacted
|
||||
*/
|
||||
|
||||
LinkToolbarUI = function()
|
||||
{
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.refresh =
|
||||
function()
|
||||
{
|
||||
if (!linkToolbarUI.isLinkToolbarEnabled())
|
||||
return;
|
||||
|
||||
linkToolbarUI.doRefresh();
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.isLinkToolbarEnabled =
|
||||
function()
|
||||
{
|
||||
if (document.getElementById("cmd_viewlinktoolbar").getAttribute("checked") == "true")
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.doRefresh =
|
||||
function()
|
||||
{
|
||||
// Not doing <meta http-equiv> elements yet.
|
||||
// If you enable checking for A links, the browser becomes
|
||||
// unresponsive during this call...for as long as 2 or more
|
||||
// seconds on heavily linked documents.
|
||||
|
||||
var currentNode = window._content.document.documentElement;
|
||||
if(!(currentNode instanceof Components.interfaces.nsIDOMHTMLHtmlElement)) return;
|
||||
currentNode = currentNode.firstChild;
|
||||
|
||||
while(currentNode) {
|
||||
if(currentNode instanceof Components.interfaces.nsIDOMHTMLHeadElement) {
|
||||
currentNode = currentNode.firstChild;
|
||||
|
||||
while(currentNode) {
|
||||
if ((currentNode instanceof Components.interfaces.nsIDOMHTMLLinkElement) &&
|
||||
(currentNode.rel || currentNode.rev) &&
|
||||
currentNode.href) {
|
||||
linkToolbarHandler.handle(currentNode);
|
||||
}
|
||||
|
||||
currentNode = currentNode.nextSibling;
|
||||
}
|
||||
} else if (currentNode instanceof Components.interfaces.nsIDOMElement) {
|
||||
// head is supposed to be the first element inside html.
|
||||
// Got something else instead. returning
|
||||
return;
|
||||
} else {
|
||||
// Got a comment node or something like that. Moving on.
|
||||
currentNode = currentNode.nextSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.getLinkElements =
|
||||
function()
|
||||
{
|
||||
return getHeadElement().getElementsByTagName("link");
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.getHeadElement =
|
||||
function()
|
||||
{
|
||||
return window._content.document.getElementsByTagName("head").item(0);
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.getAnchorElements =
|
||||
function()
|
||||
{
|
||||
// XXX: document.links includes AREA links, which technically
|
||||
// shouldn't be checked for REL attributes
|
||||
// FIXME: doesn't work on XHTML served as application/xhtml+xml
|
||||
return window._content.document.links;
|
||||
}
|
||||
|
||||
/** called on every page unload */
|
||||
LinkToolbarUI.prototype.clear =
|
||||
function()
|
||||
{
|
||||
if (!linkToolbarUI.isLinkToolbarEnabled())
|
||||
return;
|
||||
|
||||
linkToolbarUI.doClear();
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.doClear =
|
||||
function()
|
||||
{
|
||||
this.hideMiscellaneousSeperator();
|
||||
linkToolbarHandler.clearAllItems();
|
||||
}
|
||||
|
||||
/* called whenever something on the toolbar is clicked */
|
||||
LinkToolbarUI.prototype.clicked =
|
||||
function(event)
|
||||
{
|
||||
// Return if this is one of the menubuttons.
|
||||
if (event.target.getAttribute("type") == "menu") return;
|
||||
|
||||
if (!event.target.getAttribute("href")) return;
|
||||
|
||||
var destURL = event.target.getAttribute("href");
|
||||
|
||||
// We have to do a security check here, because we are loading URIs given
|
||||
// to us by a web page from chrome, which is privileged.
|
||||
try {
|
||||
var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService().
|
||||
QueryInterface(Components.interfaces.nsIScriptSecurityManager);
|
||||
ssm.checkLoadURIStr(window.content.location.href, destURL, 0);
|
||||
loadURI(destURL);
|
||||
} catch (e) {
|
||||
dump("Error: it is not permitted to load this URI from a <link> element: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// functions for twiddling XUL elements in the toolbar
|
||||
|
||||
LinkToolbarUI.prototype.toggleLinkToolbar =
|
||||
function()
|
||||
{
|
||||
goToggleToolbar('linktoolbar', 'cmd_viewlinktoolbar');
|
||||
if (this.isLinkToolbarEnabled())
|
||||
this.doRefresh();
|
||||
else
|
||||
this.doClear();
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.showMiscellaneousSeperator =
|
||||
function()
|
||||
{
|
||||
document.getElementById("misc-seperator").removeAttribute("collapsed");
|
||||
}
|
||||
|
||||
LinkToolbarUI.prototype.hideMiscellaneousSeperator =
|
||||
function()
|
||||
{
|
||||
document.getElementById("misc-seperator").setAttribute("collapsed", "true");
|
||||
}
|
||||
|
||||
const linkToolbarUI = new LinkToolbarUI;
|
|
@ -0,0 +1,183 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
- the License. You may obtain a copy of the License at
|
||||
- http://www.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Eric Hodel's <drbrain@segment7.net> code.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Eric Hodel.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2001
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Christopher Hoess <choess@force.stwing.upenn.edu>
|
||||
- Tim Taylor <tim@tool-man.org>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
- of those above. If you wish to allow use of your version of this file only
|
||||
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
- use your version of this file under the terms of the MPL, indicate your
|
||||
- decision by deleting the provisions above and replace them with the notice
|
||||
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
<?xml-stylesheet href="chrome://navigator/skin/linkToolbar.css" type="text/css"?>
|
||||
<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
|
||||
<!DOCTYPE window SYSTEM "chrome://navigator/locale/linkToolbar.dtd">
|
||||
|
||||
<overlay id="linkToolbarOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:rdf="http://www.mozilla.org/rdf">
|
||||
|
||||
<!-- classes -->
|
||||
<script type="application/x-javascript" src="chrome://navigator/content/linkToolbarHandler.js" />
|
||||
<script type="application/x-javascript" src="chrome://navigator/content/linkToolbarItem.js" />
|
||||
<script type="application/x-javascript" src="chrome://navigator/content/languageDictionary.js" />
|
||||
|
||||
<!-- functions -->
|
||||
<script type="application/x-javascript" src="chrome://navigator/content/linkToolbarOverlay.js" />
|
||||
|
||||
<script type="application/x-javascript">
|
||||
<![CDATA[
|
||||
var contentArea = document.getElementById("appcontent");
|
||||
contentArea.addEventListener("load", linkToolbarUI.refresh, true);
|
||||
contentArea.addEventListener("unload", linkToolbarUI.clear, true);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<broadcasterset id="navBroadcasters">
|
||||
<broadcaster id="cmd_viewlinktoolbar" oncommand="linkToolbarUI.toggleLinkToolbar();" checked="true" />
|
||||
</broadcasterset>
|
||||
|
||||
<menupopup id="view_toolbars_popup">
|
||||
<menuitem label="&linkToolbar.label;" class="menuitem-iconic" type="checkbox" observes="cmd_viewlinktoolbar" position="3" />
|
||||
</menupopup>
|
||||
|
||||
<toolbox id="navigator-toolbox">
|
||||
<toolbar id="linktoolbar" class="chromeclass-directories"
|
||||
onclick="event.preventBubble(); return linkToolbarUI.clicked(event);"
|
||||
tbautostretch="always">
|
||||
|
||||
<toolbarbutton id="link-top" class="bookmark-item"
|
||||
label="&topButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarbutton id="link-up" class="bookmark-item"
|
||||
label="&upButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarseparator />
|
||||
|
||||
<toolbarbutton id="link-first" class="bookmark-item"
|
||||
label="&firstButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarbutton id="link-prev" class="bookmark-item"
|
||||
label="&prevButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarbutton id="link-next" class="bookmark-item"
|
||||
label="&nextButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarbutton id="link-last" class="bookmark-item"
|
||||
label="&lastButton.label;" disabled="true" tooltip="aTooltip" />
|
||||
|
||||
<toolbarseparator />
|
||||
|
||||
<toolbarbutton id="document-menu" class="bookmark-item"
|
||||
type="menu"
|
||||
container="true"
|
||||
label="&documentButton.label;" disabled="true">
|
||||
<menupopup id="document-menu-popup">
|
||||
|
||||
<menuitem id="link-toc" label="&tocButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
<menu id="link-chapter" label="&chapterButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-chapter-popup" />
|
||||
</menu>
|
||||
<menu id="link-section" label="§ionButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-section-popup" />
|
||||
</menu>
|
||||
<menu id="link-subsection" label="&subSectionButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-subsection-popup" />
|
||||
</menu>
|
||||
<menu id="link-appendix" label="&appendixButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-appendix-popup" />
|
||||
</menu>
|
||||
<menuitem id="link-glossary" label="&glossaryButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
<menuitem id="link-index" label="&indexButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
|
||||
<toolbarbutton id="more-menu" class="bookmark-item"
|
||||
type="menu"
|
||||
container="true"
|
||||
label="&moreButton.label;" disabled="true">
|
||||
<menupopup id="more-menu-popup">
|
||||
|
||||
<menuitem id="link-help" label="&helpButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
<menuitem id="link-search" label="&searchButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
|
||||
<menuseparator />
|
||||
|
||||
<menuitem id="link-author" label="&authorButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
<menuitem id="link-copyright" label="©rightButton.label;" disabled="true"
|
||||
class="menuitem-iconic bookmark-item"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type" />
|
||||
|
||||
<menuseparator />
|
||||
|
||||
<menu id="link-bookmark" label="&bookmarkButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-bookmark-popup" />
|
||||
</menu>
|
||||
|
||||
<menuseparator />
|
||||
|
||||
<menu id="link-alternate" label="&alternateButton.label;" disabled="true"
|
||||
class="menu-iconic bookmark-item" container="true"
|
||||
rdf:type="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type">
|
||||
<menupopup id="link-alternate-popup" />
|
||||
</menu>
|
||||
|
||||
<menuseparator collapsed="true" id="misc-seperator" />
|
||||
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
|
||||
</toolbar>
|
||||
</toolbox>
|
||||
</overlay>
|
|
@ -27,6 +27,7 @@ Contributor(s): ______________________________________. -->
|
|||
|
||||
<?xul-overlay href="chrome://navigator/content/navigatorOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://navigator/content/navExtraOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://navigator/content/linkToolbarOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://communicator/content/sidebar/sidebarOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://communicator/content/securityOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://communicator/content/communicatorOverlay.xul"?>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
- the License. You may obtain a copy of the License at
|
||||
- http://www.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Christopher Hoess <choess@stwing.upenn.edu>'s code.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Christopher Hoess.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2001
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Eric Hodel <drbrain@segment7.net>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
- of those above. If you wish to allow use of your version of this file only
|
||||
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
- use your version of this file under the terms of the MPL, indicate your
|
||||
- decision by deleting the provisions above and replace them with the notice
|
||||
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
<!-- Link Toolbar Title -->
|
||||
<!ENTITY linkToolbar.label "Link Toolbar">
|
||||
|
||||
<!-- Toolbar buttons, menus, and menuitems -->
|
||||
<!ENTITY topButton.label "Top">
|
||||
<!ENTITY upButton.label "Up">
|
||||
<!ENTITY firstButton.label "First">
|
||||
<!ENTITY prevButton.label "Previous">
|
||||
<!ENTITY nextButton.label "Next">
|
||||
<!ENTITY lastButton.label "Last">
|
||||
|
||||
<!ENTITY documentButton.label "Document">
|
||||
|
||||
<!ENTITY tocButton.label "Table of Contents">
|
||||
<!ENTITY chapterButton.label "Chapters">
|
||||
<!ENTITY sectionButton.label "Sections">
|
||||
<!ENTITY subSectionButton.label "Subsections">
|
||||
<!ENTITY appendixButton.label "Appendices">
|
||||
<!ENTITY glossaryButton.label "Glossary">
|
||||
<!ENTITY indexButton.label "Index">
|
||||
|
||||
<!ENTITY moreButton.label "More">
|
||||
|
||||
<!ENTITY helpButton.label "Help">
|
||||
<!ENTITY searchButton.label "Search">
|
||||
|
||||
<!ENTITY authorButton.label "Authors">
|
||||
<!ENTITY copyrightButton.label "Copyright">
|
||||
|
||||
<!ENTITY bookmarkButton.label "Bookmarks">
|
||||
|
||||
<!ENTITY alternateButton.label "Other Versions">
|
Загрузка…
Ссылка в новой задаче