aboutsummaryrefslogtreecommitdiffstats
path: root/simg.js
blob: 8100db0c841d75e7fd7c804b261d2fa1d26f88e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// INFO //
var INFO =
<plugin name="simg.js" version="0.3"
        summary="Save image on contents area"
        href="http://github.com/vimpr/vimperator-plugins/blob/master/simg.js"
        xmlns="http://vimperator.org/namespaces/liberator">
  <author email="mitsugu.oyama@gmail.com">Mitsugu Oyama</author>
  <license href="http://opensource.org/licenses/mit-license.php">MIT</license>
  <project name="Vimperator" minVersion="2.3"/>
  <p>
    You can save image on the currnet context area by this plugin.
  </p>
  <item>
    <tags>'simg'</tags>
    <spec>:simg</spec>
    <description>
      <p>You can save image on the currnet context area by this plugin.</p>
    </description>
  </item>
</plugin>;

commands.addUserCommand(
  ['simg'],
  'Save Image File current page',
  function(){
    let contents=gBrowser.selectedBrowser.contentDocument;
    let Cc=Components.classes;
    let Ci=Components.interfaces;
    let cookie=contents.cookie;
    let xhrImg;

    let directoryPicker=function() {
      let path;
      let fp=Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
      fp.init(window,'Select Directory',Ci.nsIFilePicker.modeGetFolder);
      let result=fp.show();
      switch(result){
        case Ci.nsIFilePicker.returnOK:
          path=fp.file.path;
          break;
        default:
        case Ci.nsIFilePicker.returnCancel:
          return '';
      }
      return path;
    };

    let saveDirectory=directoryPicker();
    if(saveDirectory.length<1) return;
    let imgURL=contents.URL;
    let savePath;

    let trueCurrntImg=function(){
      let fileName=imgURL.substr(imgURL.lastIndexOf('/'));
      if (-1!=fileName.indexOf('?')){
        fileName=fileName.substr(0,fileName.indexOf('?'));
      }
      savePath=saveDirectory+fileName;
      let instream=xhrImg.responseText;
      let aFile=Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
      aFile.initWithPath(savePath);
      if(true===aFile.exists()){
        let value=window.prompt('すでに同じ名前のファイルがあります。デフォルトファイル名を変更してください。',fileName.substr(1));
        if(null===value){
          return false;
        }
        fileName='/'+value;
        savePath=saveDirectory+fileName;
        aFile.initWithPath(savePath);
      }
      let outstream=Cc["@mozilla.org/network/safe-file-output-stream;1"]
        .createInstance(Ci.nsIFileOutputStream);
      outstream.init(aFile,0x02|0x08|0x20,0664,0);
      outstream.write(instream,instream.length);
      if (outstream instanceof Ci.nsISafeOutputStream) {
        outstream.finish();
      }else{
        outstream.close();
      }
    };
    let falseCurrntImg=function(){
      liberator.echo("Image file accept error.");
      return false;
    };

    xhrImg=Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
      .createInstance();
    xhrImg.QueryInterface(Ci.nsIDOMEventTarget);
    xhrImg.addEventListener("load",trueCurrntImg,false);
    xhrImg.addEventListener("error",falseCurrntImg,false);
    xhrImg.QueryInterface(Ci.nsIXMLHttpRequest);
    xhrImg.open("GET",imgURL,true);
    xhrImg.overrideMimeType('text/plain;charset=x-user-defined');
    xhrImg.setRequestHeader('Referer',contents.URL);
    xhrImg.setRequestHeader('Cookie',cookie);
    xhrImg.send(null);
  }
);
tatus=", stat, keyword ? "&keyword=" + encodeURIComponent(keyword) : id ? "&in_reply_to_status_id=" + id : "", "&source=" + CLIENT_NAME ].join(''); //liberator.log('xhr.send(' + senddata +')',0); xhr.send(senddata); } function favHaiku(username, password, user){ var xhr = new XMLHttpRequest(); xhr.open("POST", "http://h.hatena.ne.jp/api/statuses/user_timeline/" + user + ".json", false, username, password); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(null); xhr.open("POST", "http://h.hatena.ne.jp/api/favorites/create/" + evalFunc(xhr.responseText)[0].id + '.json', false, username, password); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(null); } function unfavHaiku(username, password, user){ var xhr = new XMLHttpRequest(); xhr.open("POST", "http://h.hatena.ne.jp/api/statuses/user_timeline/" + user + ".json?count=1", false, username, password); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(null); xhr.open("POST", "http://h.hatena.ne.jp/api/favorites/destroy/" + evalFunc(xhr.responseText)[0].id + '.json', false, username, password); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(null); } function isValidStatusID(id){ if (!statuses) return false; return statuses.some(function(status) status.id == id); } function getStatusIDFromUserID(userid){ if (!statuses) return null; return statuses.filter(function(status) status.in_reply_to_user_id == userid)[0].id; } function getTimelineURLFromTarget(target){ if (target == "/"){ return "http://h.hatena.ne.jp/api/statuses/public_timeline.json"; } else if (target == "album"){ return "http://h.hatena.ne.jp/api/statuses/album.json"; } else if (/^#(.+)/.test(target)){ return "http://h.hatena.ne.jp/api/statuses/keyword_timeline/" + encodeURIComponent(RegExp.$1) + ".json"; } else if (/^@?(.+)/.test(target)){ return "http://h.hatena.ne.jp/api/statuses/user_timeline/" + RegExp.$1 + ".json"; } return "http://h.hatena.ne.jp/api/statuses/friends_timeline.json"; } function statusToXML(statuses){ var html = <style type="text/css"><![CDATA[ span.haiku.entry-title { text-decoration: underline; } .haiku.entry-content { white-space: normal; } .haiku.entry-content a { text-decoration: none; } dl.haiku { margin-left: 1em; } img.haiku.photo { border; 0px; width: 16px; height: 16px; vertical-align: baseline; } ]]></style>; statuses.forEach(function(status) { var text = status.text; var keyword = status.keyword; var star = status.favorited > 0 ? <><img src="http://s.hatena.ne.jp/images/star.gif"/><span style="color:orange;">{'x' + status.favorited}</span></> : <></>; var replies = <></>; if (text.indexOf(keyword+"=") == 0) text = status.text.substr(keyword.length + 1); text = convert(text); keyword = convert(keyword); if (status.replies.length > 0){ replies = <dl class="haiku"></dl>; status.replies.forEach(function(rep){ replies.* += <> <dt> <img src={rep.user.profile_image_url} alt={rep.user.screen_name} class="haiku photo"/> <strong>{rep.user.name}</strong> </dt> <dd class="haiku entry-content">{rep.text.substr(keyword.length)}</dd> </>; }); } html += <> <div> <img src={status.user.profile_image_url} alt={status.user.screen_name} title={status.user.screen_name} class="haiku photo"/> <strong>{status.user.name}&#x202C;</strong> {star} <span>:</span> <span class="haiku entry-title">{keyword}</span><br/> <span class="haiku entry-content">{text}</span> </div> {replies} <hr/> </>; }); return html; } function showFollowersStatus(username, password, target){ var xhr = new XMLHttpRequest(); var endPoint = getTimelineURLFromTarget(target); xhr.open("POST", endPoint, false, username, password); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(null); statuses = evalFunc(xhr.responseText); var html = statusToXML(statuses); liberator.log(html.toXMLString(), 0); liberator.echo(html, true); } function convert(str){ function createHTML(all){ var str = all; if (all.indexOf("id:") == 0){ str = '<a href="http://h.hatena.ne.jp/' + all.replace(":", "/") + '">' + all + '</a>'; } else if (/\.(?:jpe?g|gif|png|bmp)$/.test(all)){ str = '<img src="' + all + '"/>'; } else if (/^http:\/\/(?:[^.]+\.)?youtube\.com\/(?:watch\?(?:[^&]+&)*v=|v\/)([^&=#?;\/]+)/.test(all)){ var url = "http://www.youtube.com/v/" + RegExp.$1 + "&amp;fs=1"; str = '<a href="#" class="hl-URL">' + url + '</a>' + '<div><object width="300" height="250" data="' + url + '" type="application/x-shockwave-flash">'+ '<param name="wmode" value="transparent"/><param name="allowFullScreen" value="true"/>'+ '</object></div>'; } else if (/^http:\/\/[^.]+\.nicovideo\.jp\/watch\/([-\w]+)$/.test(all)){ str = '<iframe width="312" height="176" src="http://ext.nicovideo.jp/thumb/'+RegExp.$1 + '" scrolling="no">'+ '<a href="' + all + '">' +all+'</a></iframe>'; } else if (all.charAt(0) == "["){ var keyword = all.substring(2, all.length -2); str = '<a href="http://h.hatena.ne.jp/keyword/' + keyword + '" class="hl-URL">' + keyword + '</a>'; } return str; } var str = str.replace(/&/g,"&amp;") .replace(/</g,"&lt;") .replace(/>/g,"&gt;") .replace(/\n/g,"<br/>") .replace(/\[\[[^\]]+\]\]|https?:\/\/[-\w!#$%&'()*+,.\/:;=?@~]+|id:[a-zA-Z][-\w]{1,30}[a-zA-Z\d]/g, createHTML); return new XMLList(str); } commands.addUserCommand(["haiku"], "Change Haiku status", function(args){ var special = args.bang; var password; var username; try { var logins = passwordManager.findLogins({}, 'http://h.hatena.ne.jp', null, 'http://h.hatena.ne.jp (API)'); if (logins.length) [username, password] = [logins[0].username, logins[0].password]; else { var ps = Cc['@mozilla.org/embedcomp/prompt-service;1'].getService(Ci.nsIPromptService); var [user,pass] = [{ value : '' }, { value : '' }]; var ret = ps.promptUsernameAndPassword( window, 'http://h.hatea.ne.jp (API)', 'Enter username and password.\nyou can get "password" from\n\thttp://h.hatena.ne.jp/api#auth', user, pass, null, {}); if(ret){ username = user.value; password = pass.value.replace(/@.*$/, ''); var nsLoginInfo = new Components.Constructor( '@mozilla.org/login-manager/loginInfo;1', Ci.nsILoginInfo, 'init'); loginInfo = new nsLoginInfo('http://h.hatena.ne.jp', null, 'http://h.hatena.ne.jp (API)', username, password, '', ''); passwordManager.addLogin(loginInfo); } else throw 'Haiku: account not found'; } } catch (ex){ liberator.echoerr(ex); } var arg = args.string.replace(/%URL%/g, buffer.URL) .replace(/%TITLE%/g, buffer.title); if (special && arg.match(/^\+\s*(.*)/)) favHaiku(username, password, RegExp.$1) else if (special && arg.match(/^-\s*(.*)/)) unfavHaiku(username, password, RegExp.$1) else if (special || arg.length == 0) showFollowersStatus(username, password, arg) else sayHaiku(username, password, arg); }, { bang: true, hereDoc: true, completer: function(context, args){ if (!statuses) return; var matches= context.filter.match(/^([@#]|[-+]\s*)(\S*)$/); if (!matches) return; var list = []; var [prefix, target] = [matches[1],matches[2]]; switch (prefix.charAt(0)){ case "+": case "-": if (!args.bang) return; case "@": context.title = ["ID","Entry"]; if (args.bang) list = statuses.map(function(entry) ["@" + entry.user.id, entry.text]); else list = statuses.map(function(entry) ["@" + entry.user.id + "#" + entry.id, entry.text]); break; case "#": context.title = ["Keyword","Entry"]; list = statuses.map(function(entry) ["#" + entry.keyword, entry.text]); break; } if (target){ list = list.filter(function($_) $_[0].indexOf(target) >= 0); } context.completions = list; } } ); })(); // vim:sw=4 ts=4 et: