aboutsummaryrefslogtreecommitdiffstats
path: root/gmperator.js
diff options
context:
space:
mode:
Diffstat (limited to 'gmperator.js')
-rw-r--r--gmperator.js403
1 files changed, 403 insertions, 0 deletions
diff --git a/gmperator.js b/gmperator.js
new file mode 100644
index 0000000..24b2e36
--- /dev/null
+++ b/gmperator.js
@@ -0,0 +1,403 @@
+/**
+ * ==VimperatorPlugin==
+ * @name gmperator
+ * @description Vimperator plugin for Greasemonkey
+ * @author teramako teramako@gmail.com
+ * @namespace http://d.hatena.ne.jp/teramako/
+ * @version 0.5b
+ * ==/VimperatorPlugin==
+ *
+ * ---------------------------
+ * Usage:
+ * ---------------------------
+ * {{{
+ *
+ * :gmli[st] {filter} -> show user scripts matches {filter}
+ * :gmli[st]! -> show all user scripts
+ * :gmli[st] full -> same as :gmli[st]!
+ *
+ * :gmlo[ad] {name|filename} -> load the user script to the current page
+ * but, don't dispatch load event
+ * so maybe you should edit the scripts before load
+ * :gmlo[ad]! {name|filename} -> force load the user script
+ *
+ * :gmset! -> toggle enable/disable Greasemonkey
+ * :gmset! {filename} -> toogle enable/disable the script
+ * :gmset {filename} {options}
+ * {options}:
+ * -n[ame] {value} -> change name to {value}
+ * -i[nclude] {expr[,expr,...]} -> change includes to expr list ("," demiliter)
+ * -e[xclude] {expr[,expr,...]} -> change excludes to expr list ("," demiliter)
+ *
+ * Caution:
+ * The change is permanent, not only the session.
+ * And cannot get back.
+ *
+ * e.g.)
+ * :gmset! {filename} -n fooScriptName -i http://*,https://* -e http://example.com/*
+ * toggle enable or disable,
+ * name to "fooScriptName",
+ * includes to "http://*" and "https://*",
+ * and excludes to "http://example.com/*"
+ *
+ * ---------------------------
+ * Autocommand
+ * ---------------------------
+ * Available events:
+ * 'GMInjectedScript' -> when open either foreground or background
+ * 'GMActiveScript' -> when TabSelect or open foreground
+ * e.g.)
+ * autocmd GMActiveScript scriptName\.user\.js$ :echo "scriptName is executing"
+ * when any URL and scriptName.user.js is executing
+ *
+ * ---------------------------
+ * Dialog
+ * ---------------------------
+ * :dialog userscriptmanager -> open Greasemonkey UserScript Manager
+ *
+ * }}}
+ * ---------------------------
+ * For plugin developer:
+ * ---------------------------
+ * {{{
+ *
+ * you can access to the sandbox of Greasemonkey !!!
+ *
+ * liberator.plugins.gmperator => (
+ * allItem : return object of key : {panalID},
+ * value : {GmContainer}
+ * {panelID} => @see gBrowser.mTags[].linkedPanel
+ * currentPanel
+ * currentContainer : return the current {GmContainer} object
+ * currentSandbox : return the current sandbox object
+ * gmScripts : return array of {userScripts}
+ * {userScripts} => (
+ * filename : {String}
+ * name : {String}
+ * namespace : {String}
+ * description: {String}
+ * enabled : {Boolean}
+ * includes : {String[]}
+ * encludes : {String[]}
+ * )
+ * )
+ * }}}
+ */
+(function(){
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const gmID = '@greasemonkey.mozdev.org/greasemonkey-service;1';
+if (!Cc[gmID]) {
+ log('Greasemonkey is not installed');
+ return;
+}
+
+liberator.plugins.gmperator = (function(){ //{{{
+ // -----------------------
+ // PUBLIC section
+ // -----------------------
+ // {{{
+ var manager = {
+ register: function (uri,sandbox,script){
+ var panelID = getPanelID(sandbox.window);
+ if (!panelID) return;
+ var gmCon;
+ if (containers[panelID] && containers[panelID].uri == uri){
+ gmCon = containers[panelID];
+ } else {
+ gmCon = new GmContainer(uri,sandbox);
+ containers[panelID] = gmCon;
+ this.__defineGetter__(panelID,function() gmCon);
+ log('gmpeartor: Registered: ' + panelID + ' - ' + uri, 8);
+ }
+ gmCon.sandbox = sandbox;
+ gmCon.addScript(script);
+ gmCon.uri = uri;
+ triggerGMEvent('GMInjectedScript', uri, script._filename);
+ if (panelID == this.currentPanel){
+ triggerGMEvent('GMActiveScript', uri, script._filename);
+ }
+ },
+ get gmScripts() GM_getConfig().scripts,
+ get allItem() containers,
+ get currentPanel() getBrowser().mCurrentTab.linkedPanel,
+ get currentContainer() containers[this.currentPanel] || null,
+ get currentSandbox(){
+ var id = this.currentPanel;
+ return containers[id] ? containers[id].sandbox : null;
+ },
+ getSandboxFromWindow: function(win){
+ for each(var c in containers){
+ if(c.sandbox.window == win) return sandbox;
+ }
+ return null;
+ },
+ getContainersFromURI: function(uri){
+ var list = [];
+ for each(var c in containers){
+ if (c.uri == uri) list.push(c);
+ }
+ return list.length > 0 ? list : null;
+ },
+ };
+ // }}}
+ // -----------------------
+ // PRIVATE section
+ // -----------------------
+ // {{{
+ var containers = {};
+ var gmSvc = Cc[gmID].getService().wrappedJSObject;
+
+ function appendCode(target,name,func){
+ var original = target[name];
+ target[name] = function(){
+ var tmp = original.apply(target,arguments);
+ func.apply(this,arguments);
+ return tmp;
+ };
+ }
+ appendCode(gmSvc, 'evalInSandbox', function(code,uri,sandbox,script){
+ liberator.plugins.gmperator.register(uri,sandbox,script);
+ });
+ function getPanelID(win){
+ var tabs = getBrowser().mTabs;
+ for (var i=0; tabs.length; i++){
+ var tab = tabs.item(i);
+ if (tab.linkedBrowser.contentWindow == win){
+ return tab.linkedPanel;
+ }
+ }
+ }
+ function updateGmContainerList(event){
+ var t = event.target;
+ if (t && t.localName == 'tab' && t.linkedPanel){
+ delete containers[t.linkedPanel];
+ delete liberator.plugins.gmperator[t.linkedPanel];
+ }
+ }
+ function dispatchGMTabSelect(event){
+ var panelID = event.originalTarget.linkedPanel;
+ var container;
+ if (container = containers[panelID]){
+ liberator.log(panelID + '\n' + container.uri +'\n'+ container.scripts.length, 8);
+ container.scripts.forEach(function(script){
+ triggerGMEvent('GMActiveScript', container.uri, script._filename);
+ });
+ }
+ }
+ /**
+ * trigger autocommand
+ * @param {String} name Event name
+ * @param {String} uri
+ * @param {String} filename script filename
+ */
+ function triggerGMEvent(name, uri, filename){
+ autocommands.trigger(name, uri+'\n'+filename);
+ liberator.log('gmpeartor: '+ name + ' ' + uri+'\n'+filename, 8);
+ }
+ getBrowser().mTabContainer.addEventListener('TabClose',updateGmContainerList,false);
+ getBrowser().mTabBox.addEventListener('TabSelect',dispatchGMTabSelect,false);
+
+ config.autocommands.push(["GMInjectedScript","Triggered when UserScript is injected"]);
+ config.autocommands.push(["GMActiveScript","Triggered when location is changed and injected UserScripts are exist"]);
+ config.dialogs.push(["userscriptmanager", "Greasemonkey Manager", function(){GM_openUserScriptManager();}]);
+ // }}}
+ return manager;
+})(); //}}}
+
+// ---------------------------
+// User Command
+// ---------------------------
+commands.addUserCommand(['gmli[st]','lsgm'], 'list Greasemonkey scripts', //{{{
+ function(arg,special){
+ var str = '';
+ var scripts = GM_getConfig().scripts;
+ var reg;
+ if (special || arg == 'full'){
+ reg = new RegExp('.*');
+ } else if( arg ){
+ reg = new RegExp(arg,'i');
+ }
+ if (reg){
+ for each(var s in scripts){
+ if ( reg.test(s.name) || reg.test(s._filename) ) {
+ str += scriptToString(s) + '\n';
+ }
+ }
+ } else {
+ var table = <table/>;
+ var tr;
+ for each(var script in scripts){
+ tr = <tr/>;
+ if (script.enabled){
+ tr.* += <td style="font-weight:bold;">{script.name}</td>;
+ } else {
+ tr.* += <td>{script.name}</td>;
+ }
+ tr.* += <td>({script._filename})</td>;
+ table.* += tr;
+ }
+ str += table.toSource().replace(/\n/g,'');
+ }
+ echo(str,true);
+ function scriptToString(script){
+ var table = <table>
+ <caption class="hl-Title" style="text-align:left">{script.name}</caption>
+ </table>;
+ [['FileName','_filename'], ['NameSpace','namespace'], ['Description','description'],
+ ['Includes','includes'], ['Excludes','excludes'], ['Enabled','enabled']].forEach(function(prop){
+ var tr = <tr>
+ <th style="font-weight:bold;text-align:left;vertical-align:top">{prop[0]}</th>
+ </tr>;
+ var contents = script[prop[1]];
+ if (typeof contents == "string" || typeof contents == "boolean"){
+ tr.* += <td>{contents}</td>;
+ } else {
+ var td = <td/>;
+ for (var i=0; i<contents.length; i++){
+ td.* += contents[i];
+ if (contents[i+1]) td.* += <br/>;
+ }
+ tr.* += td;
+ }
+ table.* += tr;
+ });
+ return table.toSource().replace(/\n/g,'');
+ }
+ }
+); //}}}
+commands.addUserCommand(['gmlo[ad]'], 'load Greasemonkey scripts', //{{{
+ function(arg, special){
+ if (!arg) {
+ echoerr('Usage: :gmlo[ad][!] {name|filename}');
+ return;
+ }
+ var scripts = GM_getConfig().scripts;
+ var script;
+ for (var i=0; i<scripts.length; i++){
+ if (scripts[i]._filename == arg || scripts[i].name == arg){
+ script = scripts[i];
+ break;
+ }
+ }
+ if (!script) {
+ echoerr('no such a user script');
+ return;
+ } else if (liberator.plugins.gmperator.currentContainer.hasScript(script._filename) && !special){
+ echoerr(script._filename + ' is already loaded!');
+ return;
+ } else {
+ echo('loading: ' +script._filename);
+ }
+ try {
+ var href = buffer.URL;
+ var unsafewin = window.content.document.defaultView.wrappedJSObject;
+ GM_BrowserUI.gmSvc.wrappedJSObject.injectScripts([script],href,unsafewin,window);
+ } catch(e){
+ log(e);
+ echoerr(e);
+ }
+ /*
+ // do you have idea how to dispatch load event to only the script ?
+ window.setTimeout(function(){
+ var loadEvent = document.createEvent('Event');
+ loadEvent.initEvent('load',true,true, window.content.document,1);
+ window.content.document.dispatchEvent(loadEvent);
+ },100);
+ */
+ },{
+ completer: function(filter) scriptsCompleter(filter,true)
+ }
+); //}}}
+commands.addUserCommand(['gmset'], 'change settings for Greasemonkey scripts', //{{{
+ function(args, special){
+ var options = [ [['-name','-n'], commands.OPTION_STRING],
+ [['-include','-i'], commands.OPTION_LIST],
+ [['-exclude','-e'], commands.OPTION_LIST] ];
+ var res = commands.parseArgs(args, options);
+ if (res.arguments.length == 0) {
+ if (special) GM_setEnabled(!GM_getEnabled()); // toggle enable/disable Greasemonkey
+ return;
+ }
+ var filename = res.arguments[0];
+ var config = GM_getConfig();
+ var script;
+ for (var i=0; i<config.scripts.length; i++){
+ if (config.scripts[i]._filename == filename){
+ script = config.scripts[i];
+ break;
+ }
+ }
+ if (!script) return;
+ if (special){ // toggle enable/disable the script if {filename} is exist
+ script.enabled = !script.enabled;
+ }
+ if (res['-name']) script.name = res['-name'];
+ if (res['-include']) script.include = res['-include'];
+ if (res['-exclude']) script.exclude = res['-exclude'];
+ config._save();
+ },{
+ completer: function(filter)
+ scriptsCompleter(filter, false)
+ }
+); //}}}
+
+// ---------------------------
+// Utils
+// ---------------------------
+/** Grasemonkey sandbox container {{{
+ * @param {String} uri
+ * @param {Sandbox} sandbox
+ * @param {Array} scripts
+ */
+function GmContainer(uri,sandbox){
+ this.uri = uri;
+ this.sandbox = sandbox;
+ this.scripts = [];
+}
+GmContainer.prototype = {
+ addScript : function(script) {
+ if (!this.hasScript(script)){
+ return this.scripts.push(script)
+ }
+ return false;
+ },
+ hasScript : function(script){
+ var filename;
+ switch( typeof(script) ){
+ case 'object': filename = script._filename; break;
+ case 'string': filename = script; break;
+ default: return null;
+ }
+ return this.scripts.some(function(s) s._filename == filename);
+ }
+}; // }}}
+function scriptsCompleter(filter,flag){ //{{{
+ var candidates = [];
+ var scripts = GM_getConfig().scripts;
+ var isAll = false;
+ if (!filter) isAll=true;
+ if (flag){
+ for each(var s in scripts){
+ if (isAll || s.name.toLowerCase().indexOf(filter) == 0 ||
+ s._filename.indexOf(filter) == 0)
+ {
+ candidates.push([s.name, s.description]);
+ candidates.push([s._filename, s.description]);
+ }
+ }
+ } else {
+ for each(var s in scripts){
+ if (isAll || s._filename.indexOf(filter) == 0)
+ {
+ candidates.push([s._filename, s.description]);
+ }
+ }
+ }
+ return [0,candidates];
+} //}}}
+
+})();
+
+// vim: fdm=marker sw=4 ts=4 et: