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

Revision 32139, 7.7 kB (checked in by teramako, 17 months ago)

fix close method

Line 
1let PLUGIN_INFO =
2<VimperatorPlugin>
3<name>{NAME}</name>
4<description>search DeliciousBookmark and that completer</description>
5<require type="extension" id="{2fa4ed95-0317-4c6a-a74c-5f3e3912c1f9}">Delicious Bookmarks</require>
6<author mail="teramako@gmail.com" homepage="http://vimperator.g.hatena.ne.jp/teramako/">teramako</author>
7<version>0.3</version>
8<minVersion>2.0pre</minVersion>
9<maxVersion>2.0</maxVersion>
10<detail><![CDATA[
11== Command ==
12:ds[earch] -tags tag, ...:
13:delicious[search] -tags tag, ...:
14  search bookmark contains all tags
15
16:ds[earch] -query term:
17:delicious[search] -query term:
18  search bookmark contains term in the titile or the URL or the note
19
20== Completion ==
21:open or :tabopen command completion
22
23>||
24set complete+=D
25||<
26
27or write in RC file
28
29>||
30autocmd VimperatorEnter ".*" :set complete+=D
31||<
32
33== guioptions ==
34show Delicious Toolbar or not
35>||
36set go+=D
37or
38set go-=D
39||<
40
41]]></detail>
42</VimperatorPlugin>;
43
44liberator.plugins.delicious = (function(){
45
46let uuid = PLUGIN_INFO.require[0].@id.toString();
47if (Application.extensions.has(uuid) && Application.extensions.get(uuid).enabled){
48  const ydls = Cc["@yahoo.com/nsYDelLocalStore;1"].getService(Ci.nsIYDelLocalStore);
49} else {
50  return null;
51}
52const ss = Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
53
54// dabase connection object
55let dbc = null;
56
57// sql statements
58let statements = {
59  allTags: null,
60  simpleQuery: null,
61};
62
63/**
64 * return Delicious bookmark batabase file
65 * @return {nsIFile}
66 */
67function getBookmarkFile(){
68  let file = services.get("directory").get("ProfD",Ci.nsIFile)
69  file.append("ybookmarks.sqlite");
70  if (!file.exists() || !file.isReadable()){
71    return null;
72  }
73  return file;
74}
75
76/**
77 * get all tag names from Delicious Bookmark
78 * @return {String[]}
79 */
80function getAllTags(){
81  let list = [];
82  let st = statements.allTags;
83  try {
84    while (st.executeStep()){
85      list.push(st.getString(0));
86    }
87  } finally {
88    st.reset();
89  }
90  return list;
91}
92/**
93 * @param {CompetionContext} context
94 * @param {Array} args
95 * @return {Array}
96 */
97function tagCompletion(context, args){
98  let filter = context.filter;
99  let have = filter.split(",");
100  args.completeFilter = have.pop();
101  let prefix = filter.substr(0, filter.length - args.completeFilter.length);
102  let tags = getAllTags();
103  return [[prefix + tag, tag] for ([i, tag] in Iterator(tags)) if (have.indexOf(tag)<0)];
104}
105/**
106 * search Delicious Bookmarks
107 * contains all tags and query in title or URL or Note
108 * @param {String[]} tags
109 * @param {String} query
110 * @return {Array[]} [[url, title, note], ...]
111 *         if both tags and query is none, returns []
112 */
113function bookmarkSearch(tags, query){
114  if (!query && (!tags || tags.length == 0))
115    return [];
116
117  let sql;
118  let list = [];
119  let st;
120  let finalize = true;
121  try {
122    if (!tags || tags.length == 0){
123      st = statements.simpleQuery;
124      st.bindUTF8StringParameter(0, '%' + query + '%');
125      finalize = false;
126    }  else {
127      let sqlList = [
128        'SELECT b.name,b.url,b.description',
129        'FROM bookmarks b, bookmarks_tags bt, tags t',
130        'WHERE bt.tag_id = t.rowid',
131        'AND b.rowid = bt.bookmark_id',
132        'AND t.name in (',
133        ['?' + (parseInt(i)+1) for (i in tags)].join(","),
134        ')'];
135      if (query){
136        let num = tags.length + 1;
137        sqlList.push([
138          'AND (',
139          'b.name like', '?' + num,
140          'OR b.url like', '?' + num,
141          'OR b.description like', '?' + num,
142          ')',
143          'GROUP BY b.rowid HAVING COUNT (b.rowid) = ?' + (num + 1),
144          'ORDER BY b.added_date DESC'
145        ].join(" "));
146        sql = sqlList.join(" ");
147        st = dbc.createStatement(sql);
148        st.bindUTF8StringParameter(tags.length, '%'+query+'%');
149        st.bindInt32Parameter(tags.length+1, tags.length);
150      } else {
151        sqlList.push([
152          'GROUP BY b.rowid HAVING COUNT (b.rowid) = ?' + (tags.length + 1),
153          'ORDER BY b.added_date DESC'
154        ].join(" "));
155        sql = sqlList.join(" ");
156        st = dbc.createStatement(sql);
157        st.bindInt32Parameter(tags.length, tags.length);
158      }
159      for (let i in tags){
160        st.bindUTF8StringParameter(i, tags[i]);
161      }
162    }
163    while (st.executeStep()){
164      let url = st.getString(1);
165      list.push({
166        url: url,
167        name: st.getString(0),
168        note: st.getString(2),
169        icon: bookmarks.getFavicon(url),
170        tags: ydls.getTags(url, {})
171      });
172    }
173  } finally {
174    st.reset();
175    if (finalize) st.finalize();
176  }
177  return list;
178}
179function templateDescription(item){
180  return (item.tags && item.tags.length > 0 ? "[" + item.tags.join(",") + "]" : "") + item.note;
181}
182function templateTitleAndIcon(item){
183  let simpleURL = item.text.replace(/^https?:\/\//, '');
184  return <>
185    <span highlight="CompIcon">{item.icon ? <img src={item.icon}/> : <></>}</span><span class="td-strut"/>{item.name}<a href={item.text} highlight="simpleURL">
186      <span class="extra-info">{simpleURL}</span>
187    </a>
188  </>;
189}
190
191commands.addUserCommand(["delicious[search]","ds[earch]"], "Delicious Bookmark Search",
192  function(args){
193    if (args.length > 0){
194      liberator.open(args[0], liberator.CURRENT_TAB);
195      return;
196    }
197    let list = bookmarkSearch(args["-tags"], args["-query"]);
198    let xml = template.tabular(["Title","Tags and Note"], [], list.map(function(item){
199      return [
200        <><img src={item.icon}/><a highlight="URL" href={item.url}>{item.name}</a></>,
201        "[" + item.tags.join(",") + "] " + item.note
202      ];
203    }));
204    liberator.echo(xml, true);
205  },{
206    options: [
207      [["-tags","-t"], commands.OPTION_LIST, null, tagCompletion],
208      [["-query","-q"], commands.OPTION_STRING]
209    ],
210    completer: function(context, args){
211      context.format = {
212        anchored: true,
213        title: ["Title and URL", "Tags and Note"],
214        keys: { text: "url", name: "name", icon: "icon", tags: "tags", note: "note"},
215        process: [templateTitleAndIcon, templateDescription],
216      };
217      context.filterFunc = null;
218      context.regenerate = true;
219      context.generate = function() bookmarkSearch(args["-tags"], args["-query"]);
220    },
221  },true);
222
223let self = {
224  init: function(){
225    if (dbc){
226      try {
227        this.close();
228      } catch(e) {}
229    }
230    let file = getBookmarkFile();
231    if (!file) return;
232    dbc = ss.openDatabase(file);
233
234    statements.allTags = dbc.createStatement("SELECT name FROM tags");
235    statements.simpleQuery = dbc.createStatement([
236      'SELECT name,url,description FROM bookmarks',
237      'WHERE name like ?1 OR',
238      'url like ?1 OR',
239      'description like ?1',
240      'ORDER BY added_date DESC'
241    ].join(" "));
242  },
243  get tags(){
244    return getAllTags();
245  },
246  /**
247   * @see bookmarkSearch
248   */
249  search: function(tags, query){
250    return bookmarkSearch(tags, query);
251  },
252  /**
253   * used by completion
254   * :set complete+=D
255   * @param {CompletionContext} context
256   */
257  urlCompleter: function(context){
258    context.format = {
259      anchored: true,
260      title: ["Delicious Bookmarks"],
261      keys: { text: "url", name: "name", icon: "icon", tags: "tags", note: "note"},
262      process: [templateTitleAndIcon, templateDescription],
263    };
264    context.filterFunc = null;
265    context.regenerate = true;
266    context.generate = function() bookmarkSearch([], context.filter);
267  },
268  close: function(){
269    for each(let st in statements){
270      if (st.state > 0)
271        st.finalize();
272    }
273    if (dbc.connectionReady)
274      dbc.close();
275  },
276};
277self.init();
278liberator.registerObserver("shutdown", self.close);
279config.guioptions['D'] = ['Delicious Toolbar',['ybToolbar']];
280completion.addUrlCompleter("D", "Delicious Bookmarks", self.urlCompleter);
281return self;
282})();
283function onUnload(){
284  liberator.plugins.delicious.close();
285}
286// vim: sw=2 ts=2 et:
Note: See TracBrowser for help on using the browser.