root/lang/javascript/userscripts/minibufferbookmarkcommand.user.js

Revision 11134, 23.7 kB (checked in by drry, 22 months ago)
  • fixed a regexp.
Line 
1// ==UserScript==
2// @name           Minibuffer Bookmark Command
3// @namespace      http://white.s151.xrea.com/
4// @description    bookmark command for minibuffer
5// @include        *
6// ==/UserScript==
7
8var SCRIPT_VERSION = "2008.05.05"
9var SCRIPT_URL     = "http://userscripts.org/scripts/show/14490"
10
11// usage:
12//
13// location | bookmark -h --tag "--comment=this is test"
14// pinned-node | bookmark -h --tag | clear-pin
15// current-node | bookmark -h "--tag=firefox greasemonkey" --comment
16// pinned-or-current-node | bookmark -h | clear-pin
17
18// or use shortcutkey 'b' or 'B'
19//
20// b  --- bookmark with no comment and no tags (default)
21// B  --- bookmark with tags and comment
22
23// in shortcut key, which SBM do you use?
24//
25// --hatena    -h   ... hatena bookmark
26// --livedoor  -l   ... livedoor clip
27// --delicious -d   ... del.icio.us
28var SBM = '-h'
29
30// for 'b'
31var TAG = ''
32
33if(!document.body) return;
34var runMinibufferBookmarkCommand = function(){
35
36        var BookmarkL = {};
37        var BookmarkS = {};
38        var regexp       = new RegExp('^-');
39        var regexp_short = new RegExp('^-\\w');
40        var regexp_long  = new RegExp('^--\\w');
41
42        var addBookmark = function(long_name, short_name, bookmark_class){
43                BookmarkL[long_name]  = bookmark_class;
44                BookmarkS[short_name] = bookmark_class;
45        }
46
47        // tags
48        var setTags = function(tags){
49                return GM_setValue('tags', tags.toSource());
50        }
51        var getTags = function(){
52                return eval(GM_getValue('tags', '[]'))
53        }
54
55        /////////////////////////////////////////////////////////////////
56        // hatena bookmark
57        var hatenab = new function(){
58                var self = this;
59                this.checkLogin = function(html){
60                        var input = $X('//input', html);
61                        return input.length != 0;
62                }
63                this.post = function(async, opt){
64                        var comment = self.comment;
65                        if (self.tags.length) comment = '[' + self.tags.join('][') + ']' + comment;
66                        var request = [
67                                "mode=enter",
68                                "&eid=", opt.eid,
69                                "&url=", encodeURIComponent(opt.url),
70                                "&rkm=", encodeURIComponent(opt.rkm),
71                                "&is_bm=", opt.is_bm,
72                                "&title=", encodeURIComponent(opt.title),
73                                "&comment=", encodeURIComponent(comment)
74                                ].join('');
75                        GM_xmlhttpRequest({
76                          method: 'POST',
77                          url: "http://b.hatena.ne.jp/add",
78                          headers: {
79                                  'Content-Type': 'application/x-www-form-urlencoded'
80                                },
81                          onload: function(res){
82                                  async.ready();
83                                },
84                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
85                          data: request
86                        });
87                }
88                this.getParam = function(async, arg){
89                        window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark ' + arg.progress + '%');
90                        var callback = function(res){
91                                var html = res.responseText.createHTML();
92                                if(!self.checkLogin(html)){
93                                        async.error();
94                                        return;
95                                }
96                                var inputs = $X('//input', html);
97                                var res = {};
98                                inputs.forEach(function(d){
99                                        res[d.getAttribute('name')] = d.getAttribute('value');
100                                });
101                                if(keys(res).length == 1){
102                                        // already bookmarked
103                                        var a = $X('//ul[@class="entry"]/li[1]/a', html);
104                                        var text = a[0].textContent;
105                                        window.Minibuffer.message('<small>'+text+'</small><br/> has already bookmarked.', 2000);
106                                        async.ready();
107                                }else{
108                                        // not yet bookmarked
109                                        self.post(async, res);
110                                }
111                        }
112                        GM_xmlhttpRequest({
113                          method: 'GET',
114                          url: "http://b.hatena.ne.jp/add?mode=confirm&is_bm=1&url="+encodeURIComponent(arg.url),
115                          onload: callback,
116                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
117                        });
118                }
119                this.bookmark = function(urls, tags, comment){
120                        if(!urls.length) return;
121                        self.tags = tags;
122                        self.comment = comment;
123                        var total = urls.length;
124                        self.time = new Date().getTime();
125                        AsyncOrderedList(self.getParam, urls.map(function(url,i){
126                                return {
127                                  url: url,
128                                  progress: Math.floor(i / total * 100)
129                                }
130                        })).ready(function(){
131                                window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark 100 %', 1000);
132                        }).error(function(){
133                                window.Minibuffer.status('bookmark.hatena'+self.time,'Bookmark failed. you are not logging hatena in.', 3000);
134                        })
135                }
136                this.getTags = function(){
137                        // orz
138                        var a = new Async();
139                        var callback = function(res){
140                                var html = res.responseText.createHTML();
141                                if(!self.checkLogin(html)) {
142                                        a.ready([]);
143                                        return;
144                                }
145                                var tags = $X('//a[@class="tag-latest"]', html);
146                                a.ready(tags.map(function(arg){return arg.textContent}));
147                        }
148                        GM_xmlhttpRequest({
149                          method: 'GET',
150                          url: "http://b.hatena.ne.jp/my",
151                          onload: callback,
152                          onerror: function(res){a.ready([])},
153                        });
154                        return a;
155                }
156        }
157
158        /////////////////////////////////////////////////////////////////
159        // livedoor clip
160        var livedoorclip = new function(){
161                var self = this;
162                this.checkLogin = function(html){
163                        var login = $X('//form[@name="loginForm"]', html);
164                        return login.length == 0;
165                }
166                this.post = function(async, opt){
167                        var request = [
168                                "title=", encodeURIComponent(opt.title),
169                                "&postkey=", encodeURIComponent(opt.postkey),
170                                "&link=", encodeURIComponent(opt.link),
171                                "&tags=", encodeURIComponent(self.tags.join(' ')),
172                                "&notes=", encodeURIComponent(self.comment|''),
173                                ].join('');
174                        GM_xmlhttpRequest({
175                          method: 'POST',
176                          url: "http://clip.livedoor.com/clip/add",
177                          headers: {
178                                  'Content-Type': 'application/x-www-form-urlencoded'
179                                },
180                          onload: function(res){
181                                  async.ready();
182                                },
183                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
184                          data: request
185                        });
186                }
187                this.getParam = function(async, arg){
188                        window.Minibuffer.status('bookmark.livedoor'+self.time,'Bookmark ' + arg.progress + '%');
189                        var callback = function(res){
190                                var html = res.responseText.createHTML();
191                                if(!self.checkLogin(html)){
192                                        async.error();
193                                        return;
194                                }
195                                var delete_form = $X('//form[@action="/clip/delete"]', html);
196                                if(delete_form.length){
197                                        // already bookmarked
198                                        var text = $X('id("my_title")', html)[0].value;
199                                        window.Minibuffer.message('<small>'+text+'</small><br/> has already bookmarked.', 2000);
200                                        async.ready();
201                                }else{
202                                        // not yet bookmarked
203                                        var add_form = $X('//form[@action="/clip/add"]//input | //form[@action="/clip/add"]//textarea', html);
204                                        var res = {};
205                                        add_form.forEach(function(d){
206                                                res[d.getAttribute('name')] = d.getAttribute('value');
207                                        });
208                                        self.post(async, res);
209                                }
210                        }
211                        GM_xmlhttpRequest({
212                          method: 'GET',
213                          url: "http://clip.livedoor.com/clip/add?link="+encodeURIComponent(arg.url),
214                          onload: callback,
215                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
216                        });
217                }
218                this.bookmark = function(urls, tags, comment){
219                        if(!urls.length) return;
220                        self.tags = tags;
221                        self.comment = comment;
222                        var total = urls.length;
223                        self.time = new Date().getTime();
224                        AsyncOrderedList(self.getParam, urls.map(function(url,i){
225                                return {
226                                  url: url,
227                                  progress: Math.floor(i / total * 100)
228                                }
229                        })).ready(function(){
230                                window.Minibuffer.status('bookmark.livedoor'+self.time,'Bookmark 100 %', 1000);
231                        }).error(function(){
232                                window.Minibuffer.status('bookmark.livedoor'+self.time,'Bookmark failed. you are not logging livedoor in.', 3000);
233                        })
234                }
235                this.getTags = function(){
236                        var a = new Async();
237                        var callback = function(res){
238                                var html = res.responseText.createHTML();
239                                if(!self.checkLogin(html)) {
240                                        a.ready([]);
241                                        return;
242                                }
243                                var span = $X('id("tag_list")/span', html);
244                                a.ready(span.map(function(arg){return arg.textContent}));
245                        }
246                        GM_xmlhttpRequest({
247                          method: 'GET',
248                          url: "http://clip.livedoor.com/clip/add?link=http://aaaaaaaaaaaaaaaaaaaaaaaaaaa",
249                          onload: callback,
250                          onerror: function(res){a.ready([])},
251                        });
252                        return a;
253                }
254        }
255
256        /////////////////////////////////////////////////////////////////
257        // del.icio.us
258        var delicious = new function(){
259                var self = this;
260                this.checkLogin = function(html){
261                        return $X('id("header-auth-links")/a[@href="/logout"]', html).length;
262                }
263                this.post = function(async, opt){
264                        var request = [
265                                "url=", encodeURIComponent(opt.url),
266                                "&oldurl=", encodeURIComponent(opt.url),
267                                "&private=", opt.private,
268                                "&description=", encodeURIComponent(opt.description),
269                                "&notes=", encodeURIComponent(self.comment),
270                                "&tags=", encodeURIComponent(self.tags.join(' ')),
271                                "&v=", opt.v,
272                                "&key=", opt.key,
273                                ].join('');
274                        GM_xmlhttpRequest({
275                          method: 'POST',
276                          url: opt.action,
277                          headers: {
278                                  'Content-Type': 'application/x-www-form-urlencoded'
279                                },
280                          onload: function(res){
281                                  async.ready();
282                                },
283                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
284                          data: request
285                        });
286                }
287                this.getTitle = function(async, opt){
288                        var callback = function(res){
289                                var html = res.responseText.createHTML();
290                                opt.description = $X('//title', html)[0].text;
291                                self.post(async, opt);
292                        }
293                        GM_xmlhttpRequest({
294                          method: 'GET',
295                          url: opt.url,
296                          onload: callback,
297                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
298                        })
299                }
300                this.getParam = function(async, arg){
301                        window.Minibuffer.status('bookmark.del.icio.us'+self.time,'Bookmark ' + arg.progress + '%');
302                        var url = arg.url;
303                        if(!url) return;
304                        var callback = function(res){
305                                var html = res.responseText.createHTML();
306                                if(!self.checkLogin(html)){
307                                        async.error();
308                                        return;
309                                }
310                                var date = $X('//form[@id="delForm"]//input[@name="date"]', html);
311                                if(date.length != 0){
312                                        // already bookmarked
313                                        var text = $X('id("description")', html)[0].value;
314                                        window.Minibuffer.message('<small>'+text+'</small><br/> has already bookmarked.', 2000);
315                                        async.ready();
316                                }else{
317                                        // not yet bookmarked
318                                        var form = $X('//form[@id="delForm"]', html)[0];
319                                        var inputs = $X('//form[@id="delForm"]//input', html);
320                                        var res = {};
321                                        inputs.forEach(function(node){
322                                                res[node.getAttribute('name')] = node.getAttribute('value');
323                                        });
324                                        var re = new RegExp('^https?://[^/]+/');
325                                        res.action = 'http://del.icio.us/' + form.action.replace(re, '');
326                                        self.getTitle(async, res);
327                                }
328                        }
329                        GM_xmlhttpRequest({
330                          method: 'GET',
331                          url: "http://del.icio.us/post?v=4&url="+encodeURIComponent(url),
332                          onload: callback,
333                          onerror: function(res){log('onerror',res.responseText, '\n',res.responseHeaders)},
334                        });
335                }
336                this.bookmark = function(urls, tags, comment){
337                        if(!urls.length) return;
338                        self.tags = tags;
339                        self.comment = comment;
340                        var total = urls.length;
341                        self.time = new Date().getTime();
342                        AsyncOrderedList(self.getParam, urls.map(function(url,i){
343                                return {
344                                  url: url,
345                                  progress: Math.floor(i / total * 100)
346                                }
347                        })).ready(function(){
348                                window.Minibuffer.status('bookmark.del.icio.us'+self.time,'Bookmark 100 %', 1000);
349                        }).error(function(){
350                                window.Minibuffer.status('bookmark.del.icio.us'+self.time,'Bookmark failed. you are not logging del.icio.us in.', 3000);
351                        })
352                }
353                this.getTags = function(){
354                        var a = new Async();
355                        var callback = function(res){
356                                var tags = $X('//tag', res.responseText.createHTML());
357                                var lst  = tags.length ? tags.map(function(d){return d.getAttribute('tag')}) : [];
358                                a.ready(lst);
359                        }
360                        GM_xmlhttpRequest({
361                          method: 'GET',
362                          url: "https://api.del.icio.us/v1/tags/get",
363                          onload: callback,
364                          onerror: function(res){a.ready([])},
365                        });
366                        return a;
367                }
368        }
369
370        addBookmark('hatena',    'h', hatenab);
371        addBookmark('livedoor',  'l', livedoorclip);
372        addBookmark('delicious', 'd', delicious);
373
374        window.Minibuffer.addCommand({
375          name: 'bookmark',
376          command: function(stdin){
377                  var args = this.args;
378                  var urls, nodes;
379                  if(!stdin.length){
380                          // command line is 'bookmark'
381                          urls = [location.href];
382                          nodes = new Array(1);
383                  }else if(stdin.every(function(a){return typeof a == 'string'})){
384                          // command line is 'location | bookmark' or 'pinned-link | bookmark'
385                          urls = stdin;
386                          nodes = new Array(urls.length);
387                  }else if(window.LDRize){
388                          if(stdin.every(function(a){return a.nodeName == 'A'})){
389                                  urls = stdin.map(function(node){return node.href});
390                                  nodes = new Array(urls.length);
391                          }else{
392                                  // assuming that command line is 'current-node | bookmark' or 'pinned-node | bookmark'
393                                  var siteinfo = window.LDRize.getSiteinfo();
394                                  var link = siteinfo.link;
395                                  if(link){
396                                          nodes = stdin;
397                                          urls = nodes.map(function(node){
398                                                  var res = $X(link,node);
399                                                  if(!res.length) return;
400                                                  return res[0].href
401                                                });
402                                  }
403                          }
404                  }
405                  var bookmark = function(tags, comment){
406                          var idx = args.position(function(e){return !e.match(regexp)});
407                          if(idx < 0) return stdin;
408                          if(typeof(idx) == 'boolean' && idx == false) idx = args.length;
409                          for(var i=0; i<idx; i++){
410                                  if(args[i].match(regexp_long)){ // long option
411                                          var clazz = BookmarkL[args[i].slice(2)];
412                                          if(clazz && clazz.bookmark) clazz.bookmark(urls, tags, comment);
413                                  }else if(args[i].match(regexp_short)){ // short option
414                                          var bookmarks = args[i].match(/\w/g);
415                                          for(var j=0; j<bookmarks.length; j++){
416                                                  var clazz = BookmarkS[bookmarks[j]];
417                                                  if(clazz && clazz.bookmark) clazz.bookmark(urls, tags, comment);
418                                          }
419                                  }
420                          }
421                  }
422
423                  // specify by commandline
424                  var getUserTags = function(){
425                          var re = new RegExp('--tag=.*');
426                          var res = args.find(function(a){return a.match(re)});
427                          if(res){
428                                  var tags = res.match(new RegExp('=(.*)'))[1];
429                                  if(tags.length){
430                                          return tags.split(' ');
431                                  }
432                          }
433                          return [];
434                  }
435                  var getUserComment = function(){
436                          var re = new RegExp('--comment=.*');
437                          var res = args.find(function(a){return a.match(re)});
438                          return res ? res.match(new RegExp('=(.*)'))[1] : '';
439                  }
440                  var user_tags = getUserTags();
441                  var user_comment = getUserComment();
442
443
444                  // no tag no comment
445                  if(!args.find("--tag") && !args.find("--comment")){
446                          bookmark(user_tags, user_comment);
447                          return stdin;
448                  }
449                  var m_comment = window.Minibuffer.getMinibuffer().setPrompt('Comment:');
450                  m_comment.shortcutkey.addCommand({
451                        key:'|',
452                        command:function(){m_comment.bindInputChar.call(m_comment,'|')}});
453                  var m_comment_callback = function(tags, comment){
454                          if(typeof comment == 'undefined')return;
455                          bookmark(tags, comment);
456                  }
457                  // comment only
458                  if(!args.find("--tag") && args.find("--comment")){
459                          m_comment.complete(function(comment){
460                                  m_comment_callback(user_tags, comment);
461                          });
462                          return stdin
463                  }
464
465                  var m_tag = window.Minibuffer.getMinibuffer().setSeparator(' ').setPrompt('Tags:');
466                  m_tag.bindSPC = function(){
467                          var i=this.html.input, b=i.selectionStart, str=i.value;
468                          var trim = function(str){
469                                  return str.replace(/^\s|\s$/g,'');
470                          }
471                          i.value = trim(str.slice(0,b)) + ' ' + trim(str.slice(b));
472                          var p = i.selectionEnd + this.separator.length;
473                          i.setSelectionRange(p,p);
474                          // eliminate highlight
475                          var c = this.html.completion;
476                          var last = this.current != -1 && c.childNodes[this.current];
477                          this.selectCandidate(null, last);
478                          this.updateComplationList();
479                  }
480                  m_tag.shortcutkey.addCommand({key:'|',   command:function(){m_tag.bindInputChar('|')}});
481                  m_tag.shortcutkey.addCommand({key:'SPC', command:function(){m_tag.bindSPC.call(m_tag)}});
482                  m_tag.shortcutkey.addCommand({key:'TAB', command:function(){m_tag.bindSelectNext()}});
483                  m_tag.shortcutkey.addCommand({key:'C-i', command:function(){m_tag.bindSelectNext()}});
484
485                  var m_tag_callback = function(tags){
486                          if(typeof tags == 'undefined')return;
487                          tags = /^\s*$/.test(tags) ? [] : tags.split(/\s+/);
488                          // tag and comment
489                          if(args.find("--comment")){
490                              m_comment.complete(function(comment){
491                                      m_comment_callback(tags, comment);
492                              });
493                          }else{
494                              // tag only
495                              bookmark(tags, user_comment);
496                          }
497                  }
498                  var _tags = getTags();
499                  if(!_tags.length){
500                          window.Minibuffer.status('bookmark.gettag', 'Getting tags ...')
501                          var arr = [];
502                          keys(BookmarkL).forEach(function (name) {
503                                  if (typeof BookmarkL[name].getTags == 'function') arr.push(BookmarkL[name].getTags);
504                          });
505                          AsyncList(arr.map(function(fn){
506                                  return fn();
507                          })).ready(function(tags_arr){
508                                  window.Minibuffer.status('bookmark.gettag', 'Getting tags done', 1000);
509                                  var tags = tags_arr.flatten().uniq().sort()
510                                  setTags(tags);
511                                  m_tag.setCandidates(tags).complete(m_tag_callback);
512                          })
513                  }else{
514                          m_tag.setCandidates(_tags).complete(m_tag_callback);
515                  }
516                  return stdin;
517          },
518        });
519
520        var getTargetCommand = function(){
521                var target_cmd = '';
522                if(window.location.href == "http://fastladder.com/reader/" ||
523                   window.location.href == "http://reader.livedoor.com/reader/"){
524                        target_cmd = 'pinned-or-current-link';
525                }else if(window.scrollY == 0){
526                        target_cmd = 'location';
527                }else if(window.LDRize){
528                        target_cmd = 'pinned-or-current-node';
529                }else{
530                        target_cmd = 'location';
531                }
532                return target_cmd;
533        }
534
535        window.Minibuffer.addShortcutkey({
536          key: 'b',
537          description: 'Bookmark',
538          command: function(){
539                  var target_cmd = getTargetCommand();
540                  window.Minibuffer.execute(target_cmd + ' | bookmark ' + SBM + ' "--tag=' + TAG + '"');
541          }});
542        window.Minibuffer.addShortcutkey({
543          key: 'B',
544          description: 'Bookmark with tags and comment',
545          command: function(){
546                  var target_cmd = getTargetCommand();
547                  window.Minibuffer.execute(target_cmd + ' | bookmark ' + SBM + ' --tag --comment');
548          }});
549        window.Minibuffer.addCommand({
550          name: 'bookmark.update-tags',
551          command: function(){setTags([])}
552        });
553
554        // library
555        Array.prototype.position = function(obj){
556                var test = (typeof(obj) == 'function') ? obj : function(a){return a == obj};
557                for(var i=0;i<this.length; i++) if(test(this[i], i)) return i;
558                return false;
559        }
560        Array.prototype.find = function(obj){
561                var i = this.position(obj);
562                return typeof(i) == 'number' ? this[i] : false;
563        }
564        Array.prototype.uniq = function(){
565                var tmp = {};
566                for(var i=0,l=this.length; i<l; i++) tmp[this[i]] = true;
567                return keys(tmp);
568        }
569        Array.prototype.flatten = function(){ // only 1 level
570                var tmp = [];
571                for(var i=0,l=this.length; i<l; i++){
572                        if(this[i] instanceof Array) tmp = tmp.concat(this[i]);
573                        else tmp.push(this[i]);
574                }
575                return tmp;
576        }
577        // from jautopagireze.user.js
578        function createHTMLDocument (title) {
579                // Firefox doesn't have createHTMLDocument
580                if (!document.implementation.createHTMLDocument) {
581                        // Maybe this is the best way to create HTMLDocument, but not worked in any browser...
582                        // var html4dt = document.implementation.createDocumentType("HTML", "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd");
583                        // var d = document.implementation.createDocument("", "HTML", html4dt);
584                        // return d;
585
586                        // In Firefox
587                        // Try to create HTMLDocument from XSLT with <xsl:output method='html'/>
588                        if (typeof XSLTProcessor != "undefined") {
589                                // Using createContextualFragment to avoid https://bugzilla.mozilla.org/show_bug.cgi?id=212362
590                                // (problem of URI of document created by DOMParser and XSLT URI)
591                                var x = new XSLTProcessor();
592                                var t = [
593                                        "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>",
594                                        "<xsl:output method='html'/>",
595                                        "<xsl:template match='/'>",
596                                        "<html><head><title>", title, "</title></head><body/></html>",
597                                        "</xsl:template>",
598                                        "</xsl:stylesheet>",
599                                        ].join("");
600                                var d = document.implementation.createDocument("", "nice-boat", null);
601                                var r = d.createRange();
602                                r.selectNodeContents(d.documentElement);
603                                try {
604                                        d.documentElement.appendChild(r.createContextualFragment(t));
605                                } catch(e) {
606                                        // TODO: Firefox 2.0.0.10 does not work on this part.
607                                        return null;
608                                }
609                                x.importStylesheet(d.documentElement.firstChild);
610                                var ret = x.transformToDocument(d);
611                                // if the returned value is not HTMLDocument, this function returns null.
612                                return ret.body ? ret : null;
613                        } else {
614                                return null;
615                        }
616                } else {
617                        return document.implementation.createHTMLDocument(title);
618                }
619        }
620        String.prototype.createHTML = function() {
621                var s = this.replace(/<script[ \t\r\n<>][\S\s]*?<\/script(?:[ \t\r\n]*>|[ \t\r\n]+)|<(?:i?frame|html|object|script)(?:[ \t\r\n][^<>]*(?:>|(?=<))|[ \t\r\n]*>)|<\/(?:i?frame|html|object|script)(?:[ \t\r\n]*>|[ \t\r\n]+)/gi, "");
622                var d = createHTMLDocument();
623                if (d) {
624                        while (d.documentElement.firstChild) d.documentElement.removeChild(d.documentElement.firstChild);
625                        var r = d.createRange();
626                        r.selectNodeContents(d.documentElement);
627                        d.documentElement.appendChild(r.createContextualFragment(s));
628                        return d;
629                } else {
630                        function createDocumentFragmentByString(str) {
631                                var range = document.createRange();
632                                range.setStartAfter(document.body);
633                                return range.createContextualFragment(str);
634                        }
635                        var htmlDoc = document.implementation.createDocument(null, 'html', null);
636                        htmlDoc.documentElement.appendChild(createDocumentFragmentByString(s));
637                        return htmlDoc;
638                }
639        }
640        function keys(hash){
641                var tmp = [];
642                for(var key in hash) if(hash.hasOwnProperty(key)) tmp.push(key);
643                return tmp;
644        }
645        var $X = window.Minibuffer.$X
646        function log() {if(console) console.log.apply(console, Array.slice(arguments));}
647        function group() {if(console) console.group.apply(console, Array.slice(arguments))}
648        function groupEnd() {if(console) console.groupEnd();}
649
650
651        // original code by cho45
652        // http://svn.coderepos.org/share/lang/javascript/userscripts/jautopagerize.user.js
653        // Async is similar to Mochikit Deferred.
654        function Async () { this.init.apply(this, arguments) }
655        Async.prototype = {
656                init : function () {
657                        this.chain = { ok: [], ng: [] };
658                },
659                ready : function (value) {
660                        return this.call("ok", value);
661                },
662                error : function (value) {
663                        return this.call("ng", value);
664                },
665                call : function (okng, value) {
666                        if (typeof value == "function") {
667                                this.chain[okng].push(value);
668                        } else { try {
669                                var c = this.chain[okng];
670                                for (var i = 0; i < c.length; i++) {
671                                        c[i](value);
672                                }
673                        } catch (e) { this.call("ng", e) } }
674                        return this;
675                }
676        };
677        function AsyncList (asyncs) {
678                var ret = new Async();
679                var values = [];
680                asyncs.forEach(function (a, i) {
681                        a.ready(function (v) {
682                                asyncs.pop();
683                                values[i] = v;
684                                if (asyncs.length == 0) {
685                                        ret.ready(values);
686                                }
687                        });
688                        a.error(function (v) {
689                                ret.error(v);
690                        });
691                        values.push(null);
692                });
693                return ret;
694        }
695
696
697        function AsyncOrderedList (func, arr) {
698                var ret = new Async();
699                var values = [];
700                var asyncs = [];
701                arr.forEach(function (x, i) {
702                        var a = new Async();
703                        a.ready(function (v) {
704                                values.push(v);
705                                if(asyncs.length == 0){
706                                        ret.ready(values);
707                                }else{
708                                        func(asyncs.shift(), arr.shift(), i, values);
709                                }
710                        });
711                        a.error(function (v) {
712                                ret.error(v);
713                        });
714                        asyncs.push(a);
715                });
716                func(asyncs.shift(), arr.shift(), values);
717                return ret;
718        }
719        window.MinibufferBookmark = {
720                $X : $X,
721                log : log,
722                addBookmark : addBookmark,
723                setTags : setTags,
724                getTags : getTags,
725                keys : keys,
726                group : group,
727                groupEnd : groupEnd,
728                Async : Async,
729                AsyncList : AsyncList,
730                AsyncOrderedList : AsyncOrderedList,
731                createHTML : String.prototype.createHTML,
732        };
733};
734
735// Based on AutoPagerize.addFilter workaround
736var i=4;
737function waitMinibuffer() {
738        if(window.Minibuffer && window.Minibuffer.addCommand) {
739                runMinibufferBookmarkCommand();
740        } else if(i-- > 0) {
741                setTimeout(arguments.callee, 500);
742        }
743}
744waitMinibuffer();
Note: See TracBrowser for help on using the browser.