summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorportix <portix@gmx.net>2014-03-04 13:38:30 +0100
committerportix <portix@gmx.net>2014-03-04 13:38:30 +0100
commit7c222c5a3063e5af5889653814d40a4efa59fa5c (patch)
treef4e9146b393a2dd96d0aa3cc683e731a23be672b
parent05c5a1a8ff467ae10c30433621a55da0fbc9b474 (diff)
downloaddwb-7c222c5a3063e5af5889653814d40a4efa59fa5c.zip
Adding initial bookmarklets plugin
-rw-r--r--Makefile4
-rw-r--r--extensions/src/Makefile17
-rw-r--r--extensions/src/bookmarklets/chrome.html89
-rw-r--r--extensions/src/bookmarklets/chrome.js60
-rw-r--r--extensions/src/bookmarklets/dom.js64
-rw-r--r--extensions/src/bookmarklets/main.js159
-rw-r--r--extensions/src/bookmarklets/shared.js69
7 files changed, 461 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 179762e5..af8b6edc 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,9 @@ install-data: all
@#Extensions
install -d $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$(EXTENSIONDIR)
for file in $(EXTENSIONDIR)/*; do \
- install -m 644 $$file $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$$file; \
+ if [ -f $$file ]; then \
+ install -m 644 $$file $(DESTDIR)$(DATADIR)/$(REAL_NAME)/$$file; \
+ fi \
done
ifdef BASHCOMPLETION
install -d $(DESTDIR)/$(BASHCOMPLETION)
diff --git a/extensions/src/Makefile b/extensions/src/Makefile
new file mode 100644
index 00000000..8db0498d
--- /dev/null
+++ b/extensions/src/Makefile
@@ -0,0 +1,17 @@
+EXTENSIONS=cookies bookmarklets
+BASEDIR=..
+DWBEM=./../../dwbem/dwbem
+
+
+all: ${EXTENSIONS}
+
+${EXTENSIONS}: .FORCE
+ @echo packing $@
+ @${DWBEM} --archive p $@ ${BASEDIR}/$@
+
+clean:
+ ${RM} ${BASEDIR}/${EXTENSIONS}
+
+.FORCE:
+
+.PHONY: clean
diff --git a/extensions/src/bookmarklets/chrome.html b/extensions/src/bookmarklets/chrome.html
new file mode 100644
index 00000000..c2feee7b
--- /dev/null
+++ b/extensions/src/bookmarklets/chrome.html
@@ -0,0 +1,89 @@
+<head>
+<style type="text/css">
+.container {
+ width:35em;
+ margin-left:auto;
+ margin-right:auto;
+}
+.button {
+ border:none;
+ outline:none;
+ width:15px;
+ height:15px;
+ background:url(data:image/gif;base64,R0lGODlhDwAPAPAAAJmZmQAAACH5BAEAAAEALAAAAAAPAA8AAAIgjI+piwDrWpSPHlcTDpvhyXCg94Vbp4GosYqZCL3hHBYAOw==) no-repeat left center;
+ cursor:pointer;
+ background-color:#eee;
+}
+button:focus, input:focus {
+ outline:none;
+ background-color:#fff;
+ box-shadow:0 0 1px 1px #999;
+};
+table {
+ font : 14px normal monospace;
+ border-collapse:collapse;
+ width : 100%;
+ table-layout:fixed;
+};
+thead {
+ margin-left:auto;
+ margin-right:auto;
+}
+tr {
+ width:100%;
+}
+th {
+ text-align:left;
+ color:#eee;
+}
+th, td {
+ padding:0.5em 0.5em;
+}
+th { background-color : #555555; }
+tr { background-color:#ffffff; border-bottom:1px solid #ccc; }
+#saveButton {
+ background-color:#eee;
+ float:right;
+ display:inline;
+ margin-top : 1em;
+ padding:0.2em 0.6em;
+ cursor:pointer;
+ border:none;
+}
+#saveButton:focus {
+ background-color:#fff;
+}
+
+th:nth-child(1), td:nth-child(1) { width : 32%}
+th:nth-child(2), td:nth-child(2) { width : 32% }
+th:nth-child(3), td:nth-child(3) { width : 32% }
+th:nth-child(4), td:nth-child(4) { max-width : 4% }
+input {
+ border : 1px solid #eee;
+ outline:none;
+ background-color:#eee;
+}
+input:focus {
+ background-color:#fff;
+}
+</style>
+</head>
+<body>
+<div class="container">
+ <table id="content">
+ <thead>
+ <tr>
+ <th data-name="name">name</th>
+ <th data-name="shortcut"> shortcut </th>
+ <th data-name="command">command</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody id="content">
+ </tbody>
+ </table>
+ <button id="saveButton">save</button>
+
+</div>
+
+</body>
diff --git a/extensions/src/bookmarklets/chrome.js b/extensions/src/bookmarklets/chrome.js
new file mode 100644
index 00000000..b8085b1d
--- /dev/null
+++ b/extensions/src/bookmarklets/chrome.js
@@ -0,0 +1,60 @@
+/*jslint */
+/*global xrequire,tabs,io,script,provide,xgettext*/
+var shared = xrequire("shared");
+
+function chromeDelete(name) {
+ shared.delete(null, name);
+ tabs.current.reload();
+}
+
+function chromeSave(data) {
+ var oldData = shared.getAll();
+ var newData = {};
+ var name;
+ shared.removeAllBinds();
+ data.forEach(function(d) {
+ var orig = oldData[d.origName];
+ newData[d.name] = {
+ name : d.name,
+ shortcut : d.shortcut,
+ command : d.command,
+ script : orig.script
+ };
+ });
+ shared.save(newData);
+ shared.addAllBinds();
+ io.notify("Bookmarklets saved");
+}
+
+return function(wv) {
+ var data, name, b, list, id;
+
+ data = shared.getAll();
+ list = [];
+ id = script.generateId();
+ for (name in data) {
+ b = data[name];
+ list.push({
+ name : b.name,
+ shortcut : b.shortcut,
+ command : b.command
+ });
+ }
+ list = list.sort(function(a, b) {
+ return a.name < b.name ? -1 : 1;
+ });
+ wv.onceDocumentLoaded = function() {
+ provide(id, {
+ delete : chromeDelete,
+ save : chromeSave
+ });
+ wv.inject(xgettext("~dom.js"), { moduleId : id, data : list }, 1);
+
+ // cleanup
+ wv.onceNavigation = function() {
+ provide(id, null, true);
+ };
+
+ };
+ return xgettext("~chrome.html");
+};
diff --git a/extensions/src/bookmarklets/dom.js b/extensions/src/bookmarklets/dom.js
new file mode 100644
index 00000000..ab781132
--- /dev/null
+++ b/extensions/src/bookmarklets/dom.js
@@ -0,0 +1,64 @@
+var exports = this.exports;
+DOMUtil = {
+ delete : function(name) {
+ dwb(function() {
+ require(this.exports.moduleId).delete(this.exports.bookmarklet);
+ }, { moduleId : exports.moduleId, bookmarklet : name });
+ },
+ save : function() {
+ var elements = document.querySelectorAll("[data-id]");
+ var data = Array.prototype.map.call(elements, function(e) {
+ var origName = e.dataset.id;
+ var nameNode = e.firstElementChild;
+ var name = nameNode.firstElementChild.value;
+ var shortcutNode = nameNode.nextElementSibling;
+ var shortcut = shortcutNode.firstElementChild.value;
+ var command = shortcutNode.nextElementSibling.firstElementChild.value;
+ return {
+ origName : origName,
+ name : name,
+ shortcut : shortcut,
+ command : command
+ };
+ });
+ dwb(function() {
+ require(this.exports.moduleId).save(this.exports.data);
+ }, { moduleId : exports.moduleId, data : data });
+ }
+};
+(function() {
+ var content;
+ function createElement(parent, type, props) {
+ var prop;
+ var e = document.createElement(type);
+ for (prop in props) {
+ e[prop] = props[prop];
+ }
+ parent.appendChild(e);
+
+ return e;
+ }
+
+ function createWithParent(parent, type, props) {
+ var e = createElement(parent, "td");
+ var ret = createElement(e, type, props);
+ ret.setAttribute("tabindex", 1);
+ return ret;
+ }
+
+ content = document.getElementById("content");
+ exports.data.forEach(function(b) {
+ var button, row;
+
+ row = createElement(content, "tr", { role : "presentation" });
+ row.dataset.id = b.name;
+ createWithParent(row, "input", { value : b.name });
+ createWithParent(row, "input", { value : b.shortcut });
+ createWithParent(row, "input", { value : b.command });
+ button = createWithParent(row, "button", { className : "button" });
+ button.setAttribute("onclick", "DOMUtil.delete('" + b.name + "')");
+
+ content.appendChild(row);
+ });
+ document.getElementById("saveButton").setAttribute("onclick", "DOMUtil.save()");
+}());
diff --git a/extensions/src/bookmarklets/main.js b/extensions/src/bookmarklets/main.js
new file mode 100644
index 00000000..4d435bf1
--- /dev/null
+++ b/extensions/src/bookmarklets/main.js
@@ -0,0 +1,159 @@
+/*jslint eqeq:true,forin:true*/
+/*global data, script,xprovide,xinclude,io,util,Signal,ButtonContext,bind,extensions*/
+
+/*<INFO
+creates a context menu entry for saving bookmarklets
+INFO>*/
+
+var defaultConfig = {
+//<DEFAULT_CONFIG
+// The location to save bookmarklets
+file : data.configDir + "/bookmarklets.json",
+
+// command to delete a bookmarklet
+deleteCommand : "bm_delete",
+
+// shortcut to delete a bookmarklet
+deleteShortcut : null,
+
+// command to list all bookmarklet and execute the selected bookmarklet
+listCommand : "bm_list",
+
+// shortcut to list all bookmarklet and execute the selected bookmarklet
+listShortcut : null,
+
+// command to change a bookmarklet
+changeCommand : "bm_change",
+
+// shortcut to change a bookmarklet
+changeShortcut : null
+
+//>DEFAULT_CONFIG
+};
+
+var shared;
+var cmdDelete, cmdList, cmdChange;
+
+function newBookmarklet(bmscript, confirmOverwrite) {
+ var data, name, shortcut, command, bookmarklet;
+ data = shared.getAll();
+ name = io.prompt("Name:");
+
+ if (!name || name.trim().length == 0) {
+ io.error("Name is required");
+ return;
+ }
+
+ if (confirmOverwrite && data[name] && !io.confirm(name + " already exists, overwrite (y/n)?")) {
+ return;
+ }
+
+ shortcut = io.prompt("Shortcut:");
+ command = io.prompt("Command:");
+
+ bookmarklet = {
+ name : name,
+ shortcut : shortcut,
+ command : command,
+ script : bmscript
+ };
+ data[name] = bookmarklet;
+ shared.save(data);
+
+ shared.addBind(name, bookmarklet);
+}
+
+// actions
+function doList(data, name) {
+ shared.inject(data[name].script);
+}
+
+function doDelete(data, name) {
+ shared.delete(data, name);
+ io.notify("bookmarklet " + name + " deleted");
+}
+
+function doChange(data, name) {
+ var bmscript = data[name].script;
+ shared.delete(data, name);
+ newBookmarklet(bmscript, false);
+}
+
+function complete(label, action) {
+ var data = shared.getAll();
+ var name, list = [], b;
+ for (name in data) {
+ b = data[name];
+ list.push({
+ left : name,
+ right : (b.shortcut ? "shortcut: " + b.shortcut + " " : "") +
+ (b.command ? "command: " + b.command : "")
+ });
+ }
+ if (list.length == 0) {
+ io.error("No bookmarklets found");
+ return;
+ }
+ util.tabComplete(label + ":", list, action.bind(null, data), true);
+}
+
+function onContextMenu(bmscript, wv, menu) {
+ menu.addItems([{
+ label : "Save as _bookmarklet",
+ callback : newBookmarklet.bind(null, bmscript, true)
+ }]);
+}
+
+function onButtonPress(wv, result, e) {
+ var linkUri, signal, bmscript;
+ if (e.button == 3 && (result.context & ButtonContext.link) ) {
+ linkUri = result.linkUri;
+ if (linkUri.substring(0, 11) == "javascript:") {
+ bmscript = decodeURI(linkUri.substring(11));
+ script.own(Signal.once("contextMenu", onContextMenu.bind(null, bmscript)));
+ }
+ }
+}
+
+cmdDelete = complete.bind(null, "Delete bookmarklet", doDelete);
+cmdList = complete.bind(null, "Use bookmarklet", doList);
+cmdChange = complete.bind(null, "Change bookmarklet", doChange);
+
+function init(config) {
+ config = config || defaultConfig;
+ config.name = "bookmarklets";
+
+ xprovide("config", config, true);
+ shared = xinclude("~shared.js");
+
+ this.exports.config = config;
+
+ script.own(
+ Signal.connect("buttonPress", onButtonPress),
+ bind(config.deleteShortcut, cmdDelete, config.deleteCommand),
+ bind(config.listShortcut, cmdList, config.listCommand),
+ bind(config.changeShortcut, cmdChange, config.changeCommand),
+ extensions.registerChrome("bookmarklets", xinclude("~chrome.js"))
+ );
+
+ shared.addAllBinds();
+
+ return true;
+}
+function end() {
+ script.removeHandles();
+ shared.end();
+ return true;
+}
+
+var bookmarklets = {
+ defaultConfig : defaultConfig,
+ exports : {
+ deleteBookmarklet : cmdDelete,
+ listBookmarklets : cmdList,
+ changeBookmarklet : cmdChange
+ },
+ init : init,
+ end : end
+};
+return bookmarklets;
diff --git a/extensions/src/bookmarklets/shared.js b/extensions/src/bookmarklets/shared.js
new file mode 100644
index 00000000..0dfc8d22
--- /dev/null
+++ b/extensions/src/bookmarklets/shared.js
@@ -0,0 +1,69 @@
+/*jslint eqeq:true*/
+/*global system,FileTest,extensions,io,bind,tabs,script,xprovide,xrequire*/
+var config = xrequire("config");
+
+var shared = {
+ bindHandles : {},
+ getAll : function() {
+ var data, backup, content;
+ if (system.fileTest(config.file, FileTest.exists)) {
+ content = io.read(config.file);
+ try {
+ data = JSON.parse(content);
+ }
+ catch (e) {
+ backup = config.file + ".backup";
+ extensions.error(config.name, "The bookmarklet file is corrupted, creating backup " + backup);
+ io.write(backup, "w", content);
+ }
+ }
+ return data || {};
+ },
+ addBind : function(name, bm) {
+ if (bm.shortcut || bm.command) {
+ var handle = bind(bm.shortcut || null,
+ this.inject.bind(null, bm.script),
+ bm.command || null);
+ this.bindHandles[name] = handle;
+ script.own(handle);
+ }
+ },
+ inject : function(bm, cmd) {
+ (cmd && cmd.nummod != -1 ? tabs[cmd.nummod - 1] : tabs.current).inject(bm, null, 0);
+ },
+ delete : function(data, name) {
+ data = data || this.getAll();
+ delete data[name];
+ this.save(data);
+ this.removeBind(name);
+ },
+ removeAllBinds : function() {
+ var name;
+ for (name in this.bindHandles) {
+ this.removeBind(name);
+ }
+ },
+ removeBind : function(name) {
+ if (this.bindHandles[name]) {
+ this.bindHandles[name].remove();
+ delete this.bindHandles[name];
+ }
+ },
+ addAllBinds : function() {
+ var name;
+ var bookmarklets = this.getAll();
+ for (name in bookmarklets) {
+ this.addBind(name, bookmarklets[name]);
+ }
+ },
+ save : function(data) {
+ io.write(config.file, "w", JSON.stringify(data));
+ },
+ end : function() {
+ this.bindHandles = {};
+ script.removeHandles();
+ }
+};
+xprovide("shared", shared, true);
+
+return shared;