aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/clipboard.js128
-rw-r--r--lib/main.js28
-rw-r--r--lib/persistent-page-mod.js56
-rw-r--r--tests/test-util.js2
4 files changed, 212 insertions, 2 deletions
diff --git a/lib/clipboard.js b/lib/clipboard.js
new file mode 100644
index 0000000..e5b4ac8
--- /dev/null
+++ b/lib/clipboard.js
@@ -0,0 +1,128 @@
+// Released under the MIT/X11 license
+// http://www.opensource.org/licenses/mit-license.php
+
+/**
+ * returns content of the system clipboard
+ * @return string with the content of the clipboard or "" if empty.
+ * originally from
+ * https://developer.mozilla.org/en/Using_the_Clipboard
+ *
+ */
+// TODO to-be-replaced by
+// var contents = jetpack.clipboard.get();
+// http://hsivonen.iki.fi/kesakoodi/clipboard/
+// https://wiki.mozilla.org/Labs/Jetpack/JEP/10
+
+function getClipboard() {
+ const kClipboardContractID = "@mozilla.org/widget/clipboard;1";
+ const kClipboardIID = Ci.nsIClipboard;
+ var clip = Cc[kClipboardContractID].getService(kClipboardIID);
+ if (!clip) {
+ throw new Error("No access to the clipboard!");
+ }
+ return clip;
+}
+
+function createTransferable() {
+ const kTransferableContractID = "@mozilla.org/widget/transferable;1";
+ const kTransferableIID = Ci.nsITransferable
+ var trans = Cc[kTransferableContractID].createInstance(kTransferableIID);
+ if (!trans) {
+ throw new Error("No access to the transfer object during the set of clipboard!");
+ }
+ return trans;
+}
+
+var getMethod = exports.get = function getMethod( flavor ) {
+ var pastetext = "", mimeType = "", stuff = {};
+ var len = 0, clipId = 0, clip = {}, trans = {};
+
+ // flavor argument is optional
+ if (flavor === undefined) {
+ flavor = "plain";
+ }
+
+ if (flavor === "plain") {
+ mimeType = "text/unicode";
+ } else if (favor === "html") {
+ mimeType = "text/html";
+ } else {
+ throw new Error("Unsupported flavor '" + flavor + "'!");
+ }
+
+ clip = getClipboard();
+
+ trans = createTransferable();
+
+ trans.addDataFlavor(mimeType);
+ clip.getData(trans, clip.kGlobalClipboard);
+
+ var str = {};
+ var strLength = {};
+
+ trans.getTransferData(mimeType, str, strLength);
+
+ if (str) {
+ str = str.value.QueryInterface(Ci.nsISupportsString);
+ pastetext = str.data.substring(0, strLength.value / 2);
+ }
+ return pastetext;
+};
+
+var setMethod = exports.set = function setMethod(content, flavor) {
+ var mimeType = "", stuff = {};
+ var len = 0, clipId = 0, clip = {}, trans = {};
+
+ // flavor argument is optional
+ if (flavor === undefined) {
+ flavor = "plain";
+ }
+
+ if (flavor === "plain") {
+ mimeType = "text/unicode";
+ } else if (favor === "html") {
+ mimeType = "text/html";
+ } else {
+ throw new Error("Unsupported flavor '" + flavor + "'!");
+ }
+
+ stuff = Cc["@mozilla.org/supports-string;1"].
+ createInstance(Ci.nsISupportsString);
+ if (!stuff) {
+ return false;
+ }
+ stuff.data = content;
+ len = content.length * 2;
+
+ clip = getClipboard();
+
+ trans = createTransferable();
+
+ trans.addDataFlavor(mimeType);
+ trans.setTransferData(mimeType, stuff, content.length * 2);
+
+ clip.setData(trans, null, clip.kGlobalClipboard);
+};
+
+function createSupportsWString() {
+ return Cc["@mozilla.org/supports-wstring;1"].
+ createInstance(Ci.nsISupportsWString);
+}
+
+var flavorsMethod = exports.getCurrentFlavors = function flavorsMethod() {
+ // currently the only possible flavors in Jetpack-prototype are "plain" and
+ // "html", i.e., "text/plain" (or text/unicode?) and "text/html" (or
+ // application/xml+xhtml?)
+ var possibleTypes = {
+ "text/unicode": "plain",
+ "text/plain": "plain",
+ "text/html": "html"
+ };
+ var flavourArray = createSupportsArray();
+
+ for (mime in possibleTypes) {
+ var kSuppString = createSupportsWString();
+ kSuppString.data = mime;
+ flavourArray.AppendElement(kSuppString);
+ }
+};
diff --git a/lib/main.js b/lib/main.js
index eca533e..365d445 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -58,6 +58,18 @@ var bottomRow = {};
// /////////////////////////////////////////////////////////////////////////////
+function doReplace(window) {
+ for (var node in require("text-node").iterator(window.document.body)) {
+ var origText = node.textContent;
+ var newText = origText.replace("friend", "acquaintance", "g");
+ newText = newText.replace("Friend", "Acquaintance", "g");
+ if (newText != origText) {
+ node.textContent = newText;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
let config = {};
config.matches = [
"https://bugzilla.redhat.com/show_bug.cgi",
@@ -89,4 +101,18 @@ util.loadJSON(jetpack.storage.settings.JSONURL, function(parsedData) {
};
jetpack.pageMods.add(callback, config);
-}, this); \ No newline at end of file
+}, this);
+
+////////////////////////////////////////////////////////////////
+
+// FIXME What are the real values of options and callbacks parameters?
+exports.main = function main(options, callbacks) {
+ require("tab-browser").whenContentLoaded(
+ function(window) {
+ if (window.location.protocol == "http:" &&
+ // options.matches
+ window.location.host.match(/facebook.com$/))
+ require("persistent-page-mod").register(window, doReplace);
+ }
+ );
+};s \ No newline at end of file
diff --git a/lib/persistent-page-mod.js b/lib/persistent-page-mod.js
new file mode 100644
index 0000000..5c00a8f
--- /dev/null
+++ b/lib/persistent-page-mod.js
@@ -0,0 +1,56 @@
+var timer = require("timer");
+
+function PersistentPageMod(window, callback) {
+ memory.track(this);
+ this.window = window;
+ this.callback = callback;
+ this.window.addEventListener("unload", this, false);
+ this.window.addEventListener("DOMSubtreeModified", this, false);
+ this.doMod();
+ require("unload-2").ensure(this);
+}
+
+PersistentPageMod.prototype = {
+ REPLACE_DELAY: 100,
+ doMod: function doMod() {
+ try {
+ this.callback.call(undefined, this.window);
+ } catch (e) {
+ console.exception(e);
+ }
+ this.timerID = null;
+ },
+ handleEvent: function handleEvent(event) {
+ switch (event.type) {
+ case "unload":
+ if (event.target == this.window.document)
+ this.unload();
+ break;
+ case "DOMSubtreeModified":
+ if (this.timerID == null) {
+ // Wait a bit to do the replacing. Otherwise, we just get called
+ // tons of times in a tiny period and end up hanging the browser
+ // for a while.
+ var self = this;
+ this.timerID = timer.setTimeout(function() self.doMod(),
+ this.REPLACE_DELAY);
+ }
+ break;
+ }
+ },
+ unload: function unload() {
+ if (this.timerID != null) {
+ timer.clearTimeout(this.timerID);
+ this.timerID = null;
+ }
+ this.window.removeEventListener("DOMSubtreeModified", this, false);
+ this.window.removeEventListener("unload", this, false);
+ }
+};
+
+require("errors").catchAndLogProps(PersistentPageMod.prototype,
+ "handleEvent");
+
+var register = exports.register = function register(window, callback) {
+ new PersistentPageMod(window, callback);
+};
diff --git a/tests/test-util.js b/tests/test-util.js
index a9d0e6a..6292e84 100644
--- a/tests/test-util.js
+++ b/tests/test-util.js
@@ -186,7 +186,7 @@ exports.ensureLoadText = function (test) {
// test.waitUntilDone();
// util.loadText(url, function (txt) {
// console.log(txt);
-// //test.assertEqual(txt, pushkinTestString);
+// test.assertEqual(txt, pushkinTestString);
// test.done();
// });
// };