tbogard%aol.net 606cb975b6 Removed the ViewSource function as it is no longer used. BrowserViewSource is what is always used now.
git-svn-id: svn://10.0.0.236/trunk@62854 18797224-902f-48f8-a5cc-f745e15eee43
2000-03-14 04:41:46 +00:00

469 lines
19 KiB
JavaScript

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Mozilla Communicator client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* William A. ("PowerGUI") Law <law@netscape.com>
*/
/*------------------------------ nsContextMenu ---------------------------------
| This JavaScript "class" is used to implement the browser's content-area |
| context menu. |
| |
| For usage, see references to this class in navigator.xul. |
| |
| Currently, this code is relatively useless for any other purpose. In the |
| longer term, this code will be restructured to make it more reusable. |
------------------------------------------------------------------------------*/
function nsContextMenu( xulMenu ) {
this.target = null;
this.menu = null;
this.onImage = false;
this.onLink = false;
this.onSaveableLink = false;
this.link = false;
this.inFrame = false;
this.hasBGImage = false;
// Initialize new menu.
this.initMenu( xulMenu );
}
// Prototype for nsContextMenu "class."
nsContextMenu.prototype = {
// onDestroy is a no-op at this point.
onDestroy : function () {
},
// Initialize context menu.
initMenu : function ( popup, event ) {
// Save menu.
this.menu = popup;
// Get contextual info.
this.setTarget( document.popupNode );
// Initialize (disable/remove) menu items.
this.initItems();
},
initItems : function () {
this.initOpenItems();
this.initNavigationItems();
this.initViewItems();
this.initMiscItems();
this.initSaveItems();
this.initClipboardItems();
},
initOpenItems : function () {
// Remove open/edit link if not applicable.
this.showItem( "context-openlink", this.onSaveableLink );
this.showItem( "context-editlink", this.onSaveableLink );
// Remove open frame if not applicable.
this.showItem( "context-openframe", this.inFrame );
// Remove separator after open items if neither link nor frame.
this.showItem( "context-sep-open", this.onSaveableLink || this.inFrame );
},
initNavigationItems : function () {
// Back determined by canGoBack broadcaster.
this.setItemAttrFromNode( "context-back", "disabled", "canGoBack" );
// Forward determined by canGoForward broadcaster.
this.setItemAttrFromNode( "context-forward", "disabled", "canGoForward" );
// Reload is always OK.
// Stop determined by canStop broadcaster.
this.setItemAttrFromNode( "context-stop", "disabled", "canStop" );
},
initSaveItems : function () {
// Save page is always OK.
// Save frame as depends on whether we're in a frame.
this.showItem( "context-saveframe", this.inFrame );
// Save link depends on whether we're in a link.
this.showItem( "context-savelink", this.onSaveableLink );
// Save background image depends on whether there is one.
this.showItem( "context-savebgimage", this.hasBGImage );
// Save image depends on whether there is one.
this.showItem( "context-saveimage", this.onImage );
},
initViewItems : function () {
// View source is always OK.
// View frame source depends on whether we're in a frame.
this.showItem( "context-viewframesource", this.inFrame );
// View Info don't work no way no how.
this.showItem( "context-viewinfo", false );
// View Frame Info isn't working, either.
this.showItem( "context-viewframeinfo", false );
// View Image depends on whether an image was clicked on.
this.showItem( "context-viewimage", this.onImage );
},
initMiscItems : function () {
// Add bookmark always OK.
// Send Page not working yet.
this.showItem( "context-sendpage", false );
},
initClipboardItems : function () {
// Select All is always OK.
// Copy depends on whether there is selected text.
// Enabling this context menu item is now done through the global
// command updating system
// this.setItemAttr( "context-copy", "disabled", this.isNoTextSelected() );
// Copy link location depends on whether we're on a link.
this.showItem( "context-copylink", this.onLink );
// Copy image location depends on whether we're on an image.
this.showItem( "context-copyimage", this.onImage );
},
// Set various context menu attributes based on the state of the world.
setTarget : function ( node ) {
// Initialize contextual info.
this.onImage = false;
this.imageURL = "";
this.onLink = false;
this.inFrame = false;
this.hasBGImage = false;
// Remember the node that was clicked.
this.target = node;
// See if the user clicked on an image.
if ( this.target.nodeType == 1 ) {
if ( this.target.tagName.toUpperCase() == "IMG" ) {
this.onImage = true;
this.imageURL = this.target.src;
// Look for image map.
var mapName = this.target.getAttribute( "usemap" );
if ( mapName ) {
// Find map.
var map = this.target.ownerDocument.getElementById( mapName.substr(1) );
if ( map ) {
// Search child <area>s for a match.
var areas = map.childNodes;
//XXX Client side image maps are too hard for now!
dump( "Client side image maps not supported yet, sorry!\n" );
areas.length = 0;
for ( var i = 0; i < areas.length && !this.onLink; i++ ) {
var area = areas[i];
if ( area.nodeType == 1
&&
area.tagName.toUpperCase() == "AREA" ) {
// Get type (rect/circle/polygon/default).
var type = area.getAttribute( "type" );
var coords = this.parseCoords( area );
switch ( type.toUpperCase() ) {
case "RECT":
case "RECTANGLE":
break;
case "CIRC":
case "CIRCLE":
break;
case "POLY":
case "POLYGON":
break;
case "DEFAULT":
// Default matches entire image.
this.onLink = true;
this.link = area;
this.onSaveableLink = this.isLinkSaveable( this.link );
break;
}
}
}
}
}
} else if (this.target.tagName.toUpperCase() == "INPUT") {
if(this.target.getAttribute( "type" ).toUpperCase() == "IMAGE") {
this.onImage = true;
this.imageURL = this.target.src;
}
} else if (this.target.getAttribute( "background" )) {
this.onImage = true;
this.imageURL = this.target.getAttribute( "background" );
} else {
var cssAttr = this.target.style.getPropertyValue( "list-style-image" ) ||
this.target.style.getPropertyValue( "list-style" ) ||
this.target.style.getPropertyValue( "background-image" ) ||
this.target.style.getPropertyValue( "background" );
if ( cssAttr ) {
this.onImage = true;
this.imageURL = cssAttr.toLowerCase().replace(/url\("*(.+)"*\)/, "$1");
}
}
}
// See if the user clicked in a frame.
if ( this.target.ownerDocument != window.content.document ) {
this.inFrame = true;
}
// Bubble out, looking for link.
var elem = this.target;
while ( elem && !this.onLink ) {
// Test for element types of interest.
if ( elem.nodeType == 1 &&
( elem.tagName.toUpperCase() == "A"
||
elem.tagName.toUpperCase() == "AREA" ) ) {
// Clicked on a link.
this.onLink = true;
// Remember corresponding element.
this.link = elem;
// Remember if it is saveable.
this.onSaveableLink = this.isLinkSaveable( this.link );
}
elem = elem.parentNode;
}
},
// Returns true iff clicked on link is saveable.
isLinkSaveable : function ( link ) {
// Test for missing protocol property.
if ( !link.protocol ) {
// We must resort to testing the URL string :-(.
dump( "Bug! Link.protocol is still undefined!\n" );
var protocol = link.href.substr( 0, 11 );
return protocol != "javascript:";
} else {
// Presume all but javascript: urls are saveable.
return link.protocol != "javascript:";
}
},
// Open linked-to URL in a new window.
openLink : function () {
// Determine linked-to URL.
openNewWindowWith( this.linkURL() );
},
// Edit linked-to URL in a new window.
editLink : function () {
BrowserEditPage( this.linkURL() );
},
// Open clicked-in frame in its own window.
openFrame : function () {
openNewWindowWith( this.target.ownerDocument.location.href );
},
viewInfo : function () {
dump( "nsContextMenu.viewInfo not implemented yet\n" );
},
viewFrameInfo : function () {
dump( "nsContextMenu.viewFrameInfo not implemented yet\n" );
},
// Open new window with the URL of the image.
viewImage : function () {
openNewWindowWith( this.imageURL );
},
// Save URL of clicked-on frame.
saveFrame : function () {
this.savePage( this.target.ownerDocument.location.href );
},
// Save URL of clicked-on link.
saveLink : function () {
this.savePage( this.linkURL() );
},
// Save URL of clicked-on image.
saveImage : function () {
this.savePage( this.imageURL );
},
// Save URL of background image.
saveBGImage : function () {
this.savePage( this.bgImageURL() );
},
// Generate link URL and put it on clibboard.
copyLink : function () {
this.copyToClipboard( this.linkURL() );
},
// Generate image URL and put it on the clipboard.
copyImage : function () {
this.copyToClipboard( this.imageURL );
},
// Determine if "Block Image" is to appear in the menu.
checkForImageBlocker: function () {
pref = Components.classes['component://netscape/preferences'];
pref = pref.getService();
pref = pref.QueryInterface(Components.interfaces.nsIPref);
try {
if (pref.GetBoolPref("imageblocker.enabled")) {
var element = document.getElementById("context-blockimage");
element.setAttribute("style","display: inline;" );
}
} catch(e) {
}
},
// Block image from loading in the future.
blockImage : function () {
cookieviewer = Components.classes["component://netscape/cookieviewer/cookieviewer-world"].createInstance();
cookieviewer = cookieviewer.QueryInterface(Components.interfaces.nsICookieViewer);
cookieviewer.BlockImage(this.imageURL);
// here's how we would have liked to do this but there is no idl for cookies
// wallet = Components.classes['component://netscape/wallet'];
// wallet = wallet.getService();
// wallet = wallet.QueryInterface(Components.interfaces.nsIWalletService);
// wallet.WALLET_ChangePassword();
},
// Utilities
// Show/hide one item (specified via name or the item element itself).
showItem : function ( itemOrId, show ) {
var item = null;
if ( itemOrId.constructor == String ) {
// Argument specifies item id.
item = document.getElementById( itemOrId );
} else {
// Argument is the item itself.
item = itemOrId;
}
if ( item ) {
var styleIn = item.getAttribute( "style" );
var styleOut = styleIn;
if ( show ) {
// Remove style="display:none;".
styleOut = styleOut.replace( "display:none;", "" );
} else {
// Set style="display:none;".
if ( styleOut.indexOf( "display:none;" ) == -1 ) {
// Add style the first time we need to.
styleOut += "display:none;";
}
}
// Only set style if it's different.
if ( styleIn != styleOut ) {
item.setAttribute( "style", styleOut );
}
}
},
// Set given attribute of specified context-menu item. If the
// value is null, then it removes the attribute (which works
// nicely for the disabled attribute).
setItemAttr : function ( id, attr, val ) {
var elem = document.getElementById( id );
if ( elem ) {
if ( val == null ) {
// null indicates attr should be removed.
elem.removeAttribute( attr );
} else {
// Set attr=val.
elem.setAttribute( attr, val );
}
}
},
// Set context menu attribute according to like attribute of another node
// (such as a broadcaster).
setItemAttrFromNode : function ( item_id, attr, other_id ) {
var elem = document.getElementById( other_id );
if ( elem && elem.getAttribute( attr ) == "true" ) {
this.setItemAttr( item_id, attr, "true" );
} else {
this.setItemAttr( item_id, attr, null );
}
},
// Temporary workaround for DOM api not yet implemented by XUL nodes.
cloneNode : function ( item ) {
// Create another element like the one we're cloning.
var node = document.createElement( item.tagName );
// Copy attributes from argument item to the new one.
var attrs = item.attributes;
for ( var i = 0; i < attrs.length; i++ ) {
var attr = attrs.item( i );
node.setAttribute( attr.nodeName, attr.nodeValue );
}
// Voila!
return node;
},
// Generate fully-qualified URL for clicked-on link.
linkURL : function () {
return this.link.href;
},
// Returns "true" if there's no text selected, null otherwise.
isNoTextSelected : function ( event ) {
// Not implemented so all text-selected-based options are disabled.
return "true";
},
// Copy link/image url to clipboard.
copyToClipboard : function ( text ) {
// Get clipboard.
var clipboard = Components
.classes["component://netscape/widget/clipboard"]
.getService ( Components.interfaces.nsIClipboard );
// Create tranferable that will transfer the text.
var transferable = Components
.classes["component://netscape/widget/transferable"]
.createInstance( Components.interfaces.nsITransferable );
if ( clipboard && transferable ) {
transferable.addDataFlavor( "text/unicode" );
// Create wrapper for text.
var data = createInstance( "component://netscape/supports-wstring",
"nsISupportsWString" );
if ( data ) {
data.data = text ;
transferable.setTransferData( "text/unicode", data, text.length * 2 );
// Put on clipboard.
clipboard.setData( transferable, null );
}
}
},
// Save specified URL in user-selected file.
savePage : function ( url ) {
// Default is to save current page.
if ( !url ) {
url = window.content.location.href;
}
// Use stream xfer component to prompt for destination and save.
var xfer = Components
.classes[ "component://netscape/appshell/component/xfer" ]
.getService( Components.interfaces.nsIStreamTransfer );
try {
// When Necko lands, we need to receive the real nsIChannel and
// do SelectFileAndTransferLocation!
// Use this for now...
xfer.SelectFileAndTransferLocationSpec( url, window );
} catch( exception ) {
// Failed (or cancelled), give them another chance.
dump( "SelectFileAndTransferLocationSpec failed, rv=" + exception + "\n" );
}
return;
},
// Parse coords= attribute and return array.
parseCoords : function ( area ) {
return [];
},
toString : function () {
return "contextMenu.target = " + this.target + "\n" +
"contextMenu.onImage = " + this.onImage + "\n" +
"contextMenu.onLink = " + this.onLink + "\n" +
"contextMenu.link = " + this.link + "\n" +
"contextMenu.inFrame = " + this.inFrame + "\n" +
"contextMenu.hasBGImage = " + this.hasBGImage + "\n";
}
};