From 3485424f6e72161aef139d9f5723cbd0760b38e2 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sun, 9 Jan 2011 15:36:10 -0500 Subject: [PATCH] Automagically grab form charset in ;S. --- common/content/bookmarks.js | 45 +++++++++++++++++++++++--------- common/content/commands.js | 2 +- common/content/statusline.js | 5 ++-- common/modules/bookmarkcache.jsm | 35 ++++++++++++++++++------- common/modules/javascript.jsm | 4 +-- common/modules/services.jsm | 1 + common/modules/util.jsm | 30 +++++++++++++++------ 7 files changed, 87 insertions(+), 35 deletions(-) diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js index b2304211..887187a7 100644 --- a/common/content/bookmarks.js +++ b/common/content/bookmarks.js @@ -58,7 +58,7 @@ var Bookmarks = Module("bookmarks", { add: function add(unfiled, title, url, keyword, tags, force) { // FIXME if (isObject(unfiled)) - var { unfiled, title, url, keyword, tags, post, force } = unfiled; + var { unfiled, title, url, keyword, tags, post, charset, force } = unfiled; try { let uri = util.createURI(url); @@ -82,13 +82,15 @@ var Bookmarks = Module("bookmarks", { if (!bmark) return false; + if (charset !== undefined) + bmark.charset = charset; if (post !== undefined) bmark.post = post; if (keyword) bmark.keyword = keyword; } catch (e) { - dactyl.log(e, 0); + util.reportError(e); return false; } @@ -102,10 +104,12 @@ var Bookmarks = Module("bookmarks", { * @param {Element} elem A form element for which to add a keyword. */ addSearchKeyword: function (elem) { - let [url, post] = util.parseForm(elem); + let [url, post, charset] = util.parseForm(elem); let options = { "-title": "Search " + elem.ownerDocument.title }; if (post != null) options["-post"] = post; + if (charset != null && charset !== "UTF-8") + options["-charset"] = charset; commandline.open(":", commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ", @@ -134,7 +138,7 @@ var Bookmarks = Module("bookmarks", { let extra = ""; if (title != url) extra = " (" + title + ")"; - this.add(true, title, url); + this.add({ unfiled: true, title: title, url: url }); dactyl.echomsg({ domains: [util.getHost(url)], message: "Added bookmark: " + url + extra }); } }, @@ -179,8 +183,10 @@ var Bookmarks = Module("bookmarks", { } ids.forEach(function (id) { let bmark = bookmarkcache.bookmarks[id]; - if (bmark) - PlacesUtils.tagging.untagURI(util.newURI(bmark.url), null); + if (bmark) { + PlacesUtils.tagging.untagURI(bmark.uri, null); + bmark.charset = null; + } services.bookmarks.removeItem(id); }); return ids.length; @@ -302,6 +308,7 @@ var Bookmarks = Module("bookmarks", { let [shortcutURL, postData] = PlacesUtils.getURLAndPostDataForKeyword(keyword); if (!shortcutURL) return [url, null]; + let bmark = bookmarkcache.keywords[keyword]; let data = window.unescape(postData || ""); if (/%s/i.test(shortcutURL) || /%s/i.test(data)) { @@ -309,17 +316,16 @@ var Bookmarks = Module("bookmarks", { var matches = shortcutURL.match(/^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/); if (matches) [, shortcutURL, charset] = matches; - else { + else try { charset = services.history.getCharsetForURI(util.newURI(shortcutURL)); } catch (e) {} - } - var encodedParam; if (charset) - encodedParam = escape(window.convertFromUnicode(charset, param)); + var encodedParam = escape(window.convertFromUnicode(charset, param)); else - encodedParam = encodeURIComponent(param); + encodedParam = bmark.encodeURIComponent(param); + shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param); if (/%s/i.test(data)) postData = window.getPostDataStream(data, param, encodedParam, "application/x-www-form-urlencoded"); @@ -443,6 +449,7 @@ var Bookmarks = Module("bookmarks", { force: args.bang, unfiled: false, keyword: args["-keyword"] || null, + charset: args["-charset"], post: args["-post"], tags: args["-tags"] || [], title: args["-title"] || (args.length === 0 ? buffer.title : null), @@ -470,7 +477,15 @@ var Bookmarks = Module("bookmarks", { } completion.bookmark(context, args["-tags"], { keyword: args["-keyword"], title: args["-title"] }); }, - options: [keyword, title, tags, post] + options: [keyword, title, tags, post, + { + names: ["-charset", "-c"], + description: "The character encoding of the bookmark", + type: CommandOption.STRING, + completer: function (context) completion.charset(context), + validator: Option.validateCompleter + } + ] }); commands.add(["bmarks"], @@ -547,14 +562,20 @@ var Bookmarks = Module("bookmarks", { let bmark = bmarks[0]; options["-title"] = bmark.title; + if (bmark.charset) + options["-charset"] = bmark.charset; if (bmark.keyword) options["-keyword"] = bmark.keyword; + if (bmark.post) + options["-post"] = bmark.post; if (bmark.tags.length > 0) options["-tags"] = bmark.tags.join(", "); } else { if (buffer.title != buffer.URL.spec) options["-title"] = buffer.title; + if (content.document.characterSet !== "UTF-8") + options["-charset"] = content.document.characterSet; } commandline.open(":", diff --git a/common/content/commands.js b/common/content/commands.js index 39b8f453..9b54f4d8 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -903,7 +903,7 @@ var Commands = Module("commands", { // we have a validator function if (typeof opt.validator == "function") { - if (opt.validator.call(this, arg, quoted) == false) { + if (opt.validator(arg, quoted) == false) { fail("Invalid argument for option: " + optname); if (complete) // Always true. complete.highlight(args.completeStart, count - 1, "SPELLCHECK"); diff --git a/common/content/statusline.js b/common/content/statusline.js index 2e0e6b1e..2bc9660b 100644 --- a/common/content/statusline.js +++ b/common/content/statusline.js @@ -232,9 +232,8 @@ var StatusLine = Module("statusline", { else if (progress < 1) { progress = Math.floor(progress * 20); progressStr = "[" - + "====================".substr(0, progress) - + ">" - + " ".substr(0, 19 - progress) + + "===================> " + .substr(20 - progress, 20) + "]"; } this.widgets.progress.value = progressStr; diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm index faa37313..3e1273d6 100644 --- a/common/modules/bookmarkcache.jsm +++ b/common/modules/bookmarkcache.jsm @@ -10,14 +10,25 @@ defineModule("bookmarkcache", { require: ["services", "storage", "util"] }); -var Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "id"); +var Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "charset", "id"); var Keyword = Struct("keyword", "title", "icon", "url"); Bookmark.defaultValue("icon", function () BookmarkCache.getFavicon(this.url)); +update(Bookmark.prototype, { + get extra() [ + ["keyword", this.keyword, "Keyword"], + ["tags", this.tags.join(", "), "Tag"] + ].filter(function (item) item[1]), + + get uri() util.newURI(this.url), + + encodeURIComponent: function _encodeURIComponent(str) { + if (!this.charset || this.charset === "UTF-8") + return encodeURIComponent(str); + let conv = services.CharsetConv(this.charset); + return escape(conv.ConvertFromUnicode(str) + conv.Finish()); + } +}) Bookmark.setter = function (key, func) this.prototype.__defineSetter__(key, func); -Bookmark.prototype.__defineGetter__("extra", function () [ - ["keyword", this.keyword, "Keyword"], - ["tags", this.tags.join(", "), "Tag"] - ].filter(function (item) item[1])); Bookmark.setter("url", function (val) { let tags = this.tags; this.tags = null; @@ -26,6 +37,7 @@ Bookmark.setter("url", function (val) { }); Bookmark.setter("title", function (val) { services.bookmarks.setItemTitle(this.id, val); }); Bookmark.setter("post", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.POST, val); }); +Bookmark.setter("charset", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.CHARSET, val); }); Bookmark.setter("keyword", function (val) { services.bookmarks.setKeywordForBookmark(this.id, val); }); Bookmark.setter("tags", function (val) { services.tagging.untagURI(this.uri, null); @@ -37,6 +49,7 @@ var name = "bookmark-cache"; var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { POST: "bookmarkProperties/POSTData", + CHARSET: "dactyl/charset", init: function init() { services.bookmarks.addObserver(this, false); @@ -68,12 +81,14 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { let keyword = services.bookmarks.getKeywordForBookmark(node.itemId); let tags = services.tagging.getTagsForURI(uri, {}) || []; let post = BookmarkCache.getAnnotation(node.itemId, this.POST); - return Bookmark(node.uri, node.title, node.icon && node.icon.spec, post, keyword, tags, node.itemId); + let charset = BookmarkCache.getAnnotation(node.itemId, this.CHARSET); + return Bookmark(node.uri, node.title, node.icon && node.icon.spec, post, keyword, tags, charset, node.itemId); }, - annotate: function (id, key, val) { + annotate: function (id, key, val, timespan) { if (val) - services.annotation.setItemAnnotation(id, key, val, 0, services.annotation.EXPIRE_NEVER); + services.annotation.setItemAnnotation(id, key, val, 0, + timespan || services.annotation.EXPIRE_NEVER); else if (services.annotation.itemHasAnnotation(id, key)) services.annotation.removeItemAnnotation(id, key); }, @@ -159,7 +174,9 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { onItemChanged: function onItemChanged(itemId, property, isAnnotation, value) { if (isAnnotation) if (property === this.POST) - [property, value] = ["post", BookmarkCache.getAnnotation(itemId, this.POST)]; + [property, value] = ["post", BookmarkCache.getAnnotation(itemId, property)]; + else if (property === this.CHARSET) + [property, value] = ["charset", BookmarkCache.getAnnotation(itemId, property)]; else return; diff --git a/common/modules/javascript.jsm b/common/modules/javascript.jsm index d48b4659..2dd6c8cf 100644 --- a/common/modules/javascript.jsm +++ b/common/modules/javascript.jsm @@ -624,8 +624,8 @@ var JavaScript = Module("javascript", { "Uint16Array", "Uint32Array", "Uint8Array", "XML", "XMLHttpProgressEvent", "XMLList", "XMLSerializer", "XPCNativeWrapper", "XPCSafeJSWrapper", "XULControllers", "decodeURI", "decodeURIComponent", - "encodeURI", "encodeURIComponent", "eval", "isFinite", "isNaN", - "isXMLName", "parseFloat", "parseInt", "undefined", "uneval" + "encodeURI", "encodeURIComponent", "escape", "eval", "isFinite", "isNaN", + "isXMLName", "parseFloat", "parseInt", "undefined", "unescape", "uneval" ].concat([k.substr(6) for (k in keys(Ci)) if (/^nsIDOM/.test(k))]) .concat([k.substr(3) for (k in keys(Ci)) if (/^nsI/.test(k))]) .concat(this.magicalNames) diff --git a/common/modules/services.jsm b/common/modules/services.jsm index 7d4138f4..8cd60af9 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -64,6 +64,7 @@ var Services = Module("Services", { this.add("windowWatcher", "@mozilla.org/embedcomp/window-watcher;1", Ci.nsIWindowWatcher); this.add("zipReader", "@mozilla.org/libjar/zip-reader-cache;1", Ci.nsIZipReaderCache); + this.addClass("CharsetConv", "@mozilla.org/intl/scriptableunicodeconverter", Ci.nsIScriptableUnicodeConverter, "charset"); this.addClass("File", "@mozilla.org/file/local;1", Ci.nsILocalFile); this.addClass("file:", "@mozilla.org/network/protocol;1?name=file", Ci.nsIFileProtocolHandler); this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 149e6627..6fe6c639 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1070,21 +1070,35 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), // Nuances gleaned from browser.jar/content/browser/browser.js parseForm: function parseForm(field) { function encode(name, value, param) { - if (param) - value = value + "%s"; - if (post) - return name + "=" + value; - return encodeURIComponent(name) + "=" + (param ? value : encodeURIComponent(value)); + param = param ? "%s" : ""; + if (post) // Seems wrong. + return encodeComponent(name + "=" + value + param); + return encodeComponent(name) + "=" + encodeComponent(value) + param; } let form = field.form; let doc = form.ownerDocument; - let charset = doc.charset; + + let charset = doc.characterSet; + let converter = services.CharsetConv(charset); + for each (let cs in form.acceptCharset.split(/\s*,\s*|\s+/)) { + let c = services.CharsetConv(cs); + if (c) { + converter = services.CharsetConv(cs); + charset = cs; + } + } + let uri = util.newURI(doc.baseURI.replace(/\?.*/, ""), charset); let url = util.newURI(form.action, charset, uri).spec; let post = form.method.toUpperCase() == "POST"; + let encodeComponent = encodeURIComponent; + if (charset !== "UTF-8") + encodeComponent = function encodeComponent(str) + escape(converter.ConvertFromUnicode(str) + converter.Finish()); + let elems = []; if (field instanceof Ci.nsIDOMHTMLInputElement && field.type == "submit") elems.push(encode(field.name, field.value)); @@ -1101,8 +1115,8 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } } if (post) - return [url, elems.map(encodeURIComponent).join('&'), elems]; - return [url + "?" + elems.join('&'), null]; + return [url, elems.join('&'), elems, charset]; + return [url + "?" + elems.join('&'), null, charset]; }, /**