root/lang/javascript/vimperator-plugins/branches/2.2/pino.js

Revision 33682, 10.5 kB (checked in by snaka, 16 months 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.0</minVersion>
39  <maxVersion>2.1</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.3.1</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    == API ==
70    plugins.pino.items():
71      Return pinned items list array.
72      Each item is following structure.
73      >||
74      {
75         created_on : (create date),
76         link : (url),
77         title : (page title)
78      }
79      ||<
80
81    plugins.pino.shift():
82      Return first item and remove pin.
83
84    plugins.pino.remove(link):
85      Remove pin from item that matched by 'link'.
86
87  ]]></detail>
88  <detail lang="ja"><![CDATA[
89    == 概要 ==
90    livedoor Reader でピンを立てた記事をVimperatorのコマンドラインから開く
91    ことができます。
92
93    == コマンド ==
94    :[count]pino:
95      そのまま<Enter>で先頭のn件(デフォルト5件、グローバル変数で調整可能)
96      をバックグラウンドのタブで開きます。
97      <TAB>で補完候補の一覧にピンを立てた記事の一覧から選択することもできます。
98      count を指定すると、その件数だけ開きます。
99      以下のオプションが指定可能です。
100      -list:
101        ピンの一覧を表示します。
102
103    == グローバル変数 ==
104    g:pinoOpenItemsCount:
105      一度に開くピンの数
106      default: 5
107
108    g:pinoOpenBehavior:
109      ピンを開くときの挙動、liberator.open()の第2引数として使用する値
110      参考)http://wiki.livedoor.jp/shin_yan/d/liberator%282%2e0%29#content_34
111      default: liberator.NEW_BACKGROUND_TAB
112
113    g:pinoAscendingOrder:
114      ピンの一覧の表示順を昇順(古い順)とするかどうか
115      default: "false" (新しい順)
116
117    g:pinoBaseURL:
118      fastladder を使う場合は、この変数を "http://fastladder.com" とする。
119      default: "http://reader.livedoor.com"
120
121    == API ==
122    plugins.pino.items():
123      ピンの一覧を配列で取得する。
124      ピンのデータ構造は以下のとおりとなっている。
125      >||
126      {
127         created_on : (create date),
128         link : (url),
129         title : (page title)
130      }
131      ||<
132
133    plugins.pino.shift():
134      先頭のピンを取得して、そのピンを一覧から削除する。
135
136    plugins.pino.remove(link):
137      linkに該当するピンを一覧から削除する。
138
139  ]]></detail>
140</VimperatorPlugin>;
141// }}}
142let self = liberator.plugins.pino = (function() {
143  // COMMAND /////////////////////////////////////////////////////// {{{
144  commands.addUserCommand(
145    ["pinneditemopen", "pino"],
146    "Open livedoor Reader(and clone server) pinned item",
147    function(args) {
148      let pins = new Pins();
149      let items = pins.items();
150      if (!items || items.length == 0) {
151        liberator.echo("Pinned item doesn't exists.");
152        return;
153      }
154
155      if (args["-list"]) {
156        //let items = pins.items();
157        let list = <div>{items.length} items.
158                    <ul>{
159                      [<li><a href={i.link}>{i.title}</a><br/></li>
160                        for each (i in items)
161                      ].reduce(function(a, b) a + b)
162                    }</ul>
163                   </div>;
164        liberator.echo(list, commandline.FORCE_MULTILINE);
165        return;
166      }
167
168      if (args.string == "") {
169        let pin;
170        let max = (args.count >= 1) ? args.count : openItemsCount();
171        for(let i = 0; i < max; i++) {
172          if (!(pin = pins.shift()))
173            break;
174          setTimeout(function(link) liberator.open(link, openBehavior()), 200 * i, pin.link);
175        }
176      }
177      else {
178        liberator.open(args.string, openBehavior());
179        pins.remove(args.string);
180      }
181    },
182    {
183      literal: 0,
184      count: true,
185      completer: function(context) {
186        var pins = new Pins();
187        context.title = ["url", "title"];
188        context.completions = [
189          [i.link, i.title] for each (i in pins.items())
190        ];
191      },
192      options: [
193        [["-list", "-l"], commands.OPTION_NOARG]
194      ]
195    },
196    true    // for Debug
197  );
198  // }}}
199  // GLOBAL VARIABLES ////////////////////////////////////////////// {{{
200  var gv = liberator.globalVariables;
201  function openItemsCount()
202    gv.pinoOpenItemsCount || 5;
203
204  function ascending()
205    window.eval(gv.pinoAscendingOrder) == true; // default: false
206
207  function openBehavior()
208    window.eval(gv.pinoOpenBehavior) || liberator.NEW_BACKGROUND_TAB;
209
210  function baseURL()
211    gv.pinoBaseURL || "http://reader.livedoor.com";
212
213  // }}}
214  // CLASS ///////////////////////////////////////////////////////// {{{
215
216  function Pins() {
217    this.cache = null;
218    this.apiKey = getLDRApiKey();
219    this.sortOrder = ascending()
220                      ? function(a, b) (a.created_on < b.created_on ? -1 : 1)
221                      : function(a, b) (a.created_on > b.created_on ? -1 : 1);
222  }
223  Pins.prototype = {
224    items : function() {
225      let result = this.cache
226              ? this.cache
227              : this.cache = this._getPinnedItems();
228      return (result || []).sort(this.sortOrder);
229    },
230
231    shift : function() {
232      if (this.items().length == 0)
233        return null;
234      var pin = this.items().shift();
235      this.remove(pin.link);
236      return pin;
237    },
238
239    remove : function(link) {
240      var unescapedLink = unescapeHTML(link);
241      var request = new libly.Request(
242        baseURL() + "/api/pin/remove",
243        {
244          //Cookie: "reader_sid=" + this.apiKey,
245          //Referer: "http://reader.livedoor.com/reader/"
246        },
247        {
248          postBody: toQuery({link: unescapedLink, ApiKey: this.apiKey})
249        }
250      );
251
252      request.addEventListener("onSuccess", function(data) {
253        liberator.log("Removed pin from '" + link + "' was succeeded.");
254      });
255      request.addEventListener("onFailure", function(data) {
256        liberator.echoerr("Cannot remove pin");
257      });
258      request.post();
259    },
260
261    _getPinnedItems : function() {
262      var result = null;
263      var request = new libly.Request(
264          baseURL() + "/api/pin/all",
265          null,
266          {
267            asynchronous: false,
268            postBody: toQuery({ApiKey: this.apiKey})
269          }
270      );
271
272      request.addEventListener("onSuccess", function(data) {
273        if (isLoginPage(data)) {
274          liberator.echoerr("Can't get pinned list. Maybe you should login to livedoor.");
275          return;
276        }
277        result = liberator.eval(data.responseText);
278      });
279      request.addEventListener("onFailure", function(data) {
280        liberator.echoerr("Can't get pinned list!!!");
281      });
282      request.post();
283
284      return result;
285    },
286  }
287  // }}}
288  // FUNCTIONS ///////////////////////////////////////////////////// {{{
289  var libly = plugins.libly;
290
291  function getLDRApiKey() {
292    var ioService = Cc["@mozilla.org/network/io-service;1"]
293                    .getService(Ci.nsIIOService);
294    var uri = ioService.newURI(baseURL(), null, null);
295    var channel = ioService.newChannelFromURI(uri);
296    var cookie = Cc["@mozilla.org/cookieService;1"]
297                .getService(Ci.nsICookieService)
298                .getCookieString(uri, channel);
299    var apiKey = cookie.match(/reader_sid=([^;]+)/);
300    return apiKey ? apiKey[1]: null;
301  }
302
303  function unescapeHTML(source) {
304    var result = source;
305    [
306      [/&lt;/g,  "<"],
307      [/&gt;/g,  ">"],
308      [/&amp;/g, "&"]
309    ].forEach( function(rule) {
310      result = result.replace(rule[0], rule[1]);
311    });
312    return result;
313  }
314
315  function toQuery(source)
316    [encodeURIComponent(i) + "=" + encodeURIComponent(source[i])
317        for (i in source)
318    ].join('&');
319
320  function isLoginPage(response)
321    response.responseText.substr(0, 5) == '<?xml'
322
323  // }}}
324  // API /////////////////////////////////////////////////////////// {{{
325  return {
326    items : function()
327      (new Pins).items(),
328
329    shift : function()
330      (new Pins).shift(),
331
332    head : function()   // @deprecated
333      self.shift(),
334
335    remove : function(link)
336      (new Pins).remove(link),
337  };
338  // }}}
339})();
340// for backward compatibility
341self.api = {};
342[
343  self.api[p] = self[p]
344    for each (p in "items head remove".split(' '))
345];
346// vim: ts=2 sw=2 et fdm=marker
Note: See TracBrowser for help on using the browser.