michael@0: // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * context menu command handlers michael@0: */ michael@0: michael@0: var ContextCommands = { michael@0: _picker: null, michael@0: michael@0: get _ellipsis() { michael@0: delete this._ellipsis; michael@0: this._ellipsis = "\u2026"; michael@0: try { michael@0: this._ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data; michael@0: } catch (ex) { } michael@0: return this._ellipsis; michael@0: }, michael@0: michael@0: get clipboard() { michael@0: return Cc["@mozilla.org/widget/clipboardhelper;1"] michael@0: .getService(Ci.nsIClipboardHelper); michael@0: }, michael@0: michael@0: get docRef() { michael@0: return Browser.selectedBrowser.contentWindow.document; michael@0: }, michael@0: michael@0: /* michael@0: * Context menu handlers michael@0: */ michael@0: michael@0: // Text specific michael@0: michael@0: cut: function cc_cut() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: michael@0: if (!target) { michael@0: return; michael@0: } michael@0: michael@0: if (target.localName === "browser") { michael@0: // content michael@0: if (ContextMenuUI.popupState.string) { michael@0: this.sendCommand("cut"); michael@0: michael@0: SelectionHelperUI.closeEditSession(true); michael@0: } michael@0: } else { michael@0: // chrome michael@0: CommandUpdater.doCommand("cmd_cut"); michael@0: } michael@0: michael@0: target.focus(); michael@0: }, michael@0: michael@0: copy: function cc_copy() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: michael@0: if (!target) { michael@0: return; michael@0: } michael@0: michael@0: if (target.localName == "browser") { michael@0: // content michael@0: if (ContextMenuUI.popupState.string) { michael@0: this.sendCommand("copy"); michael@0: } michael@0: } else if (ContextMenuUI.popupState.string) { michael@0: this.clipboard.copyString(ContextMenuUI.popupState.string, this.docRef); michael@0: } else { michael@0: // chrome michael@0: CommandUpdater.doCommand("cmd_copy"); michael@0: } michael@0: michael@0: target.focus(); michael@0: }, michael@0: michael@0: paste: function cc_paste() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: michael@0: if (!target) { michael@0: return; michael@0: } michael@0: michael@0: if (target.localName == "browser") { michael@0: // content michael@0: let x = ContextMenuUI.popupState.x; michael@0: let y = ContextMenuUI.popupState.y; michael@0: let json = {x: x, y: y, command: "paste" }; michael@0: target.messageManager.sendAsyncMessage("Browser:ContextCommand", json); michael@0: } else { michael@0: // chrome michael@0: CommandUpdater.doCommand("cmd_paste"); michael@0: target.focus(); michael@0: } michael@0: SelectionHelperUI.closeEditSession(); michael@0: }, michael@0: michael@0: pasteAndGo: function cc_pasteAndGo() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: target.editor.selectAll(); michael@0: target.editor.paste(Ci.nsIClipboard.kGlobalClipboard); michael@0: BrowserUI.goToURI(); michael@0: }, michael@0: michael@0: select: function cc_select() { michael@0: SelectionHelperUI.openEditSession(ContextMenuUI.popupState.target, michael@0: ContextMenuUI.popupState.xPos, michael@0: ContextMenuUI.popupState.yPos, michael@0: true); michael@0: }, michael@0: michael@0: selectAll: function cc_selectAll() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: if (target.localName == "browser") { michael@0: // content michael@0: let x = ContextMenuUI.popupState.xPos; michael@0: let y = ContextMenuUI.popupState.yPos; michael@0: let json = {x: x, y: y, command: "select-all" }; michael@0: target.messageManager.sendAsyncMessage("Browser:ContextCommand", json); michael@0: SelectionHelperUI.attachEditSession(target, x, y); michael@0: } else { michael@0: // chrome michael@0: target.editor.selectAll(); michael@0: target.focus(); michael@0: } michael@0: }, michael@0: michael@0: // called on display of the search text menu item michael@0: searchTextSetup: function cc_searchTextSetup(aRichListItem, aSearchString) { michael@0: let defaultURI; michael@0: let defaultName; michael@0: aSearchString = aSearchString.trim(); michael@0: try { michael@0: let defaultPB = Services.prefs.getDefaultBranch(null); michael@0: const nsIPLS = Ci.nsIPrefLocalizedString; michael@0: defaultName = defaultPB.getComplexValue("browser.search.defaultenginename", nsIPLS).data; michael@0: let defaultEngine = Services.search.getEngineByName(defaultName); michael@0: defaultURI = defaultEngine.getSubmission(aSearchString).uri.spec; michael@0: } catch (ex) { michael@0: Cu.reportError(ex); michael@0: return false; michael@0: } michael@0: let displayString = aSearchString; michael@0: if (displayString.length > 15) { michael@0: displayString = displayString.substring(0, 15) + this._ellipsis; michael@0: } michael@0: // label child node michael@0: let label = Services.strings michael@0: .createBundle("chrome://browser/locale/browser.properties") michael@0: .formatStringFromName("browser.search.contextTextSearchLabel2", michael@0: [defaultName, displayString], 2); michael@0: aRichListItem.childNodes[0].setAttribute("value", label); michael@0: aRichListItem.setAttribute("searchString", defaultURI); michael@0: return true; michael@0: }, michael@0: michael@0: searchText: function cc_searchText(aRichListItem) { michael@0: let defaultURI = aRichListItem.getAttribute("searchString"); michael@0: aRichListItem.childNodes[0].setAttribute("value", ""); michael@0: aRichListItem.setAttribute("searchString", ""); michael@0: BrowserUI.addAndShowTab(defaultURI, Browser.selectedTab); michael@0: }, michael@0: michael@0: // Link specific michael@0: michael@0: openLinkInNewTab: function cc_openLinkInNewTab() { michael@0: let url = ContextMenuUI.popupState.linkURL; michael@0: BrowserUI.openLinkInNewTab(url, false, Browser.selectedTab); michael@0: }, michael@0: michael@0: copyLink: function cc_copyLink() { michael@0: this.clipboard.copyString(ContextMenuUI.popupState.linkURL, michael@0: this.docRef); michael@0: }, michael@0: michael@0: bookmarkLink: function cc_bookmarkLink() { michael@0: let state = ContextMenuUI.popupState; michael@0: let uri = Util.makeURI(state.linkURL); michael@0: let title = state.linkTitle || state.linkURL; michael@0: michael@0: try { michael@0: Bookmarks.addForURI(uri, title); michael@0: } catch (e) { michael@0: return; michael@0: } michael@0: }, michael@0: michael@0: // Image specific michael@0: michael@0: saveImageToLib: function cc_saveImageToLib() { michael@0: this.saveToWinLibrary("Pict"); michael@0: }, michael@0: michael@0: copyImage: function cc_copyImage() { michael@0: // copy to clibboard michael@0: this.sendCommand("copy-image-contents"); michael@0: }, michael@0: michael@0: copyImageSrc: function cc_copyImageSrc() { michael@0: this.clipboard.copyString(ContextMenuUI.popupState.mediaURL, michael@0: this.docRef); michael@0: }, michael@0: michael@0: openImageInNewTab: function cc_openImageInNewTab() { michael@0: BrowserUI.addAndShowTab(ContextMenuUI.popupState.mediaURL, Browser.selectedTab); michael@0: }, michael@0: michael@0: // Video specific michael@0: michael@0: saveVideoToLib: function cc_saveVideoToLib() { michael@0: this.saveToWinLibrary("Vids"); michael@0: }, michael@0: michael@0: copyVideoSrc: function cc_copyVideoSrc() { michael@0: this.clipboard.copyString(ContextMenuUI.popupState.mediaURL, michael@0: this.docRef); michael@0: }, michael@0: michael@0: openVideoInNewTab: function cc_openVideoInNewTab() { michael@0: BrowserUI.addAndShowTab(ContextMenuUI.popupState.mediaURL, Browser.selectedTab); michael@0: }, michael@0: michael@0: // Bookmarks michael@0: michael@0: editBookmark: function cc_editBookmark() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: target.startEditing(); michael@0: }, michael@0: michael@0: removeBookmark: function cc_removeBookmark() { michael@0: let target = ContextMenuUI.popupState.target; michael@0: target.remove(); michael@0: }, michael@0: michael@0: // App bar michael@0: michael@0: errorConsole: function cc_errorConsole() { michael@0: PanelUI.show("console-container"); michael@0: }, michael@0: michael@0: jsShell: function cc_jsShell() { michael@0: // XXX for debugging, this only works when running on the desktop. michael@0: if (!Services.metro.immersive) michael@0: window.openDialog("chrome://browser/content/shell.xul", "_blank", michael@0: "all=no,scrollbars=yes,resizable=yes,dialog=no"); michael@0: }, michael@0: michael@0: findInPage: function cc_findInPage() { michael@0: FindHelperUI.show(); michael@0: }, michael@0: michael@0: viewOnDesktop: function cc_viewOnDesktop() { michael@0: Appbar.onViewOnDesktop(); michael@0: }, michael@0: michael@0: // Checks for MS app store specific meta data, and if present opens michael@0: // the Windows Store to the appropriate app michael@0: openWindowsStoreLink: function cc_openWindowsStoreLink() { michael@0: let storeLink = this.getStoreLink(); michael@0: if (storeLink) { michael@0: Browser.selectedBrowser.contentWindow.document.location = storeLink; michael@0: } michael@0: }, michael@0: michael@0: getStoreLink: function cc_getStoreLink() { michael@0: let metaData = Browser.selectedBrowser.contentWindow.document.getElementsByTagName("meta"); michael@0: let msApplicationName = metaData.namedItem("msApplication-PackageFamilyName"); michael@0: if (msApplicationName) { michael@0: return "ms-windows-store:PDP?PFN=" + msApplicationName.getAttribute("content"); michael@0: } michael@0: return null; michael@0: }, michael@0: michael@0: getPageSource: function cc_getPageSource() { michael@0: let uri = Services.io.newURI(Browser.selectedBrowser.currentURI.spec, null, null); michael@0: if (!uri.schemeIs("view-source")) { michael@0: return "view-source:" + Browser.selectedBrowser.currentURI.spec; michael@0: } michael@0: return null; michael@0: }, michael@0: michael@0: viewPageSource: function cc_viewPageSource() { michael@0: let uri = this.getPageSource(); michael@0: if (uri) { michael@0: BrowserUI.addAndShowTab(uri, Browser.selectedTab); michael@0: } michael@0: }, michael@0: michael@0: /* michael@0: * Utilities michael@0: */ michael@0: michael@0: saveToWinLibrary: function cc_saveToWinLibrary(aType) { michael@0: let popupState = ContextMenuUI.popupState; michael@0: let browser = popupState.target; michael@0: michael@0: // ContentAreaUtils internalSave relies on various desktop related prefs, michael@0: // values, and functionality. We want to be more direct by saving the michael@0: // image to the users Windows Library. If users want to specify the michael@0: // save location they can use the context menu option 'Save (type) To'. michael@0: michael@0: let dirSvc = Components.classes["@mozilla.org/file/directory_service;1"] michael@0: .getService(Components.interfaces.nsIProperties); michael@0: let saveLocationPath = dirSvc.get(aType, Components.interfaces.nsIFile); michael@0: michael@0: let fileInfo = new ContentAreaUtils.FileInfo(); michael@0: ContentAreaUtils.initFileInfo(fileInfo, popupState.mediaURL, michael@0: browser.documentURI.originCharset, michael@0: null, null, null); michael@0: let filename = michael@0: ContentAreaUtils.getNormalizedLeafName(fileInfo.fileName, fileInfo.fileExt); michael@0: saveLocationPath.append(filename); michael@0: michael@0: // Start the background save process michael@0: ContentAreaUtils.internalPersist({ michael@0: sourceURI : fileInfo.uri, michael@0: sourceDocument : null, michael@0: sourceReferrer : browser.documentURI, michael@0: targetContentType : popupState.contentType, michael@0: targetFile : saveLocationPath, michael@0: sourceCacheKey : null, michael@0: sourcePostData : null, michael@0: bypassCache : false, michael@0: initiatingWindow : this.docRef.defaultView michael@0: }); michael@0: }, michael@0: michael@0: sendCommand: function sendCommand(aCommand) { michael@0: // Send via message manager over to ContextMenuHandler michael@0: let browser = ContextMenuUI.popupState.target; michael@0: browser.messageManager.sendAsyncMessage("Browser:ContextCommand", { command: aCommand }); michael@0: }, michael@0: michael@0: /* michael@0: * isAccessibleDirectory michael@0: * michael@0: * Test to see if the directory exists and is writable. michael@0: */ michael@0: isAccessibleDirectory: function isAccessibleDirectory(aDirectory) { michael@0: return aDirectory && aDirectory.exists() && aDirectory.isDirectory() && michael@0: aDirectory.isWritable(); michael@0: }, michael@0: michael@0: /* michael@0: * saveFileAs michael@0: * michael@0: * Browse for a location and then save a file to the local system using michael@0: * standard download prefs. michael@0: * michael@0: * @param aFileUriString path to file michael@0: */ michael@0: saveFileAs: function saveFileAs(aPopupState) { michael@0: let srcUri = null; michael@0: let mediaURL = aPopupState.mediaURL; michael@0: try { michael@0: srcUri = Util.makeURI(mediaURL, null, null); michael@0: } catch (ex) { michael@0: Util.dumpLn("could not parse:", mediaURL); michael@0: return; michael@0: } michael@0: michael@0: let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); michael@0: let windowTitle = Strings.browser.GetStringFromName("browserForSaveLocation"); michael@0: michael@0: picker.init(window, windowTitle, Ci.nsIFilePicker.modeSave); michael@0: michael@0: // prefered filename michael@0: let fileName = mediaURL.substring(mediaURL.lastIndexOf("/") + 1); michael@0: if (fileName.length) michael@0: picker.defaultString = fileName; michael@0: michael@0: // prefered file extension michael@0: let fileExtension = mediaURL.substring(mediaURL.lastIndexOf(".") + 1); michael@0: if (fileExtension.length) michael@0: picker.defaultExtension = fileExtension; michael@0: picker.appendFilters(Ci.nsIFilePicker.filterImages); michael@0: michael@0: // prefered save location michael@0: Task.spawn(function() { michael@0: let preferredDir = yield Downloads.getPreferredDownloadsDirectory(); michael@0: picker.displayDirectory = new FileUtils.File(preferredDir); michael@0: michael@0: try { michael@0: let lastDir = Services.prefs.getComplexValue("browser.download.lastDir", Ci.nsILocalFile); michael@0: if (this.isAccessibleDirectory(lastDir)) michael@0: picker.displayDirectory = lastDir; michael@0: } michael@0: catch (e) { } michael@0: michael@0: this._picker = picker; michael@0: this._pickerUrl = mediaURL; michael@0: this._pickerContentDisp = aPopupState.contentDisposition; michael@0: this._contentType = aPopupState.contentType; michael@0: picker.open(ContextCommands); michael@0: }.bind(this)); michael@0: }, michael@0: michael@0: /* michael@0: * Filepicker callback michael@0: */ michael@0: done: function done(aSuccess) { michael@0: let picker = this._picker; michael@0: this._picker = null; michael@0: michael@0: if (aSuccess == Ci.nsIFilePicker.returnCancel) michael@0: return; michael@0: michael@0: let file = picker.file; michael@0: if (file == null) michael@0: return; michael@0: michael@0: try { michael@0: if (file.exists()) michael@0: file.remove(false); michael@0: } catch (e) {} michael@0: michael@0: ContentAreaUtils.internalSave(this._pickerUrl, null, null, michael@0: this._pickerContentDisp, michael@0: this._contentType, false, "SaveImageTitle", michael@0: new AutoChosen(file, Util.makeURI(this._pickerUrl, null, null)), michael@0: getBrowser().documentURI, this.docRef, true, null); michael@0: michael@0: var newDir = file.parent.QueryInterface(Ci.nsILocalFile); michael@0: Services.prefs.setComplexValue("browser.download.lastDir", Ci.nsILocalFile, newDir); michael@0: }, michael@0: }; michael@0: michael@0: function AutoChosen(aFileAutoChosen, aUriAutoChosen) { michael@0: this.file = aFileAutoChosen; michael@0: this.uri = aUriAutoChosen; michael@0: } michael@0: