Utils: Added parseHtml(), extracted from the feed-specific parseRemoteDocument().

This commit is contained in:
satyr 2010-03-20 06:57:26 +09:00
Родитель 2a0f4f1090
Коммит 9c771324d8
2 изменённых файлов: 81 добавлений и 103 удалений

Просмотреть файл

@ -1,112 +1,42 @@
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
var Utils = {
__proto__: (Cu.import("resource://ubiquity/modules/utils.js", null)
.Utils),
__proto__: Cu.import("resource://ubiquity/modules/utils.js", null).Utils,
__globalObject: this,
// Just like the standard Utils.uri, only if we get a malformed URI
// error, we'll try re-evaluating the string using a base URI of the
// feed making the call.
uri: function uri(obj) {
if (typeof obj !== "string") return this.__proto__.uri(obj);
try {
return this.__proto__.uri(obj);
} catch (e if e.result === Cr.NS_ERROR_MALFORMED_URI) {
} catch (e if (typeof obj !== "string" &&
e.result === Cr.NS_ERROR_MALFORMED_URI)) {
return this.__proto__.uri({uri: obj, base: feed.id});
}
}
};
Utils.url = Utils.uri;
Utils.ajaxGet = function ajaxGet(url, callbackFunction, failureFunction) {
jQuery.ajax({
url: url,
success: callbackFunction,
error: failureFunction
});
};
Utils.parseRemoteDocument = function parseRemoteDocument(remoteUrl,
postParams,
successCallback,
errorCallback) {
// based on code from http://mxr.mozilla.org/mozilla/source/browser/components/microsummaries/src/nsMicrosummaryService.js
var rootElement = null;
var iframe = null;
var parseHandler = {
handleEvent: function handleEvent(event) {
event.target.removeEventListener("DOMContentLoaded", this, false);
var doc = iframe.contentDocument;
rootElement.removeChild(iframe);
successCallback(doc);
}
};
function parseHtml(htmlText) {
var window = Utils.currentChromeWindow;
var document = window.document;
rootElement = document.documentElement;
iframe = document.createElement('iframe');
iframe.setAttribute("collapsed", true);
// secure iframe against untrusted content
iframe.setAttribute("type", "content");
// needed to create a docshell
rootElement.appendChild(iframe);
// stop loading about:blank (not needed, and weird things could happpen apparently)
iframe.docShell.QueryInterface(Ci.nsIWebNavigation)
.stop(Ci.nsIWebNavigation.STOP_NETWORK);
// turn off unneeded/unwanted/bad things
iframe.docShell.allowJavascript = false;
iframe.docShell.allowAuth = false;
iframe.docShell.allowPlugins = false;
iframe.docShell.allowMetaRedirects = false;
iframe.docShell.allowSubframes = false;
iframe.docShell.allowImages = false;
// Convert the HTML text into an input stream.
var converter = (Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter));
converter.charset = "UTF-8";
var stream = converter.convertToInputStream(htmlText);
// Set up a channel to load the input stream.
var channel = (Cc["@mozilla.org/network/input-stream-channel;1"]
.createInstance(Ci.nsIInputStreamChannel));
channel.setURI(Utils.url(remoteUrl));
channel.contentStream = stream;
// Load in the background so we don't trigger web progress listeners.
channel.QueryInterface(Ci.nsIRequest)
.loadFlags |= Ci.nsIRequest.LOAD_BACKGROUND;
// need to specify content type, so user isn't prompted to download "unknown" file type
var baseChannel = channel.QueryInterface(Ci.nsIChannel);
baseChannel.contentType = "text/html";
// this will always be UTF-8 thanks to XMLHttpRequest and nsIScriptableUnicodeConverter
baseChannel.contentCharset = "UTF-8";
// background loads don't fire "load" events, listen for DOMContentLoaded instead
iframe.addEventListener("DOMContentLoaded", parseHandler, true);
var uriLoader = Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader);
uriLoader.openURI(channel, true, iframe.docShell);
}
Utils.ajaxGet = function ajaxGet(url, callbackFunction, failureFunction) (
jQuery.ajax({url: url, success: callbackFunction, error: failureFunction}));
Utils.parseRemoteDocument = function parseRemoteDocument(
remoteUrl, postParams, successCallback, errorCallback) {
var ajaxOptions = {
url: remoteUrl,
type: "GET",
dataType: "text",
success: parseHtml,
success: function pRD_success(htm) { Utils.parseDocument(htm, callback) },
error: errorCallback,
};
if (postParams) {
ajaxOptions.type = "POST";
ajaxOptions.data = postParams;
}
jQuery.ajax(ajaxOptions);
return jQuery.ajax(ajaxOptions);
};
var CmdUtils = {
__proto__: (Cu.import("resource://ubiquity/modules/cmdutils.js", null)
.CmdUtils),
__proto__:
Cu.import("resource://ubiquity/modules/cmdutils.js", null).CmdUtils,
__globalObject: this,
__nextId: 0,
};

Просмотреть файл

