aboutsummaryrefslogtreecommitdiffstats
path: root/auto-focus-frame.js
blob: 9c1e60a2401dff81f10395cac2e0beaaa6931f05 (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
/* NEW BSD LICENSE {{{
Copyright (c) 2009, anekos.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. The names of the authors may not be used to endorse or promote products
       derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.


###################################################################################
# http://sourceforge.jp/projects/opensource/wiki/licenses%2Fnew_BSD_license       #
# に参考になる日本語訳がありますが、有効なのは上記英文となります。                #
###################################################################################

}}} */

// PLUGIN_INFO {{{
let PLUGIN_INFO =
<VimperatorPlugin>
  <name>Auto focus frame</name>
  <description>Automatically focus to largest frame.</description>
  <description lang="ja">最も大きなフレームに自動的にフォーカスする</description>
  <version>1.0.9</version>
  <author mail="anekos@snca.net" homepage="http://d.hatena.ne.jp/nokturnalmortum/">anekos</author>
  <license>new BSD License (Please read the source code comments of this plugin)</license>
  <license lang="ja">修正BSDライセンス (ソースコードのコメントを参照してください)</license>
  <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/auto-focus-frame.js</updateURL>
  <minVersion>2.0</minVersion>
  <maxVersion>2.2pre</maxVersion>
  <detail><![CDATA[
    == Usage ==
      Only install.
  ]]></detail>
  <detail lang="ja"><![CDATA[
    == Usage ==
      インストールするだけ
      一番面積の大きいフレームをフォーカスします
  ]]></detail>
</VimperatorPlugin>;
// }}}

(function () {

  function onLoad () {
    if (!(window.content.document instanceof HTMLDocument) || (content.frames.length <= 1))
      return;

    let targetFrames = [
      frame
      for (frame in util.Array.itervalues(content.frames))
      if (frame.frameElement instanceof HTMLFrameElement)
    ];

    let [maxSize, maxFrame] = [-1, null];
    targetFrames.forEach(function(frame) {
      if (frame.scrollMaxX <= 0 && frame.scrollMaxY <= 0)
        return;
      let size = frame.innerWidth * frame.innerHeight;
      if (maxSize < size)
        [maxSize, maxFrame] = [size, frame];
    });
    if (maxFrame)
      maxFrame.focus();
  }

  tabs.getBrowser().addEventListener("DOMContentLoaded", onLoad, true);


})();

// vim:sw=2 ts=2 et si fdm=marker:
eo/search page information and comment.</description> <description lang="ja">今見ている動画 / 検索結果の情報を Twitter に投稿する</description> <author mail="janus_wel@fb3.so-net.ne.jp" homepage="http://d.hatena.ne.jp/janus_wel">janus_wel</author> <license document="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license> <version>0.74</version> <minVersion>2.3pre</minVersion> <maxVersion>2.3pre</maxVersion> <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/matanico.js</updateURL> <detail><![CDATA[ == EX-COMMANDS == :matanico [comment]: This command posts the information of current video/search result to Twitter. "comment" is optional. :matanico! [comment]: This command copies string that be posted to Twitter, to clipboard. This is emulate command. == SETTINGS == matanico_watch_format: This is the format that be used on video page. Following special tokens are available. default setting is "$SERVICENAME : $SUBJECT($PLAYTIME) - $URL $COMMENT". $SERVICENAME: the value of "matanico_watch_servicename". $SUBJECT: video name. $PLAYTIME: video duration. $URL: video URL. $COMMENT: comment. if this token is not specified, ex-command ":matanico" ignore any comments. matanico_watch_servicename: the token "$SERVICENAME" specified by "matanico_watch_format" will be expanded to this value. this variable facilitate to change posted string without modefication of format. default value is "またニコニコ動画見てる". matanico_live_format: This is the format that be used on live page. Following special tokens are available. default setting is "$SERVICENAME : $SUBJECT - $URL $COMMENT". $SERVICENAME: matanico_live_servicename で指定した文字列に展開されます $SUBJECT: live name. $URL: live URL. $COMMENT: comment. if this token is not specified, ex-command ":matanico" ignore any comments. matanico_live_servicename: the token "$SERVICENAME" specified by "matanico_live_format" will be expanded to this value. this variable facilitate to change posted string without modefication of format. default value is "またニコニコ生放送見てる". matanico_tag_format: This is the format that be used on tag search page. Following special tokens are available. default setting is "$SERVICENAME : $TAG($NUMOFVIDEOS件) - $URL $COMMENT". $SERVICENAME: the value of "matanico_tag_servicename". $TAG: search tags. that will be separated by a space, when specified multiple tags. $NUMOFVIDEOS: the number of search result. $URL: search result URL. $COMMENT: comment. if this token is not specified, ex-command ":matanico" ignore any comments. matanico_tag_servicename: the token "$SERVICENAME" specified by "matanico_tag_format" will be expanded to this value. this variable facilitate to change posted string without modefication of format. default value is "またニコニコタグ検索してる". matanico_related_tag_format: This is the format that be used on tag search by keyword page. Following special tokens are available. default setting is "$SERVICENAME : $KEYWORD($NUMOFTAGS件) - $URL $COMMENT". $SERVICENAME: the value of "matanico_related_tag_servicename". $KEYWORD: search keyword. $NUMOFVIDEOS: the number of search result. $URL: search result URL. $COMMENT: comment. if this token is not specified, ex-command ":matanico" ignore any comments. matanico_related_tag_servicename: the token "$SERVICENAME" specified by "matanico_related_tag_format" will be expanded to this value. this variable facilitate to change posted string without modefication of format. default value is "またキーワードでニコニコタグ検索してる". ]]></detail> <detail lang="ja"><![CDATA[ == EX-COMMANDS == :matanico [comment]: 今見ている動画 / 検索した結果の情報を Twitter に投稿します comment はなくてもかまいません :matanico! [comment]: Twitter に投稿される文字列をクリップボードにコピーします Twitter には投稿しません == SETTINGS == matanico_watch_format: 動画ページにおいて投稿される文章の書式設定です以下の特殊な文字列を指定可能です設定なしの場合 "$SERVICENAME : $SUBJECT($PLAYTIME) - $URL $COMMENT" になります $SERVICENAME: matanico_watch_servicename で指定した文字列に展開されます $SUBJECT: 動画の名前に展開されます $PLAYTIME: 再生時間に展開されます $URL: 動画の URL に展開されます $COMMENT: コメントに展開されますこの指定がないと :matanico コマンドでコメントを書いても反映されません matanico_watch_servicename: matanico_watch_format で指定した $SERVICENAME 部分がこの値で展開されます書式はそのままで投稿する文字列のみを変更したい場合にこの値を変更することで設定が容易になります設定なしの場合 "またニコニコ動画見てる" が使用されます matanico_live_format: 生放送ページにおいて投稿される文章の書式設定です以下の特殊な文字列を指定可能です設定なしの場合 "$SERVICENAME : $SUBJECT - $URL $COMMENT" になります $SERVICENAME: matanico_live_servicename で指定した文字列に展開されます $SUBJECT: 動画の名前に展開されます $URL: 動画の URL に展開されます $COMMENT: コメントに展開されますこの指定がないと :matanico コマンドでコメントを書いても反映されません matanico_live_servicename: matanico_live_format で指定した $SERVICENAME 部分がこの値で展開されます書式はそのままで投稿する文字列のみを変更したい場合にこの値を変更することで設定が容易になります設定なしの場合 "またニコニコ生放送見てる" が使用されます matanico_tag_format: タグ検索ページにおいて投稿される文章の書式設定です以下の特殊な文字列を指定可能です設定なしの場合 "$SERVICENAME : $TAG($NUMOFVIDEOS件) - $URL $COMMENT" が使用されます $SERVICENAME: matanico_tag_servicename で指定した文字列に展開されます $TAG: 検索したタグ名に展開されます複数指定の場合半角スペースで区切られます $NUMOFVIDEOS: 検索結果の件数に展開されます $URL: 検索結果の URL に展開されます $COMMENT: コメント展開されますこの指定がないと :matnico コマンドでコメントを書いても反映されません matanico_tag_servicename: matanico_tag_format で指定した $SERVICENAME 部分がこの値で展開されます書式はそのままで投稿する文字列のみを変更したい場合にこの値を変更することで設定が容易になります設定なしの場合 "またニコニコタグ検索してる" が使用されます matanico_related_tag_format: キーワードによるタグ検索ページにおいて投稿される文章の書式設定です以下の特殊な文字列を指定可能です設定なしの場合 "$SERVICENAME : $KEYWORD($NUMOFTAGS件) - $URL $COMMENT" が使用されます $SERVICENAME: matanico_related_tag_servicename で指定した文字列に展開されます。。 $KEYWORD: 検索したキーワードに展開されます $NUMOFVIDEOS: 検索結果の件数に展開されます $URL: 検索結果の URL に展開されます $COMMENT: コメント展開されますこの指定がないと :matnico コマンドでコメントを書いても反映されません matanico_related_tag_servicename: matanico_related_tag_format で指定した $SERVICENAME 部分がこの値で展開されます書式はそのままで投稿する文字列のみを変更したい場合にこの値を変更することで設定が容易になります設定なしの場合 "またキーワードでニコニコタグ検索してる" が使用されます ]]></detail> </VimperatorPlugin>; (function () { // class definitions // change XPath query when html changed. function NicoScraper() {} NicoScraper.prototype = { _constants: { VERSION: '0.73', PAGECHECK: [ ['live', '^http://live\\.nicovideo\\.jp/watch/'], ['watch', '^http://[^.]+\\.nicovideo\\.jp/watch/'], ['tag', '^http://[^.]+\\.nicovideo\\.jp/tag/'], ['relatedTag', '^http://[^.]+\\.nicovideo\\.jp/related_tag/'], ], }, version: function () { return this.constants.VERSION; }, pagecheck: function () { const pageCheckData = this._constants.PAGECHECK; const currentURL = this.getURL(); for each (let [name, url] in pageCheckData) { if (currentURL.match(url)) return name; } throw new Error('current tab is not nicovideo.jp'); }, _flvplayer: function () { if (this.pagecheck() === 'watch') { let flvplayer = window.content.document.getElementById('flvplayer'); if (!flvplayer) throw new Error('video player is not found'); return flvplayer.wrappedJSObject || flvplayer; } throw new Error('current tab is not watch page on nicovideo.jp'); }, getURL: function () { return liberator.modules.buffer.URL; }, getSubject: function () { let subjectNode; switch (this.pagecheck()) { case 'watch': subjectNode = $f('id("des_2")/table/tbody/tr/td/h1'); break; case 'live': subjectNode = $f('id("stream_description")'); break; default: break; } if (subjectNode) return subjectNode.textContent; throw new Error('current tab is not watch page on nicovideo.jp'); }, getPlaytime: function () { let p = this._flvplayer(); if (p && p.ext_getTotalTime) { let playtime = Math.round(p.ext_getTotalTime()); let min = Math.floor(playtime / 60); let sec = playtime % 60; if (sec < 10) sec = '0' + sec; return [min, sec].join(':'); } throw new Error('current tab is not watch page on nicovideo.jp'); }, getTagName: function () { if (this.pagecheck() === 'tag') { let wordNodes = liberator.modules.util.evaluateXPath('id("search_words")/span[contains(concat(" ", @class, " "), " search_word ")]'); let words = []; for (let wordNode in wordNodes) words.push(wordNode.textContent); return words.join(' '); } throw new Error('current tab is not tag search page on nicovideo.jp'); }, getNumofVideos: function () { if (this.pagecheck() === 'tag') { let numofVideos = $f('//strong[contains(concat(" ", @class, " "), " result_total ")]'); return numofVideos.textContent; } throw new Error('current tab is not tag search page on nicovideo.jp'); }, getKeyword: function () { if (this.pagecheck() === 'relatedTag') { let keyword = $f('//strong[contains(concat(" ", @class, " "), " search_word ")]'); return keyword.textContent; } throw new Error('current tab is not related tag search page on nicovideo.jp'); }, getNumofTags: function () { if (this.pagecheck() === 'relatedTag') { let numofTags = $f('//strong[contains(concat(" ", @class, " "), " result_total ")]'); return numofTags.textContent; } throw new Error('current tab is not related tag search page on nicovideo.jp'); }, }; function TwitterUpdaterFactory() { let pUsername, pPassword; let pEndPoint = 'https://twitter.com/statuses/update.json'; function TwitterUpdater() {} TwitterUpdater.prototype.update = function (data) { let parameter = 'status=' + encodeURIComponent(data.newStatus); let req = new XMLHttpRequest(); if (req) { req.open('POST', pEndPoint, true, pUsername, pPassword); req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { data.onSuccess(); return; } throw new Error('failure to update status in Twitter. HTTP status code : ' + req.status); } req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.send(parameter); } }; TwitterUpdater.prototype.__defineSetter__( 'username', function (username) { pUsername = username; return this; } ); TwitterUpdater.prototype.__defineSetter__( 'password', function (password) { pPassword = password; return this; } ); return new TwitterUpdater(); } // main --- let scraper = new NicoScraper(); liberator.modules.commands.addUserCommand( ['matanico'], 'update Twitter status to current video/search page information and comment', function (args) { let arg = args.string; try { // build post string ----- let postString; // domain check switch(scraper.pagecheck()) { case 'watch': postString = onWatch(scraper, arg); break; case 'live': postString = onLive(scraper, arg); break; case 'tag': postString = onTagSearch(scraper, arg); break; case 'relatedTag': postString = onRelatedTagSearch(scraper, arg); break; default: throw new Error('current tab is not nicovideo.jp'); break; } // ':matanico!' display the evaluated format. if (args.bang) { liberator.modules.util.copyToClipboard(postString, true); return; } // get username/password and set TwitterUpdater let t = TwitterUpdaterFactory(); [t.username, t.password] = getUserAccount({ hostname: 'http://twitter.com/', formSubmitURL: 'https://twitter.com/statuses/update.json', httpRealm: null, description: 'Enter e-mail address and password. This information is cached and use from next time.', }); t.update({ newStatus: postString, onSuccess: function () liberator.echo('Posted ' + postString), }); } catch (e) { liberator.echoerr(e); liberator.log(e); } }, { bang: true, }, true ); // sub function onWatch(scraper, comment) { let format = liberator.globalVariables.matanico_watch_format || '$SERVICENAME : $SUBJECT($PLAYTIME) - $URL $COMMENT'; let serviceName = liberator.globalVariables.matanico_watch_servicename || fromUTF8Octets('またニコニコ動画見てる'); return format.replace(/\$SERVICENAME/g, serviceName) .replace(/\$SUBJECT/g, scraper.getSubject()) .replace(/\$PLAYTIME/g, scraper.getPlaytime()) .replace(/\$URL/g, scraper.getURL()) .replace(/\$COMMENT/g, comment); } function onLive(scraper, comment) { let format = liberator.globalVariables.matanico_live_format || '$SERVICENAME : $SUBJECT - $URL $COMMENT'; let serviceName = liberator.globalVariables.matanico_live_servicename || fromUTF8Octets('またニコニコ生放送見てる'); return format.replace(/\$SERVICENAME/g, serviceName) .replace(/\$SUBJECT/g, scraper.getSubject()) .replace(/\$URL/g, scraper.getURL()) .replace(/\$COMMENT/g, comment); } function onTagSearch(scraper, comment) { let format = liberator.globalVariables.matanico_tag_format || fromUTF8Octets('$SERVICENAME : $TAG($NUMOFVIDEOS件) - $URL $COMMENT'); let serviceName = liberator.globalVariables.matanico_tag_servicename || fromUTF8Octets('またニコニコタグ検索してる'); return format.replace(/\$SERVICENAME/g, serviceName) .replace(/\$TAG/g, scraper.getTagName()) .replace(/\$NUMOFVIDEOS/g, scraper.getNumofVideos()) .replace(/\$URL/g, scraper.getURL()) .replace(/\$COMMENT/g, comment); } function onRelatedTagSearch(scraper, comment) { let format = liberator.globalVariables.matanico_related_tag_format || fromUTF8Octets('$SERVICENAME : $KEYWORD($NUMOFTAGS件) - $URL $COMMENT'); let serviceName = liberator.globalVariables.matanico_related_tag_servicename || fromUTF8Octets('またキーワードでニコニコタグ検索してる'); return format.replace(/\$SERVICENAME/g, serviceName) .replace(/\$KEYWORD/g, scraper.getKeyword()) .replace(/\$NUMOFTAGS/g, scraper.getNumofTags()) .replace(/\$URL/g, scraper.getURL()) .replace(/\$COMMENT/g, comment); } // stuff functions function $f(query, node) { node = node || window.content.document; let result = (node.ownerDocument || node).evaluate( query, node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); return result.singleNodeValue || null; } function fromUTF8Octets(octets) decodeURIComponent(octets.replace(/[%\x80-\xFF]/g, function (c) '%' + c.charCodeAt(0).toString(16))); function getUserAccount(accountInfo) { // refer: // https://developer.mozilla.org/ja/Using_nsILoginManager let loginManager = Cc['@mozilla.org/login-manager;1'].getService(Ci.nsILoginManager); let logins = loginManager.findLogins( {}, accountInfo.hostname, accountInfo.formSubmitURL, accountInfo.httpRealm ); if (logins.length > 0) { // found return [logins[0].username, logins[0].password]; } else { // not found, so register // refer: https://developer.mozilla.org/Ja/Code_snippets/Dialogs_and_Prompts let promptSvc = Cc['@mozilla.org/embedcomp/prompt-service;1'].getService(Ci.nsIPromptService); let promptUsername = {value: ''}; let promptPassword = {value: ''}; let isOK = promptSvc.promptUsernameAndPassword( window, accountInfo.hostname, accountInfo.description, promptUsername, promptPassword, null, {} ); if (isOK) { let nsLoginInfo = new Components.Constructor( '@mozilla.org/login-manager/loginInfo;1', Ci.nsILoginInfo, 'init' ); // refer: https://developer.mozilla.org/ja/NsILoginInfo loginManager.addLogin(new nsLoginInfo( accountInfo.hostname, accountInfo.formSubmitURL, accountInfo.httpRealm, promptUsername.value, promptPassword.value, '', '' )); return [promptUsername.value, promptPassword.value]; } } throw new Error('account is not found: ' + accountInfo.hostname); } })(); // vim:sw=4 ts=4 et: