root/lang/javascript/vimperator-plugins/trunk/pino.js

Revision 37934, 10.8 kB (checked in by anekos, 8 weeks ago)

タブを開く間隔を指定可能に

Line 
1//
2//  pino.js  - Open livedoor Reader (and clone server) pinned items -
3//
4// LICENSE: {{{
5//
6// This software distributable under the terms of an MIT-style license.
7//
8// Copyright (c) 2009 snaka<snaka.gml@gmail.com>
9//
10// Permission is hereby granted, free of charge, to any person obtaining a copy
11// of this software and associated documentation files (the "Software"), to deal
12// in the Software without restriction, including without limitation the rights
13// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14// copies of the Software, and to permit persons to whom the Software is
15// furnished to do so, subject to the following conditions:
16//
17// The above copyright notice and this permission notice shall be included in
18// all copies or substantial portions of the Software.
19//
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26// THE SOFTWARE.
27//
28// OSI page : http://opensource.org/licenses/mit-license.php
29// Japanese : http://sourceforge.jp/projects/opensource/wiki/licenses%2FMIT_license
30//
31// }}}
32// PLUGIN INFO: {{{
33var PLUGIN_INFO =
34<VimperatorPlugin>
35  <name>{NAME}</name>
36  <description>Open livedoor Reader pinned items</description>
37  <description lang="ja">livedoor Reader でピンを立てたページを開く</description>
38  <minVersion>2.3</minVersion>
39  <maxVersion>2.4</maxVersion>
40  <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/pino.js</updateURL>
41  <require type="plugin">_libly.js</require>
42  <author mail="snaka.gml@gmail.com" homepage="http://vimperator.g.hatena.ne.jp/snaka72/">snaka</author>
43  <license>MIT style license</license>
44  <version>1.4.0</version>
45  <detail><![CDATA[
46    == Subject ==
47    Open livedoor Reader pinned items.
48
49    == Commands ==
50    :[count]pino
51      Following option is avilable.
52      -list:
53        Show pinned item list.
54
55    == Global variables ==
56    g:pinoOpenItemsCount:
57      default: 5
58
59    g:pinoOpenBehavior:
60      default: liberator.NEW_BACKGROUND_TAB
61
62    g:pinoAscendingOrder:
63      default: "false"
64
65    g:pinoBaseURL:
66      If you want to use fastladder, set "http://fastladder.com" into this variable.
67      default: "http://reader.livedoor.com"
68
69    g:pinoOpenInterval:
70      Interval of opening tabs. (msec)
71
72    == API ==
73    plugins.pino.items():
74      Return pinned items list array.
75      Each item is following structure.
76      >||
77      {
78         created_on : (create date),
79         link : (url),
80         title : (page title)
81      }
82      ||<
83
84    plugins.pino.shift():
85      Return first item and remove pin.
86
87    plugins.pino.remove(link):
88      Remove pin from item that matched by 'link'.
89
90  ]]></detail>
91  <detail lang="ja"><![CDATA[
92    == 概要 ==
93    livedoor Reader でピンを立てた記事をVimperatorのコマンドラインから開く
94    ことができます。
95
96    == コマンド ==
97    :[count]pino:
98      そのまま<Enter>で先頭のn件(デフォルト5件、グローバル変数で調整可能)
99      をバックグラウンドのタブで開きます。
100      <TAB>で補完候補の一覧にピンを立てた記事の一覧から選択することもできます。
101      count を指定すると、その件数だけ開きます。
102      以下のオプションが指定可能です。
103      -list:
104        ピンの一覧を表示します。
105
106    == グローバル変数 ==
107    g:pinoOpenItemsCount:
108      一度に開くピンの数
109      default: 5
110
111    g:pinoOpenBehavior:
112      ピンを開くときの挙動、liberator.open()の第2引数として使用する値
113      参考)http://wiki.livedoor.jp/shin_yan/d/liberator%282%2e0%29#content_34
114      default: liberator.NEW_BACKGROUND_TAB
115
116    g:pinoAscendingOrder:
117      ピンの一覧の表示順を昇順(古い順)とするかどうか
118      default: "false" (新しい順)
119
120    g:pinoBaseURL:
121      fastladder を使う場合は、この変数を "http://fastladder.com" とする。
122      default: "http://reader.livedoor.com"
123
124    g:pinoOpenInterval:
125      タブを開く間隔(ミリ秒)
126
127    == API ==
128    plugins.pino.items():
129      ピンの一覧を配列で取得する。
130      ピンのデータ構造は以下のとおりとなっている。
131      >||
132      {
133         created_on : (create date),
134         link : (url),
135         title : (page title)
136      }
137      ||<
138
139    plugins.pino.shift():
140      先頭のピンを取得して、そのピンを一覧から削除する。
141
142    plugins.pino.remove(link):
143      linkに該当するピンを一覧から削除する。
144
145  ]]></detail>
146</VimperatorPlugin>;
147// }}}
148let self = liberator.plugins.pino = (function() {
149  // COMMAND /////////////////////////////////////////////////////// {{{
150  commands.addUserCommand(
151    ["pinneditemopen", "pino"],
152    "Open livedoor Reader(and clone server) pinned item",
153    function(args) {
154      let pins = new Pins();
155      let items = pins.items();
156      if (!items || items.length == 0) {
157        liberator.echo("Pinned item doesn't exists.");
158        return;
159      }
160
161      if (args["-list"]) {
162        //let items = pins.items();
163        let list = <div>{items.length} items.
164                    <ul>{
165                      [<li><a href={i.link}>{i.title}</a><br/></li>
166                        for each (i in items)
167                      ].reduce(function(a, b) a + b)
168                    }</ul>
169                   </div>;
170        liberator.echo(list, commandline.FORCE_MULTILINE);
171        return;
172      }
173
174      if (args.string == "") {
175        let pin;
176        let max = (args.count >= 1) ? args.count : openItemsCount();
177        for(let i = 0; i < max; i++) {
178          if (!(pin = pins.shift()))
179            break;
180          setTimeout(function(link) liberator.open(link, openBehavior()), openInterval() * i, pin.link);
181        }
182      }
183      else {
184        liberator.open(args.string, openBehavior());
185        pins.remove(args.string);
186      }
187    },
188    {
189      literal: 0,
190      count: true,
191      completer: function(context) {
192        var pins = new Pins();
193        context.title = ["url", "title"];
194        context.filters = [CompletionContext.Filter.textDescription];
195        context.anchored = false;
196        context.completions = [
197          [i.link, i.title] for each (i in pins.items())
198        ];
199      },
200      options: [
201        [["-list", "-l"], commands.OPTION_NOARG]
202      ]
203    },
204    true    // for Debug
205  );
206  // }}}
207  // GLOBAL VARIABLES ////////////////////////////////////////////// {{{
208  var gv = liberator.globalVariables;
209  function openItemsCount()
210    gv.pinoOpenItemsCount || 5;
211
212  function ascending()
213    window.eval(gv.pinoAscendingOrder) == true; // default: false
214
215  function openBehavior()
216    window.eval(gv.pinoOpenBehavior) || liberator.NEW_BACKGROUND_TAB;
217
218  function baseURL()
219    gv.pinoBaseURL || "http://reader.livedoor.com";
220
221  function openInterval()
222    gv.pinoOpenInterval || 200;
223
224  // }}}
225  // CLASS ///////////////////////////////////////////////////////// {{{
226
227  function Pins() {
228    this.cache = null;
229    this.apiKey = getLDRApiKey();
230    this.sortOrder = ascending()
231                      ? function(a, b) (a.created_on < b.created_on ? -1 : 1)
232                      : function(a, b) (a.created_on > b.created_on ? -1 : 1);
233  }
234  Pins.prototype = {
235    items : function() {
236      let result = this.cache
237              ? this.cache
238              : this.cache = this._getPinnedItems();
239      return (result || []).sort(this.sortOrder);
240    },
241
242    shift : function() {
243      if (this.items().length == 0)
244        return null;
245      var pin = this.items().shift();
246      this.remove(pin.link);
247      return pin;
248    },
249
250    remove : function(link) {
251      var unescapedLink = unescapeHTML(link);
252      var request = new libly.Request(
253        baseURL() + "/api/pin/remove",
254        {
255          //Cookie: "reader_sid=" + this.apiKey,
256          //Referer: "http://reader.livedoor.com/reader/"
257        },
258        {
259          postBody: toQuery({link: unescapedLink, ApiKey: this.apiKey})
260        }
261      );
262
263      request.addEventListener("onSuccess", function(data) {
264        liberator.log("Removed pin from '" + link + "' was succeeded.");
265      });
266      request.addEventListener("onFailure", function(data) {
267        liberator.echoerr("Cannot remove pin");
268      });
269      request.post();
270    },
271
272    _getPinnedItems : function() {
273      var result = null;
274      var request = new libly.Request(
275          baseURL() + "/api/pin/all",
276          null,
277          {
278            asynchronous: false,
279            postBody: toQuery({ApiKey: this.apiKey})
280          }
281      );
282
283      request.addEventListener("onSuccess", function(data) {
284        if (isLoginPage(data)) {
285          liberator.echoerr("Can't get pinned list. Maybe you should login to livedoor.");
286          return;
287        }
288        result = liberator.eval(data.responseText);
289      });
290      request.addEventListener("onFailure", function(data) {
291        liberator.echoerr("Can't get pinned list!!!");
292      });
293      request.post();
294
295      return result;
296    },
297  }
298  // }}}
299  // FUNCTIONS ///////////////////////////////////////////////////// {{{
300  var libly = plugins.libly;
301
302  function getLDRApiKey() {
303    var ioService = Cc["@mozilla.org/network/io-service;1"]
304                    .getService(Ci.nsIIOService);
305    var uri = ioService.newURI(baseURL(), null, null);
306    var channel = ioService.newChannelFromURI(uri);
307    var cookie = Cc["@mozilla.org/cookieService;1"]
308                .getService(Ci.nsICookieService)
309                .getCookieString(uri, channel);
310    var apiKey = cookie.match(/reader_sid=([^;]+)/);
311    return apiKey ? apiKey[1]: null;
312  }
313
314  function unescapeHTML(source) {
315    var result = source;
316    [
317      [/&lt;/g,  "<"],
318      [/&gt;/g,  ">"],
319      [/&amp;/g, "&"]
320    ].forEach( function(rule) {
321      result = result.replace(rule[0], rule[1]);
322    });
323    return result;
324  }
325
326  function toQuery(source)
327    [encodeURIComponent(i) + "=" + encodeURIComponent(source[i])
328        for (i in source)
329    ].join('&');
330
331  function isLoginPage(response)
332    response.responseText.substr(0, 5) == '<?xml'
333
334  // }}}
335  // API /////////////////////////////////////////////////////////// {{{
336  return {
337    items : function()
338      (new Pins).items(),
339
340    shift : function()
341      (new Pins).shift(),
342
343    head : function()   // @deprecated
344      self.shift(),
345
346    remove : function(link)
347      (new Pins).remove(link),
348  };
349  // }}}
350})();
351// for backward compatibility
352self.api = {};
353for each (p in "items head remove".split(' '))
354  self.api[p] = self[p];
355// vim: ts=2 sw=2 et fdm=marker
Note: See TracBrowser for help on using the browser.