@ -86,22 +86,22 @@ for each (let f in [
// === {{{ Utils.Application }}} ===
// Shortcut to [[https://developer.mozilla.org/en/FUEL/Application]].
function Application()
Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication),
Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication),
// === {{{ Utils.ConsoleService }}} ===
// Shortcut to {{{nsIConsoleService}}}.
function ConsoleService()
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService),
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService),
// === {{{ Utils.ExtensionManager }}} ===
// Shortcut to {{{nsIExtensionManager}}}.
function ExtensionManager()
Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager),
Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager),
// === {{{ Utils.IOService }}} ===
// Shortcut to {{{nsIIOService}}}.
function IOService()
Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
// === {{{ Utils.UnicodeConverter }}} ===
// Shortcut to {{{nsIScriptableUnicodeConverter}}}.
@ -129,20 +129,20 @@ for each (let f in [
// The chrome application name found in {{{nsIXULAppInfo}}}.
// Example values are {{{"Firefox"}}}, {{{"Songbird"}}}, {{{"Thunderbird"}}}.
function appName()
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).name,
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).name,
// === {{{ Utils.appWindowType }}} ===
// The name of "main" application windows for the chrome application.
// Example values are {{{"navigator:browser"}}} for Firefox/Thunderbird
// and {{{"Songbird:Main"}}} for Songbird.
function appWindowType()
({Songbird: "Songbird:Main"})[Utils.appName] || "navigator:browser",
({Songbird: "Songbird:Main"})[Utils.appName] || "navigator:browser",
// === {{{ Utils.OS }}} ===
// The platform name found in {{{nsIXULRuntime}}}.
// See [[https://developer.mozilla.org/en/OS_TARGET]].
function OS()
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS,
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS,
]) defineLazyProperty(Utils, f);
@ -178,17 +178,17 @@ function log(what) {
try { return Utils.json.encode(o) } finally { return o }
}
var lead = !formatting ? log_pp(args.shift()) :
args.shift().replace(/%[sdifo]/g, function log_format($) {
if (!args.length) return $;
var a = args.shift();
switch ($) {
case "%s": return a;
case "%d":
case "%i": return parseInt(a);
case "%f": return parseFloat(a);
}
return log_pp(a);
});
args.shift().replace(/%[sdifo]/g, function log_format($) {
if (!args.length) return $;
var a = args.shift();
switch ($) {
case "%s": return a;
case "%d":
case "%i": return parseInt(a);
case "%f": return parseFloat(a);
}
return log_pp(a);
});
Utils.reportInfo(
args.reduce(function log_acc(msg, arg) msg + " " + log_pp(arg), lead));
}
@ -574,9 +574,57 @@ function getLocalUrl(url, charset) {
return req.responseText;
}
// ==={{{ Utils.parseHtml(htmlText, callback) }}}===
// Parses {{{htmlText}}} to a DOM document and passes it to {{{callback}}}.
function parseHtml(htmlText, callback) {
var {document} = Utils.currentChromeWindow;
var iframe = document.createElement("iframe");
iframe.setAttribute("collapsed", true); // hide
iframe.setAttribute("type", "content"); // secure
// needed to create a docshell
document.documentElement.appendChild(iframe);
var {docShell} = iframe;
docShell.QueryInterface(Ci.nsIWebNavigation)
.stop(Ci.nsIWebNavigation.STOP_NETWORK); // stop loading about:blank
// turn off unneeded/unwanted/bad things
(docShell.allowJavascript =
docShell.allowAuth =
docShell.allowPlugins =
docShell.allowMetaRedirects =
docShell.allowSubframes =
docShell.allowImages = false);
// Convert the HTML text into an input stream.
var converter = Utils.UnicodeConverter;
converter.charset = "UTF-8";
var stream = converter.convertToInputStream(htmlText);
// Set up a channel to load the input stream.
var channel = (Cc["@mozilla.org/network/input-stream-channel;1"]
.createInstance(Ci.nsIInputStreamChannel));
channel.setURI(Utils.IOService.newURI("about:blank", null, null));
channel.contentStream = stream;
// Load in the background so we don't trigger web progress listeners.
channel.QueryInterface(Ci.nsIRequest)
.loadFlags |= Ci.nsIRequest.LOAD_BACKGROUND;
// need to specify content type,
// so user isn't prompted to download "unknown" file type
var baseChannel = channel.QueryInterface(Ci.nsIChannel);
baseChannel.contentType = "text/html";
baseChannel.contentCharset = "UTF-8";
// background loads don't fire "load" events
listenOnce(iframe, "DOMContentLoaded", function onParsed() {
var doc = iframe.contentDocument;
iframe.parentNode.removeChild(iframe);
callback(doc);
}, true);
Cc["@mozilla.org/uriloader;1"].getService(Ci.nsIURILoader)
.openURI(channel, true, docShell);
}
// ** {{{ Utils.trim(str) }}} **
// **//Deprecated.//** Use native {{{trim()}}} instead.
Utils.trim = String.trim;
// === {{{ Utils.sortBy(array, key, descending = false) }}} ===
@ -868,7 +916,7 @@ function notify(label, value, image, priority, buttons, target) {
}
// === {{{ Utils.listenOnce(element, eventType, listener, useCapture) }}} ===
//
//
// Same as [[https://developer.mozilla.org/en/DOM/element.addEventListener]],
// except that the {{{listener}}} will be automatically removed on its
// first execution.
@ -1154,7 +1202,7 @@ for (let n in gClipboard.flavors) let (name = n) {
}
defineLazyProperty(
gClipboard, function service()
Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard));
Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard));
// == {{{ Utils.history }}} ==
// Contains functions that make it easy to access
@ -1321,7 +1369,7 @@ Utils.gist = {
//
// {{{id}}} is an optional number that specifies target Gist.
// The user needs to be the owner of that Gist.
paste: function gist_paste(files, id) {
paste: function gist_paste(files, id) {
var data = id ? ["_method=put"] : [], i = 1;
for (let name in files) {
for (let [k, v] in new Iterator({