diff options
author | portix <portix@gmx.net> | 2014-03-04 13:38:30 +0100 |
---|---|---|
committer | portix <portix@gmx.net> | 2014-03-04 13:38:30 +0100 |
commit | 7c222c5a3063e5af5889653814d40a4efa59fa5c (patch) | |
tree | f4e9146b393a2dd96d0aa3cc683e731a23be672b | |
parent | 05c5a1a8ff467ae10c30433621a55da0fbc9b474 (diff) | |
download | dwb-7c222c5a3063e5af5889653814d40a4efa59fa5c.zip |
Adding initial bookmarklets plugin
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | extensions/src/Makefile | 17 | ||||
-rw-r--r-- | extensions/src/bookmarklets/chrome.html | 89 | ||||
-rw-r--r-- | extensions/src/bookmarklets/chrome.js | 60 | ||||
-rw-r--r-- | extensions/src/bookmarklets/dom.js | 64 | ||||
-rw-r--r-- | extensions/src/bookmarklets/main.js | 159 | ||||
-rw-r--r-- | extensions/src/bookmarklets/shared.js | 69 |
7 files changed, 461 insertions, 1 deletions
@@ -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; |