Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first commit

  • Loading branch information...
commit 4566cbab1bccb28230680379512014ad13d175d9 0 parents
@spasche authored
Showing with 1,096 additions and 0 deletions.
  1. +2 −0  .gitignore
  2. +23 −0 Makefile
  3. +12 −0 chrome.manifest
  4. +12 −0 chrome.manifest_jar
  5. +48 −0 chrome/content/browserOverlay.js
  6. +60 −0 chrome/content/browserOverlay.xul
  7. +154 −0 chrome/content/openInBrowser.js
  8. +166 −0 chrome/content/unknownContentTypeOverlay.js
  9. +57 −0 chrome/content/unknownContentTypeOverlay.xul
  10. +4 −0 chrome/locale/de-DE/openInBrowser.dtd
  11. +17 −0 chrome/locale/de-DE/openInBrowser.properties
  12. +4 −0 chrome/locale/en-US/openInBrowser.dtd
  13. +17 −0 chrome/locale/en-US/openInBrowser.properties
  14. +4 −0 chrome/locale/fr/openInBrowser.dtd
  15. +17 −0 chrome/locale/fr/openInBrowser.properties
  16. +4 −0 chrome/locale/sv-SE/openInBrowser.dtd
  17. +17 −0 chrome/locale/sv-SE/openInBrowser.properties
  18. +172 −0 components/OpenInBrowser.js
  19. +59 −0 install.rdf
  20. +1 −0  tests/.htaccess
  21. +10 −0 tests/README.txt
  22. BIN  tests/TESTCASE.doc.gz
  23. BIN  tests/files/image_png.png
  24. +1 −0  tests/files/test.avi
  25. +1 −0  tests/files/test.py
  26. +1 −0  tests/files/text_plain.txt
  27. +1 −0  tests/files/text_with_binary_content.txt
  28. +1 −0  tests/files/text_xml.xml
  29. +79 −0 tests/mime.php
  30. +13 −0 tests/open_after_timeout.html
  31. +139 −0 tests/tests.html
