Show
Ignore:
Timestamp:
12/02/08 23:28:44 (5 weeks ago)
Author:
janus_wel
Message:

refactoring.
follow CVS HEAD.
use E4X

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lang/javascript/vimperator-plugins/trunk/nnp_cooperation.js

    r25172 r25713  
    11/* 
    22 * ==VimperatorPlugin== 
    3  * @name            niconicoplaylist_cooperation.js 
     3 * @name            nnp_cooperation.js 
    44 * @description     this script give you keyboard opration for NicoNicoPlaylist. 
    55 * @description-ja  NicoNicoPlaylist をキーボードで操作できるようにする。 
    66 * @author          janus_wel <janus_wel@fb3.so-net.ne.jp> 
    7  * @version         0.32 
    8  * @minversion      2.0pre 2008/10/16 
     7 * @version         0.33 
     8 * @minversion      2.0pre 
     9 * @maxversion      2.0pre 
    910 * ==/VimperatorPlugin== 
    1011 * 
     
    3940 * VARIABLES 
    4041 *   g:nnp_coop_numoflist 
    41  *     :NNPGetList で表示するリストの個数を指定する。デフォルトは 10 。 
     42 *     :nnpgetlist で表示するリストの個数を指定する。デフォルトは 10 。 
    4243 * 
    4344 * HISTORY 
     
    9596(function(){ 
    9697 
    97 // thumbnail URL 
    98 const thumbnailURL = 'http://tn-skr$HOSTNUMBER.smilevideo.jp/smile?i=$VIDEO_ID'; 
    99  
    100 // style 
    101 const styles = [ 
    102     '<style type="text/css">', 
    103         'table.nnp_coop .index     { text-align:right; width:2em; }', 
    104         'table.nnp_coop .thumbnail { text-align:center; }', 
    105         'table.nnp_coop caption    { color:green; }', 
    106         'table.nnp_coop thead      { text-align:center; }', 
    107     '</style>', 
    108 ].join(''); 
    109  
    110 // table 
    111 const tableTemplate = [ 
    112     '<table class="nnp_coop">', 
    113         '$CAPTION', 
    114         '$THEAD', 
    115         '<tbody>$ITEMS</tbody>', 
    116     '</table>', 
    117 ].join(''); 
    118  
    119 // table caption 
    120 const captionTemplate = '<caption>now playing: $PLAYTITLE (display $NUMOFDISPLAY / $NUMOFTOTAL$STATUSES)</caption>'; 
    121  
    122 // table head 
    123 const thead = [ 
    124     '<thead>', 
    125         '<tr>', 
    126             '<td> </td>', 
    127             '<td>thumbnail</td>', 
    128             '<td>title</td>', 
    129             '<td>url</td>', 
    130         '</tr>', 
    131     '</thead>', 
    132 ].join(''); 
    133  
    134 // item 
    135 const itemHTML = [ 
    136     '<tr>', 
    137         '<td class="index">$INDEX:</td>', 
    138         '<td class="thumbnail"><img src="$THUMBNAILURL" width="33" height="25" /></td>', 
    139         '<td>$TITLE</td>', 
    140         '<td>$URL</td>', 
    141     '</tr>', 
    142 ].join(''); 
    143  
    144  
    14598// scrape from div element that inserted by NicoNicoPlaylist 
    146 liberator.modules.commands.addUserCommand(['nnpgetlist'], 'get NicoNicoPlaylist', 
     99liberator.modules.commands.addUserCommand( 
     100    ['nnpgetlist'], 
     101    'get NicoNicoPlaylist', 
    147102    function (args) { 
    148         var arg = (args.length > 1) 
    149             ? args[0].toString() 
    150             : args.string; 
    151  
    152103        // check existence of NicoNicoPlaylist 
    153         var playlist = $f('//div[contains(@id, "playlistcontroller_")]'); 
    154         if(!playlist) { 
     104        let playlistNode = $f('//div[starts-with(@id, "playlistcontroller_")]'); 
     105        if(!playlistNode) { 
    155106            liberator.echoerr('NicoNicoPlaylist is not found.'); 
    156107            return; 
    157108        } 
    158109 
    159         var titleNode = $f('//h1') || $f('./html/head/title'); 
    160         var playTitle = titleNode.textContent; 
    161         var statuses = ''; 
    162         if($f('.//input[contains(@id, "-checkbox-random")]', playlist).checked) statuses += 'R'; 
    163         if($f('.//input[contains(@id, "-checkbox-loop")]', playlist).checked)   statuses += 'L'; 
    164         if($f('.//input[contains(@id, "-checkbox-full")]', playlist).checked)   statuses += 'F'; 
    165         if(statuses) statuses = ' ' + statuses; 
    166  
    167110        // check existence of items in NicoNicoPlaylist 
    168         var nodes = $s('./div[contains(concat(" ", @class, " "), " playlist-list-outer ")]/ul/li/a', playlist); 
    169         var nodesLength = nodes.length 
    170         if(nodesLength === 0) { 
     111        let nodes = buffer.evaluateXPath( 
     112            'id("' + playlistNode.id + '")/div[contains(concat(" ", @class, " "), " playlist-list-outer ")]/ul/li/a' 
     113        ); 
     114        let nodesLength = nodes.snapshotLength; 
     115        if(!nodesLength) { 
    171116            liberator.echoerr('no items in NicoNicoPlaylist.'); 
    172117            return; 
     
    174119 
    175120        // get number of displayed items 
    176         var numofList = arg.match(/^\d+$/) 
    177             ? arg 
    178             : (liberator.globalVariables.nnp_coop_numoflist || 10); 
    179  
    180         // struct display string 
     121        let numofList = liberator.globalVariables.nnp_coop_numoflist || 10; 
     122        let arg = args[0]; 
     123        if (arg && /^\d+$/.test(arg)) numofList = arg; 
     124 
    181125        // generate data 
    182         var items = new Array; 
    183         for(let i=0 ; i<nodesLength && i<numofList ; ++i ) { 
     126        let items = [], length = 0; 
     127        for(let node in nodes) { 
     128            if (length >= numofList) break; 
     129 
    184130            // get video id 
    185             let id = nodes[i].href.match(/\d+$/); 
    186             // build thumnail's URL 
    187             // refer: http://d.hatena.ne.jp/ZIGOROu/20081014/1223991205 
    188             let thumbnail = thumbnailURL.replace(/\$HOSTNUMBER/g, id % 2 + 1) 
    189                                         .replace(/\$VIDEO_ID/g,    id); 
     131            let id = node.href.match(/\d+$/); 
     132 
    190133            // evaluate variables and push to list 
    191             items.push( 
    192                 itemHTML.replace(/\$INDEX/g,        i + 1) 
    193                         .replace(/\$THUMBNAILURL/g, thumbnail) 
    194                         .replace(/\$TITLE/g,        nodes[i].textContent) 
    195                         .replace(/\$URL/g,          nodes[i].href) 
    196             ); 
     134            items.push({ 
     135                index:        ++length, 
     136                thumbnailURL: thumbnailURL(id), 
     137                title:        node.textContent, 
     138                url:          node.href, 
     139            }); 
    197140        } 
    198141 
    199142        // evaluate variables 
    200         var caption = captionTemplate 
    201             .replace(/\$NUMOFDISPLAY/g, (nodesLength < numofList) ? nodesLength : numofList) 
    202             .replace(/\$NUMOFTOTAL/g,   nodesLength) 
    203             .replace(/\$PLAYTITLE/g,    playTitle) 
    204             .replace(/\$STATUSES/g,     statuses); 
    205  
    206         // final processing 
    207         var str = styles + tableTemplate.replace(/\$CAPTION/g, caption) 
    208                                         .replace(/\$THEAD/g,   thead) 
    209                                         .replace(/\$ITEMS/g,   items.join('')); 
    210  
    211         liberator.echo(str, liberator.modules.commandline.FORCE_MULTILINE); 
    212     },{} 
     143        let xml = <> 
     144            {style()} 
     145            {table({ 
     146                numofDisplay: (nodesLength < numofList) ? nodesLength : numofList, 
     147                numofTotal:   nodesLength, 
     148                playTitle:    getPlayTitle(), 
     149                statuses:     getStatusText(playlistNode.id), 
     150                items:        items, 
     151            })} 
     152        </> 
     153 
     154        liberator.echo(xml, liberator.modules.commandline.FORCE_MULTILINE); 
     155    }, 
     156    {} 
    213157); 
    214158 
    215 // stuff functions 
     159// define other commands 
     160// only send CommandEvent to NicoNicoPlaylist script 
     161[ 
     162    [['nnppushallvideos'], 'push all videos to NicoNicoPlaylist',        'GMNNPPushAllVideos'], 
     163    [['nnppushthisvideo'], 'push current video to NicoNicoPlaylist',     'GMNNPPushThisVideo'], 
     164    [['nnpplaynext'],      'play next in NicoNicoPlaylist',              'GMNNPPlayNext'], 
     165    [['nnpremove'],        'remove item in NicoNicoPlaylist',            'GMNNPRemove'], 
     166    [['nnpclear'],         'clear all items in NicoNicoPlaylist',        'GMNNPClear'], 
     167    [['nnprandom'],        'toggle random mode of NicoNicoPlaylist',     'GMNNPRandom'], 
     168    [['nnploop'],          'toggle loop mode of NicoNicoPlaylist',       'GMNNPLoop'], 
     169    [['nnpfullscreen'],    'toggle fullscreen mode of NicoNicoPlaylist', 'GMNNPFullScreen'], 
     170].forEach( function ([command, description, eventname]){ 
     171    liberator.modules.commands.addUserCommand( 
     172        command, 
     173        description, 
     174        function (arg) { 
     175            let r = document.createEvent('CommandEvent'); 
     176            r.initCommandEvent(eventname, true, true, arg[0]); 
     177            window.content.dispatchEvent(r); 
     178        }, 
     179        {} 
     180    ); 
     181}); 
     182 
     183 
     184// stuff functions --- 
    216185// return first node 
    217186function $f(query, node) { 
    218187    node = node || window.content.document; 
    219     var result = (node.ownerDocument || node).evaluate( 
     188    let result = (node.ownerDocument || node).evaluate( 
    220189        query, 
    221190        node, 
     
    227196} 
    228197 
    229 // return snapshot nodes list 
    230 function $s(query, node) { 
    231     node = node || window.content.document; 
    232     var result = (node.ownerDocument || node).evaluate( 
    233         query, 
    234         node, 
    235         null, 
    236         XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, 
    237         null 
    238     ); 
    239     var nodes = []; 
    240     for(let i=0 ; i<result.snapshotLength ; ++i) nodes.push(result.snapshotItem(i)); 
    241     return nodes; 
    242 } 
    243  
    244 // define other commands 
    245 // only send CommandEvent to NicoNicoPlaylist script 
    246 [ 
    247     [['nnppushallvideos'], "push all videos to NicoNicoPlaylist",        'GMNNPPushAllVideos'], 
    248     [['nnppushthisvideo'], "push current video to NicoNicoPlaylist",     'GMNNPPushThisVideo'], 
    249     [['nnpplaynext'],      "play next in NicoNicoPlaylist",              'GMNNPPlayNext'], 
    250     [['nnpremove'],        "remove item in NicoNicoPlaylist",            'GMNNPRemove'], 
    251     [['nnpclear'],         "clear all items in NicoNicoPlaylist",        'GMNNPClear'], 
    252     [['nnprandom'],        "toggle random mode of NicoNicoPlaylist",     'GMNNPRandom'], 
    253     [['nnploop'],          "toggle loop mode of NicoNicoPlaylist",       'GMNNPLoop'], 
    254     [['nnpfullscreen'],    "toggle fullscreen mode of NicoNicoPlaylist", 'GMNNPFullScreen'], 
    255 ].forEach( 
    256     function ([command, description, eventname]){ 
    257         liberator.modules.commands.addUserCommand(command, description, 
    258             function (arg) { 
    259                 var r = document.createEvent("CommandEvent"); 
    260                 r.initCommandEvent(eventname, true, true, arg.string); 
    261                 window.content.dispatchEvent(r); 
    262             },{} 
    263         ); 
    264     } 
    265 ); 
     198function getPlayTitle() { 
     199    let titleNode = $f('//h1') || $f('//title'); 
     200    return titleNode.textContent; 
     201} 
     202 
     203function getStatusText(idPrefix) { 
     204    let statuses = []; 
     205    [ 
     206        ['//input[starts-with(@id, "playlist") and contains(@id, "-checkbox-random")]', 'R'], 
     207        ['//input[starts-with(@id, "playlist") and contains(@id, "-checkbox-loop")]',   'L'], 
     208        ['//input[starts-with(@id, "playlist") and contains(@id, "-checkbox-full")]',   'F'], 
     209    ].forEach(function ([query, text]) { 
     210        if ($f(query).checked) statuses.push(text); 
     211    }); 
     212    return (statuses.length) ? ' ' + statuses.join('') : ''; 
     213} 
     214 
     215// thumbnail URL 
     216// refer: http://d.hatena.ne.jp/ZIGOROu/20081014/1223991205 
     217function thumbnailURL(videoId) { 
     218    return [ 
     219        'http://tn-skr', 
     220        (videoId % 2 + 1), 
     221        '.smilevideo.jp/smile?i=', 
     222        videoId 
     223    ].join(''); 
     224} 
     225 
     226// E4X hell --- 
     227// style 
     228function style(css) { 
     229    return <style type="text/css">{[ 
     230        'table.nnp_coop .index     { text-align:right; width:2em; }', 
     231        'table.nnp_coop .thumbnail { text-align:center; }', 
     232        'table.nnp_coop caption    { color:green; }', 
     233        'table.nnp_coop thead      { text-align:center; }', 
     234    ].join('')}</style> 
     235} 
     236 
     237// table 
     238function table(data) { 
     239    return <table class="nnp_coop"> 
     240        {caption(data)} 
     241        {thead()} 
     242        <tbody>{liberator.modules.template.map(data.items, item)}</tbody> 
     243    </table> 
     244} 
     245 
     246// table caption 
     247function caption(data) { 
     248    return <caption>now playing: {data.playTitle} (display {data.numofDisplay} / {data.numofTotal}{data.statuses})</caption> 
     249} 
     250 
     251// table head 
     252function thead() { 
     253    return <thead> 
     254        <tr> 
     255            <td> </td> 
     256            <td>thumbnail</td> 
     257            <td>title</td> 
     258            <td>url</td> 
     259        </tr> 
     260    </thead> 
     261} 
     262 
     263// item 
     264function item(datum) { 
     265    return <tr> 
     266        <td class="index">{datum.index}:</td> 
     267        <td class="thumbnail"><img src={datum.thumbnailURL} width="33" height="25" /></td> 
     268        <td>{datum.title}</td> 
     269        <td>{datum.url}</td> 
     270    </tr> 
     271} 
    266272 
    267273})();