2  .gitignore
@@ -0,0 +1,2 @@
+.hg
+openinbrowser.kpf
23 Makefile
@@ -0,0 +1,23 @@
+all:
+ :
+
+NAME := openinbrowser
+VERSION := $(shell grep em:version install.rdf|sed 's@.*em:version>\([^<]*\)<.*@\1@')
+TARGET_XPI = $(NAME)-$(VERSION).xpi
+
+xpi:
+ rm -rf ../tmp || :
+ mkdir ../tmp
+ cp -r ../$(NAME) ../tmp
+ cd ../tmp/$(NAME)/chrome; \
+ zip -r $(NAME).jar *; \
+ rm -rf content locale
+ rm -rf ../tmp/$(NAME)/.hg
+ find ../tmp -name "*~" -exec rm {} \;
+ rm ../tmp/$(NAME)/chrome.manifest
+ mv ../tmp/$(NAME)/chrome.manifest_jar ../tmp/$(NAME)/chrome.manifest
+ cd ../tmp/$(NAME); \
+ zip -r $(TARGET_XPI) *
+ rm ../$(TARGET_XPI) || :
+ mv ../tmp/$(NAME)/$(TARGET_XPI) ..
+ rm -rf ../tmp
12 chrome.manifest
@@ -0,0 +1,12 @@
+content openinbrowser chrome/content/
+locale openinbrowser de-DE chrome/locale/de-DE/
+locale openinbrowser en-US chrome/locale/en-US/
+locale openinbrowser fr chrome/locale/fr/
+locale openinbrowser sv-SE chrome/locale/sv-SE/
+
+overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://openinbrowser/content/unknownContentTypeOverlay.xul
+overlay chrome://browser/content/browser.xul chrome://openinbrowser/content/browserOverlay.xul
+overlay chrome://navigator/content/navigator.xul chrome://openinbrowser/content/browserOverlay.xul
+
+component {14aa9340-c449-4956-a5f9-a52fb32f933d} components/OpenInBrowser.js
+contract @spasche.net/openinbrowser;1 {14aa9340-c449-4956-a5f9-a52fb32f933d}
12 chrome.manifest_jar
@@ -0,0 +1,12 @@
+content openinbrowser jar:chrome/openinbrowser.jar!/content/
+locale openinbrowser de-DE jar:chrome/openinbrowser.jar!/locale/de-DE/
+locale openinbrowser en-US jar:chrome/openinbrowser.jar!/locale/en-US/
+locale openinbrowser fr jar:chrome/openinbrowser.jar!/locale/fr/
+locale openinbrowser sv-SE jar:chrome/openinbrowser.jar!/locale/sv-SE/
+
+overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://openinbrowser/content/unknownContentTypeOverlay.xul
+overlay chrome://browser/content/browser.xul chrome://openinbrowser/content/browserOverlay.xul
+overlay chrome://navigator/content/navigator.xul chrome://openinbrowser/content/browserOverlay.xul
+
+component {14aa9340-c449-4956-a5f9-a52fb32f933d} components/OpenInBrowser.js
+contract @spasche.net/openinbrowser;1 {14aa9340-c449-4956-a5f9-a52fb32f933d}
48 chrome/content/browserOverlay.js
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.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 the Open in Browser extension.
+ *
+ * The Initial Developer of the Original Code is
+ * Sylvain Pasche <sylvain.pasche@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var OIB_BrowserOverlay = {
+
+ populateMimeTypesMenu: function OIBBO_popuplateViewAsMenu(event) {
+ var popup = event.target;
+
+ var uri = Application.activeWindow.activeTab.uri;
+ OpenInBrowser.populateMenu(document.getElementById("mimeTypesPopup"), uri);
+ },
+
+ onSetMimeCommand: function OIBBO_onSetMimeCommand(event) {
+ var mime = event.target.mime;
+ if (!mime)
+ return;
+
+ if (mime == OpenInBrowser.OTHER_MIME) {
+ mime = prompt(OpenInBrowser.strings.getString("SelectMimeType"));
+
+ if (!OpenInBrowser.validateMime(mime))
+ return;
+ }
+
+ OpenInBrowser.reloadWithMime(Application.activeWindow.activeTab.uri, mime)
+ }
+};
60 chrome/content/browserOverlay.xul
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.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 the Open in Browser extension.
+ -
+ - The Initial Developer of the Original Code is
+ - Sylvain Pasche <sylvain.pasche@gmail.com>.
+ - Portions created by the Initial Developer are Copyright (C) 2009
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ -
+ - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE window [
+<!ENTITY % openInBrowserDTD SYSTEM "chrome://openinbrowser/locale/openInBrowser.dtd">
+%openInBrowserDTD;
+]>
+
+<overlay id="openInBrowserBrowserOverlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/x-javascript"
+ src="chrome://openinbrowser/content/openInBrowser.js"/>
+ <script type="application/x-javascript"
+ src="chrome://openinbrowser/content/browserOverlay.js"/>
+
+ <stringbundleset id="stringbundleset">
+ <stringbundle id="strings_openInBrowser" src="chrome://openInBrowser/locale/openInBrowser.properties"/>
+ </stringbundleset>
+
+ <commandset id="mainCommandSet">
+ <command id="cmd_mimeTypeChange" oncommand="OIB_BrowserOverlay.onSetMimeCommand(event)"/>
+ </commandset>
+
+ <menupopup id="menu_viewPopup">
+ <menu id="viewAsMenu" insertafter="charsetMenu"/>
+ </menupopup>
+
+ <menupopup id="menu_View_Popup">
+ <menu id="viewAsMenu" insertafter="charsetMenu"/>
+ </menupopup>
+
+ <menu id="viewAsMenu" label="&viewAs.label;" accesskey="&viewAs.accesskey;">
+ <menupopup command="cmd_mimeTypeChange" id="mimeTypesPopup"
+ onpopupshowing="OIB_BrowserOverlay.populateMimeTypesMenu(event)"/>
+ </menu>
+
+</overlay>
154 chrome/content/openInBrowser.js
@@ -0,0 +1,154 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.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 the Open in Browser extension.
+ *
+ * The Initial Developer of the Original Code is
+ * Sylvain Pasche <sylvain.pasche@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+var OpenInBrowser = {
+ SEPARATOR_ID: "oib_separator",
+ OTHER_MIME: "other",
+
+ MIMES_HTTP: [
+ "text/plain",
+ "text/html",
+ "view-source",
+ "text/xml",
+ // Note:
+ // For image mime types, it relies on the fact that Gecko will correctly
+ // display an image even if the server sent it with a mime type that does not
+ // match the real image type. For instance, a PNG image sent with
+ // image/jpeg Content-Type will still be displayed properly.
+ "image/jpeg",
+ "oib_separator",
+ "other",
+ ],
+
+ MIMES_NON_HTTP: [
+ "view-source"
+ ],
+
+ ADDITIONAL_MIMES_PREF: "extensions.openinbrowser.additional_mimes",
+
+ get _netutil() {
+ delete this._netutil;
+ return this._netutil = Cc["@mozilla.org/network/util;1"].
+ getService(Ci.nsINetUtil);
+ },
+
+ get strings() {
+ delete this.strings;
+ return this.strings = document.getElementById("strings_openInBrowser");
+ },
+
+ populateMenu: function OIB_populateMenu(popup, uri) {
+ var mimes;
+
+ if (/^http/.test(uri.scheme)) {
+ mimes = this.MIMES_HTTP;
+
+ var additionalMimes = Application.prefs.getValue(this.ADDITIONAL_MIMES_PREF, null);
+ if (additionalMimes) {
+ mimes = mimes.slice();
+ for each (let m in additionalMimes.split("|")) {
+ if (m)
+ mimes.push(m);
+ }
+ }
+ } else {
+ mimes = this.MIMES_NON_HTTP;
+ }
+
+ while (popup.firstChild)
+ popup.removeChild(popup.firstChild);
+
+ for each (let mime in mimes) {
+ var item;
+ if (mime == this.SEPARATOR_ID) {
+ item = document.createElement("menuseparator");
+ item.id = this.SEPARATOR_ID;
+ popup.appendChild(item);
+ continue;
+ }
+ item = document.createElement("menuitem");
+ item.mime = mime;
+ // Id attribute is used for finding items with getElementById().
+ item.id = "mimeid_" + mime;
+
+ var label = mime;
+
+ // Use .stringBundle.GetStringFromName() instead of .getString()
+ // to prevent dumping an exception if not found.
+ try {
+ label = this.strings.stringBundle.GetStringFromName(mime + ".label");
+ } catch(e) { }
+ // Must use setAttribute, setting the label property doesn't work when
+ // done on elements before they are added to the DOM.
+ item.setAttribute("label", label);
+
+ try {
+ var accesskey = this.strings.stringBundle
+ .GetStringFromName(mime + ".accesskey");
+ item.setAttribute("accesskey", accesskey);
+ } catch(e) { }
+
+ popup.appendChild(item);
+ }
+ },
+
+ validateMime: function OIB_validateMime(mime) {
+ var type = this._netutil.parseContentType(mime, {}, {});
+
+ if (!type) {
+ alert(this.strings.getFormattedString("InvalidMimeType", [mime]));
+ return false;
+ }
+ return true;
+ },
+
+ reloadWithMime: function OIB_reloadWithMime(uri, mime, doc) {
+ if (mime == "view-source") {
+ var iosvc = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ uri = iosvc.newURI("view-source:" + uri.spec, null, null);
+ } else {
+ var interceptor = Cc["@spasche.net/openinbrowser;1"].
+ getService().wrappedJSObject;
+ interceptor.addInterceptInfo(uri.spec, mime);
+ }
+ var tab = Application.activeWindow.activeTab;
+ if (doc) {
+ var matchingTabs = [];
+ Application.windows.forEach(function(window) {
+ window.tabs.forEach(function(tab) {
+ if (tab.document == doc)
+ matchingTabs.push(tab);
+ })
+ })
+ if (matchingTabs.length == 1) {
+ tab = matchingTabs[0];
+ }
+ }
+ tab.load(uri);
+ }
+}
166 chrome/content/unknownContentTypeOverlay.js
@@ -0,0 +1,166 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.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 the Open in Browser extension.
+ *
+ * The Initial Developer of the Original Code is
+ * Sylvain Pasche <sylvain.pasche@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var OIB_DownloadOverlay = {
+ dialogAcceptRetVal: true,
+
+ _getMime: function OIBDO_getMime() {
+ var mime = document.getElementById("mimeTypesMenu").selectedItem.mime;
+ if (mime != OpenInBrowser.OTHER_MIME)
+ return mime;
+
+ mime = document.getElementById("mimeOtherText").value;
+ if (!OpenInBrowser.validateMime(mime))
+ mime = null;
+
+ return mime;
+ },
+
+ dialogAccepted: function OIBDO_dialogAccepted() {
+ if (document.getElementById('mode').selectedItem.id != "openInBrowser")
+ return false;
+
+ this.dialogAcceptRetVal = true;
+
+ var mime = this._getMime();
+ if (!mime) {
+ // if the mime type is not valid, keep the dialog open
+ this.dialogAcceptRetVal = false;
+ } else {
+ var parent = dialog.mContext.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowInternal);
+ OpenInBrowser.reloadWithMime(dialog.mLauncher.source, mime,
+ parent.document);
+ }
+
+ return true;
+ },
+
+ getDefaultSelectedItem: function(mimeTypesPopup, serverSentMime) {
+ // Exact match.
+ for (var i = 0; i < mimeTypesPopup.childNodes.length; i++) {
+ var item = mimeTypesPopup.childNodes[i];
+ if (item.mime && item.mime == serverSentMime)
+ return item;
+ }
+
+ function getMediaType(mime) {
+ return mime.split("/")[0].toLowerCase();
+ }
+
+ // Media type match.
+ for (var i = 0; i < mimeTypesPopup.childNodes.length; i++) {
+ var item = mimeTypesPopup.childNodes[i];
+ if (item.mime &&
+ (getMediaType(item.mime) == getMediaType(serverSentMime)))
+ return item;
+ }
+ // Fallback, select first entry.
+ return mimeTypesPopup.firstChild;
+ },
+
+ init: function OIBDO_init(event) {
+
+ // The Unknown Content Type dialog can have two different layouts.
+ // Under some conditions (executables, ...), the dialog only shows
+ // the save button. In that case the layout is modified in order to
+ // show the radio button for selecting the mime type.
+ if (dialog.dialogElement("normalBox").collapsed) {
+ document.getElementById("normalBox").collapsed = false;
+ document.getElementById("mode").firstChild.collapsed = true;
+
+ // restore button labels
+ document.documentElement.mStrBundle.GetStringFromName("button-accept");
+ var docEl = document.documentElement;
+ docEl.getButton("accept").label = docEl.mStrBundle.GetStringFromName("button-accept");
+ docEl.getButton("cancel").label = docEl.mStrBundle.GetStringFromName("button-cancel");
+
+ document.getElementById("rememberChoice").collapsed = true;
+ }
+
+ document.documentElement.setAttribute('ondialogaccept',
+ 'if(OIB_DownloadOverlay.dialogAccepted()) {' +
+ ' return OIB_DownloadOverlay.dialogAcceptRetVal;' +
+ '} else {' +
+ document.documentElement.getAttribute('ondialogaccept') +
+ '}');
+
+ // disable the remember choice label, as choice remembering
+ // is not implemented yet for open in browser.
+ if (!document.getElementById("rememberChoice").disabled) {
+ function modeCmd(event) {
+ if (event.target.localName != "radio")
+ return;
+
+ var oibRadio = document.getElementById("openInBrowser");
+ var rememberChoice = document.getElementById("rememberChoice");
+ rememberChoice.disabled = (event.target == oibRadio);
+ }
+ document.getElementById("mode").addEventListener("command", modeCmd, false);
+ }
+
+ var mimeTypesPopup = document.getElementById("mimeTypesPopup");
+
+ var downloadedDocumentUri = dialog.mLauncher.source;
+ OpenInBrowser.populateMenu(mimeTypesPopup, downloadedDocumentUri);
+
+ var serverSentMime = dialog.mLauncher.MIMEInfo.MIMEType;
+
+ var selectedItem = this.getDefaultSelectedItem(mimeTypesPopup, serverSentMime);
+ document.getElementById('mimeTypesMenu').selectedItem = selectedItem;
+
+ // Insert the server sent MIME menu item.
+ if (!/^http/.test(downloadedDocumentUri.scheme))
+ return;
+ var item = document.createElement("menuitem");
+ var serverSentMimeLabel = OpenInBrowser.strings
+ .getString("ServerSentMimeLabel");
+ item.setAttribute("label", serverSentMimeLabel);
+ var serverSentMimeTooltip = OpenInBrowser.strings.getFormattedString(
+ "ServerSentMimeTooltip", [serverSentMime]);
+ item.setAttribute("tooltiptext", serverSentMimeTooltip);
+
+ item.mime = serverSentMime;
+ var mimeSeparator = document.getElementById(OpenInBrowser.SEPARATOR_ID);
+ mimeTypesPopup.insertBefore(item, mimeSeparator);
+ },
+
+ onMimeTypeChange: function(event) {
+ var isOther = event.target.mime == OpenInBrowser.OTHER_MIME;
+ var otherText = document.getElementById("mimeOtherText");
+
+ document.getElementById("mimeOtherText");
+ otherText.hidden = !isOther;
+ document.getElementById("mode").selectedItem =
+ document.getElementById("openInBrowser");
+ if (isOther) {
+ otherText.focus();
+ }
+ window.sizeToContent();
+ }
+}
+
+window.addEventListener('load', function init() {
+ OIB_DownloadOverlay.init();
+}, false);
57 chrome/content/unknownContentTypeOverlay.xul
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.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 the Open in Browser extension.
+ -
+ - The Initial Developer of the Original Code is
+ - Sylvain Pasche <sylvain.pasche@gmail.com>.
+ - Portions created by the Initial Developer are Copyright (C) 2009
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ -
+ - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE window [
+<!ENTITY % openInBrowserDTD SYSTEM "chrome://openinbrowser/locale/openInBrowser.dtd">
+%openInBrowserDTD;
+]>
+
+<overlay id="openInBrowserDownloadOverlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/x-javascript"
+ src="chrome://openinbrowser/content/openInBrowser.js"/>
+ <script type="application/x-javascript"
+ src="chrome://openinbrowser/content/unknownContentTypeOverlay.js"/>
+
+ <dialog id="unknownContentType">
+ <stringbundle id="strings_openInBrowser" src="chrome://openInBrowser/locale/openInBrowser.properties"/>
+ <commandset>
+ <command id="cmd_mimeTypeChange" oncommand="OIB_DownloadOverlay.onMimeTypeChange(event)"/>
+ </commandset>
+ </dialog>
+
+ <radiogroup id="mode">
+ <hbox insertbefore="save">
+ <radio id="openInBrowser" label="&openAs.label;" accesskey="&openAs.accesskey;"/>
+ <vbox>
+ <menulist id="mimeTypesMenu">
+ <menupopup command="cmd_mimeTypeChange" id="mimeTypesPopup"/>
+ </menulist>
+ <textbox id="mimeOtherText" hidden="true" flex="1"/>
+ </vbox>
+ </hbox>
+ </radiogroup>
+</overlay>
4 chrome/locale/de-DE/openInBrowser.dtd
@@ -0,0 +1,4 @@
+<!ENTITY openAs.label "Öffnen in Browser als ">
+<!ENTITY openAs.accesskey "b">
+<!ENTITY viewAs.label "Ansehen als">
+<!ENTITY viewAs.accesskey "a">
17 chrome/locale/de-DE/openInBrowser.properties
@@ -0,0 +1,17 @@
+SelectMimeType=Wähle andere MIME
+InvalidMimeType="%S" ist kein gültige MIME
+ServerSentMimeLabel=Server gesendete MIME
+ServerSentMimeTooltip=MIME: %S
+
+view-source.label=Seitenquelltext
+view-source.accesskey=s
+other.label=Andere…
+other.accesskey=a
+text/plain.label=Text
+text/plain.accesskey=t
+text/html.label=Webseite
+text/html.accesskey=w
+text/xml.label=XML
+text/xml.accesskey=x
+image/jpeg.label=Grafik
+image/jpeg.accesskey=i
4 chrome/locale/en-US/openInBrowser.dtd
@@ -0,0 +1,4 @@
+<!ENTITY openAs.label "Open in browser as ">
+<!ENTITY openAs.accesskey "p">
+<!ENTITY viewAs.label "View as">
+<!ENTITY viewAs.accesskey "v">
17 chrome/locale/en-US/openInBrowser.properties
@@ -0,0 +1,17 @@
+SelectMimeType=Select other MIME type
+InvalidMimeType="%S" is not a valid MIME type
+ServerSentMimeLabel=Server sent MIME
+ServerSentMimeTooltip=MIME: %S
+
+view-source.label=Page Source
+view-source.accesskey=s
+other.label=Other…
+other.accesskey=o
+text/plain.label=Text
+text/plain.accesskey=t
+text/html.label=Web Page
+text/html.accesskey=w
+text/xml.label=XML
+text/xml.accesskey=x
+image/jpeg.label=Image
+image/jpeg.accesskey=i
4 chrome/locale/fr/openInBrowser.dtd
@@ -0,0 +1,4 @@
+<!ENTITY openAs.label "Ouvrir dans le navigateur en tant que ">
+<!ENTITY openAs.accesskey "o">
+<!ENTITY viewAs.label "Voir en tant que">
+<!ENTITY viewAs.accesskey "v">
17 chrome/locale/fr/openInBrowser.properties
@@ -0,0 +1,17 @@
+SelectMimeType=Choisir un autre type MIME
+InvalidMimeType="%S" n'est pas un type MIME valide
+ServerSentMimeLabel=MIME du serveur
+ServerSentMimeTooltip=MIME: %S
+
+view-source.label=Page Source
+view-source.accesskey=s
+other.label=Autre…
+other.accesskey=a
+text/plain.label=Texte
+text/plain.accesskey=t
+text/html.label=Page Web
+text/html.accesskey=w
+text/xml.label=XML
+text/xml.accesskey=x
+image/jpeg.label=Image
+image/jpeg.accesskey=i
4 chrome/locale/sv-SE/openInBrowser.dtd
@@ -0,0 +1,4 @@
+<!ENTITY openAs.label "Öppna i webbläsaren som ">
+<!ENTITY openAs.accesskey "p">
+<!ENTITY viewAs.label "Visa som">
+<!ENTITY viewAs.accesskey "v">
17 chrome/locale/sv-SE/openInBrowser.properties
@@ -0,0 +1,17 @@
+SelectMimeType=Välj en annan MIME-typ
+InvalidMimeType="%S" är inte en giltig MIME-typ
+ServerSentMimeLabel=Serversänt MIME
+ServerSentMimeTooltip=MIME: %S
+
+view-source.label=Sidkällkod
+view-source.accesskey=s
+other.label=Annat…
+other.accesskey=n
+text/plain.label=Text
+text/plain.accesskey=t
+text/html.label=Webbsida
+text/html.accesskey=w
+text/xml.label=XML
+text/xml.accesskey=x
+image/jpeg.label=Bild
+image/jpeg.accesskey=i
172 components/OpenInBrowser.js
@@ -0,0 +1,172 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.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 the Open in Browser extension.
+ *
+ * The Initial Developer of the Original Code is
+ * Sylvain Pasche <sylvain.pasche@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+const MAX_INTERCEPT_TIME = 10000;
+
+const EXAMINE_TOPIC = "http-on-examine-response";
+const EXAMINE_MERGED_TOPIC = "http-on-examine-merged-response";
+
+const DEBUG = false;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/**
+ * This object stores information which will be used for intercepting URL's
+ */
+function InterceptedInfo(url, mime) {
+ this.url = url;
+ this.mime = mime;
+}
+
+function debug(msg) {
+ if (DEBUG)
+ dump(msg + "\n");
+}
+
+/**
+ * The service
+ */
+function OpenInBrowser() {
+ this.wrappedJSObject = this;
+
+ this._interceptedInfos = [];
+};
+
+OpenInBrowser.prototype = {
+ classDescription: "Open in browser Javascript XPCOM Component",
+ classID: Components.ID("{14aa9340-c449-4956-a5f9-a52fb32f933d}"),
+ contractID: "@spasche.net/openinbrowser;1",
+
+ _clearCacheEntry: function OIB_clearCacheEntry(url) {
+ const cacheService = Cc["@mozilla.org/network/cache-service;1"].
+ getService(Ci.nsICacheService);
+ var httpCacheSession = cacheService.createSession("HTTP", 0, true);
+ httpCacheSession.doomEntriesIfExpired = false;
+ try {
+ var cacheKey = url.replace(/#.*$/, "");
+ var entry = httpCacheSession.openCacheEntry(cacheKey, Ci.nsICache.ACCESS_READ_WRITE, false);
+ entry.doom();
+ entry.close();
+ } catch (e) {
+ debug("Exception during cache clearing: " + e);
+ }
+ },
+
+ addInterceptInfo: function OIB_addInterceptInfo(url, mime) {
+ debug("Added intercept info " + url);
+
+ this._clearCacheEntry(url);
+ this._interceptedInfos.push(new InterceptedInfo(url, mime));
+ if (this._interceptedInfos.length == 1) {
+ this._startCapture();
+ }
+
+ // remove intercepted url's after a while in case the observer is not triggered
+ var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ var self = this;
+ var callback = {
+ notify: function notifyCallback(timer) {
+ self._removeInterceptedInfo(url);
+ }
+ }
+ timer.initWithCallback(callback, MAX_INTERCEPT_TIME, Ci.nsITimer.TYPE_ONE_SHOT);
+ },
+
+ _startCapture: function OIB_startCapture() {
+ debug("Start capture");
+ var observerService = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ observerService.addObserver(this, EXAMINE_TOPIC, false);
+ observerService.addObserver(this, EXAMINE_MERGED_TOPIC, false);
+ },
+
+ _stopCapture: function OIB_stopCapture() {
+ var observerService = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ observerService.removeObserver(this, EXAMINE_TOPIC);
+ observerService.removeObserver(this, EXAMINE_MERGED_TOPIC);
+ debug("capture stopped");
+ },
+
+ _getInterceptedInfo: function OIB_getInterceptedInfo(url) {
+ for (var i = 0; i < this._interceptedInfos.length; i++) {
+ if (this._interceptedInfos[i].url == url)
+ return this._interceptedInfos[i];
+ }
+ return null;
+ },
+
+ _removeInterceptedInfo: function OIB_removeInterceptedInfo(url) {
+ var index = -1;
+ for (var i = 0; i < this._interceptedInfos.length; i++) {
+ if (this._interceptedInfos[i].url == url) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) {
+ return;
+ }
+ this._interceptedInfos.splice(index, 1);
+ if (this._interceptedInfos.length == 0) {
+ this._stopCapture();
+ }
+ },
+
+ observe: function OIB_observe(aSubject, aTopic, aData) {
+
+ if (aTopic != EXAMINE_TOPIC && aTopic != EXAMINE_MERGED_TOPIC)
+ return;
+
+ var channel = aSubject.QueryInterface(Ci.nsIHttpChannel);
+ var url = channel.originalURI.spec;
+
+ debug("Observer inspecting: " + url);
+ var interceptedInfo = this._getInterceptedInfo(url);
+
+ if (!interceptedInfo)
+ return;
+
+ debug("Got a match " + url);
+ channel.contentType = interceptedInfo.mime;
+
+ // Disable content sniffers that could override the new mime type
+ channel.loadFlags &= ~Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS;
+
+ // drop content-disposition header
+ channel.setResponseHeader("Content-Disposition", "", false);
+ this._removeInterceptedInfo(url);
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
+};
+
+if (XPCOMUtils.generateNSGetFactory)
+ var NSGetFactory = XPCOMUtils.generateNSGetFactory([OpenInBrowser]);
+else
+ var NSGetModule = XPCOMUtils.generateNSGetModule([OpenInBrowser]);
59 install.rdf
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+
+ <em:id>openinbrowser@www.spasche.net</em:id>
+ <em:name>Open in Browser</em:name>
+ <em:version>1.10</em:version>
+ <em:description>Offers the possibility to display documents in browser window.</em:description>
+ <em:creator>Sylvain Pasche</em:creator>
+ <em:contributor>Stanimir Stamenkov</em:contributor>
+ <em:contributor>Richard Nonix</em:contributor>
+ <em:contributor>Mikael Hiort af Ornäs</em:contributor>
+ <!-- optional items -->
+ <em:homepageURL>http://www.spasche.net/openinbrowser/</em:homepageURL>
+
+ <em:localized>
+ <Description>
+ <em:locale>de-DE</em:locale>
+ <em:name>Open in Browser</em:name>
+ <em:description>Ermöglicht die Server gesendete MIME zu ändern und Dokumente direkt im Browserfenster zu betrachten.</em:description>
+ </Description>
+ </em:localized>
+ <em:localized>
+ <Description>
+ <em:locale>fr</em:locale>
+ <em:name>Ouvrir dans le navigateur</em:name>
+ <em:description>Offre la possibilité d'ouvrir les documents dans la fenêtre du navigateur.</em:description>
+ </Description>
+ </em:localized>
+ <em:localized>
+ <Description>
+ <em:locale>sv-SE</em:locale>
+ <em:name>Open in Browser</em:name>
+ <em:description>Ger dig möjlighet att öppna dokument i webbläsarfönstret.</em:description>
+ </Description>
+ </em:localized>
+
+ <!-- Firefox -->
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>3.0</em:minVersion>
+ <em:maxVersion>5.*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- SeaMonkey -->
+ <em:targetApplication>
+ <Description>
+ <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
+ <em:minVersion>2.0</em:minVersion>
+ <em:maxVersion>2.0.*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ </Description>
+</RDF>
1  tests/.htaccess
@@ -0,0 +1 @@
+AddType application/x-httpd-php .php
10 tests/README.txt
@@ -0,0 +1,10 @@
+This directory contains test for the extension.
+At this time, the tests have to be run manually.
+
+1) Open tests.html through HTTP with PHP enabled for mime.php. Follow the instructions.
+2) Open tests.html through file:/// and follow the instructions.
+
+
+Thanks to Christian Biesinger for mime.php.
+
+WARNING: do not expose mime.php publicly, it may not be XSS safe.
BIN  tests/TESTCASE.doc.gz
Binary file not shown
BIN  tests/files/image_png.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  tests/files/test.avi
@@ -0,0 +1 @@
+dummy content for test.avi
1  tests/files/test.py
@@ -0,0 +1 @@
+dummy content for test.py
1  tests/files/text_plain.txt
@@ -0,0 +1 @@
+dummy content for text_plain.txt
1  tests/files/text_with_binary_content.txt
@@ -0,0 +1 @@
+
1  tests/files/text_xml.xml
@@ -0,0 +1 @@
+<foo>dummy content</foo>
79 tests/mime.php
@@ -0,0 +1,79 @@
+<?php
+
+if (isset($_REQUEST['justshow']) && $_REQUEST['justshow']) {
+ unset($_REQUEST['justshow']);
+ $url = $PHP_SELF."?";
+ foreach ($_REQUEST as $key => $val) {
+ $url .= "$key=$val&";
+ }
+ echo "<p><a href=\"$url\">$url</a></p>";
+}
+
+else {
+
+if (isset($_REQUEST["do"]) && $_REQUEST["do"] == 1) {
+ if (isset($_REQUEST["type"]))
+ header("Content-Type: ".$_REQUEST["type"]);
+
+ $brokendisp = isset($_REQUEST["brokendisp"]) && $_REQUEST["brokendisp"] != "1";
+ $disp = "";
+ if (isset($_REQUEST["filename"]) && !$brokendisp)
+ $disp = "attachment";
+
+ if (isset($_REQUEST["disposition"]) && !$brokendisp)
+ $disp = $_REQUEST["disposition"];
+
+ if (isset($_REQUEST["filename"]) && $_REQUEST["filename"] != "") {
+ if (!$brokendisp)
+ $disp .= "; ";
+
+ $disp .= "filename=";
+ if ($_REQUEST["quote"])
+ $disp .= "\"";
+
+ $disp .= $_REQUEST["filename"];
+
+ if ($_REQUEST["quote"])
+ $disp .= "\"";
+ }
+
+ if ($disp != "")
+ header("Content-Disposition: ".$disp);
+
+ if (isset($_REQUEST["binary"]) && $_REQUEST["binary"] == 1) {
+ readfile("TESTCASE.doc.gz");
+ exit;
+ }
+}
+}
+?>
+<title>MIME General-purpose testcase</title>
+
+<h1>GET</h1>
+<form action="<?echo $_SERVER['PHP_SELF'];?>" method="GET">
+<input type="hidden" name="do" value="1">
+
+<table>
+
+
+<tr><td>MIME-Type to send, empty if unspecified</td><td> <input name="type" value="text/html"></td></tr>
+<tr><td>Content-Disposition to send, will not get sent if unspecified unless filename is specified</td><td>
+ <input name="disposition"> (if empty but filename specified, attachment will be used) </td></tr>
+
+<tr><td>Disposition Filename to send, none if unspecified </td><td><input name="filename"></td></tr>
+<tr><td colspan="2"><input type="checkbox" name="binary" value="1">Send binary content instead of textual</td></tr>
+<tr><td colspan="2"><input type="checkbox" name="quote" value="1" checked>Quote filename sent in Content-Disposition</td></tr>
+<tr><td colspan="2"><input type="checkbox" name="brokendisp" value="1">Send Content-Disposition without disposition, but with filename (Content-Disposition: filename="foo")</td></tr>
+
+</table>
+
+<button>Submit</button><br>
+<button name="justshow" value="1">Show url</button>
+
+</form>
+
+<?php
+if (isset($_REQUEST["txt"])) {
+ echo $_REQUEST["txt"];
+}
+?>
13 tests/open_after_timeout.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html lang="en">
+<head>
+ <script>
+ setTimeout(function() {
+ document.location = "mime.php?do=1&type=text%2Fplain&disposition=attachment";
+ }, 5000);
+ </script>
+</head>
+<body>
+ Redirecting...
+</body>
+</html>
139 tests/tests.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>OpenInBrowser testcases</title>
+ <script type="text/javascript">
+ onload = function() {
+ document.body.className = location.protocol.replace(":", "");
+ }
+ </script>
+ <style type="text/css">
+ body {
+ font-family: Corbel, sans;
+ margin: 1em 3em;
+ }
+ body.http > .file,
+ body.file > .http {
+ display: none;
+ }
+ </style>
+ </head>
+ <body>
+ <h2>Open In Browser extension testing.</h2>
+ <div class="http">
+ <p>
+ HTTP tests, follow the instructions below. You need PHP enabled for the
+ mime.php file in this same directory.
+ For the file tests, open this page using file:/// protocol.
+ </p>
+ <ul>
+ <li>Click on
+ <a href="mime.php?do=1&type=text%2Fplain&disposition=attachment">Text attachment</a>.
+ This should open a popup with entry "Text" selected.
+ Open page with that type and check it works as expected.
+ </li>
+ <li>
+ same with "Image"
+ <a href="mime.php?do=1&type=image%2Fjpeg&disposition=attachment">Image jpeg attachment</a>.
+ </li>
+ <li>
+ same with "Image"
+ <a href="mime.php?do=1&type=image%2Fpng&disposition=attachment">Image png attachment</a>.
+ </li>
+ <li>
+ same with "XML"
+ <a href="mime.php?do=1&type=text%2Fxml&disposition=attachment">XML attachment</a>.
+ </li>
+ <li>
+ same with "Web Page"
+ <a href="mime.php?do=1&type=text%2Fhtml&disposition=attachment">HTML attachment</a>.
+ </li>
+ <li>
+ Add a pref string "extensions.openinbrowser.additional_mimes" set to "foo/bar".
+ Clicking on the following links should select the foo/bar item.
+ <a href="mime.php?do=1&type=foo%2Fbar&disposition=attachment">foo/bar attachment</a>.
+ <a href="mime.php?do=1&type=foo%2Fbaz&disposition=attachment">foo/baz attachment</a>.
+ </li>
+ <li>
+ Remove the "extensions.openinbrowser.additional_mimes" preference.
+ Clicking on the following links should show the correct MIME type in the "Server Sent MIME (...)" label entry.
+ <a href="mime.php?do=1&type=foo%2Fbar&disposition=attachment">foo/bar attachment</a>.
+ <a href="mime.php?do=1&type=foo%2Fbaz&disposition=attachment">foo/baz attachment</a>.
+ </li>
+ <li>
+ Click on
+ <a href="mime.php?do=1&type=text%2Fplain&disposition=attachment">Text attachment</a>.
+ Selecting "Other..." and entering an invalid mime type "foo", should show an error and keep the dialog open.
+ Entering "text/plain" should open page as text in browser.
+ </li>
+ <li>
+ Open "View" > "View As", you should see Text, Web Page, Page Source, XML, Image, Other...
+ Check they are working as expected.
+ </li>
+ <li>
+ Click on "View" > "View As" > "Other...". entering an invalid mime type "foo", should show an error.
+ Entering "text/plain" should open current page as text in browser.
+ </li>
+ <li>
+ Non HTTP test, click on <a href="ftp://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/">this link</a>.
+ "View" > "View As" should contain only "Page Source". Check it is working.
+ </li>
+ <li>
+ Non HTTP test with the open with dialog, click on <a href="ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/3.0.11/win32/en-US/Firefox%20Setup%203.0.11.exe">this link</a>.
+ The dialog should show only "Page Source" in the list.
+ </li>
+ <li>
+ HTTPS test, open <a href="https://bugzilla.mozilla.org/">this link</a>. Should behave as other http pages.
+ </li>
+ <li>
+ Sniffing tests. Open <a href="files/text_with_binary_content.txt">this text file containing binary content</a>.
+ You should be able to open it as text in the browser.
+ </li>
+ <li>
+ Tab selection test: open <a href="mime.php?do=1&type=text%2Fplain&disposition=attachment">Text attachment</a>
+ in a background tab (middle click the link). Opening in browser as text should open
+ the content in the background tab, and not the current tab.
+ </li>
+ <li>
+ Tab selection test 2: open <a href="open_after_timeout.html">this page</a>.
+ Then open a new window (you have 5sec to do so). When the "Opening..." dialog appears, select to open in browser
+ as text. The content should be opened in original tab and not the new window.
+ </li>
+ </ul>
+
+ TODO:
+ Not possible to open the following url as text. Need to investigate
+ "http://releases.mozilla.org/pub/mozilla.org/firefox/releases/3.0/win32/en-US/Firefox%20Setup%203.0.exe"
+
+ </div>
+ <div class="file">
+ <p>
+ File tests, follow the instructions below.
+ For the HTTP tests, open this page using http:/// protocol.
+ </p>
+ <ul>
+ <li>
+ Open <a href="files/image_png.png">this image</a>. View > View As should
+ only display "Page Source". Check viewing that as "Page Source"
+ (should show binary data on Firefox 3.0, Firefox >= 3.5 still shows
+ the image for some reason).
+ </li>
+ <li>
+ Open
+ <a href="files/test.py">test.py</a>. You should only see "Page Source"
+ in the list (doesn't work on Mac, .py files are opened as text/plain).
+ </li>
+ <li>
+ <a href="files/test.avi">test.avi</a>
+ </li>
+ <li>
+ <a href="files/text_plain.txt">text_plain.txt</a>
+ </li>
+ <li>
+ <a href="files/text_xml.xml">text_xml.xml</a>
+ </li>
+ </ul>
+ </div>
+ </body>
+</html>

0 comments on commit 4566cba

Please sign in to comment.
Something went wrong with that request. Please try again.