| 14 | | SVN_REPOS_BASE : 'http://svn.coderepos.org/share', |
| 15 | | TRAC_BASE : 'http://coderepos.org/share', |
| 16 | | AUTHOR_ICONS : { |
| 17 | | //'tomoyo' : 'http://www.hatena.ne.jp/users/ma/mayuki/profile_s.gif' |
| 18 | | //'tomoyo' : 'id:mayuki' |
| 19 | | '*default*' : 'http://coderepos.org/share/htdocs/default-author-icon.png' |
| 20 | | , 'mayuki' : 'id:mayuki' |
| 21 | | , 'yappo' : 'id:yappo' |
| 22 | | , 'typester' : 'http://www.gravatar.com/avatar.php?gravatar_id=fbc6511bcc0649366086c0445fb456d3&size=16'//'id:typester' |
| 23 | | , 'kentaro' : 'id:antipop' |
| 24 | | , 'mizzy' : 'id:gosukenator' |
| 25 | | , 'charsbar' : 'id:charsbar' |
| 26 | | , 'secondlife' : 'id:secondlife' |
| 27 | | , 'kazeburo' : 'id:kazeburo' |
| 28 | | , 'otsune' : 'id:otsune' |
| 29 | | , 'hirose31' : 'id:hirose31' |
| 30 | | , 'nipotan' : 'id:nipotan' |
| 31 | | , 'itkz' : 'id:itkz' |
| 32 | | , 'xcezx' : 'id:xcezx' |
| 33 | | , 'nyarla' : 'id:nyarla-net' |
| 34 | | , 'tokuhirom' : 'id:tokuhirom' |
| 35 | | , 'daisuke' : 'id:lestrrat' |
| 36 | | , 'kana' : 'id:ka-nacht' |
| 37 | | , 'cho45' : 'id:cho45' |
| 38 | | , 'kan' : 'id:kan' |
| 39 | | , 'zigorou' : 'id:ZIGOROu' |
| 40 | | , 'masaki' : 'id:ikasam_a' |
| 41 | | , 'holidays-l' : 'id:holidays-l' |
| 42 | | , 'yoko' : 'id:yksk' |
| 43 | | , 'mattn' : 'id:mattn' |
| 44 | | , 'lopnor' : 'id:lopnor' |
| 45 | | , 'gyuque' : 'id:gyuque' |
| 46 | | , 'yugui' : 'id:yugui' |
| 47 | | , 'akihito' : 'id:t-akihito' |
| 48 | | , 'fujiwara' : 'id:sfujiwara' |
| 49 | | , 'yusukebe' : 'id:kamawada' |
| 50 | | , 'miyagawa' : 'id:miyagawa' |
| 51 | | , 'topia' : 'id:topia' |
| 52 | | , 'woremacx' : 'id:woremacx' |
| 53 | | , 'amachang' : 'id:amachang' |
| 54 | | , 'takesako' : 'id:TAKESAKO' |
| 55 | | , 'eto' : 'id:eto' |
| 56 | | , 'dankogai' : 'id:dankogai' |
| 57 | | , 'jknaoya' : 'id:jknaoya' |
| 58 | | , 'yasu' : 'id:hirata_yasuyuki' |
| 59 | | , 'holygrail' : 'id:HolyGrail' |
| 60 | | , 'elim' : 'id:elim' |
| 61 | | , 'cheebow' : 'id:cheebow' |
| 62 | | , 'ariela' : 'http://www.gravatar.com/avatar.php?gravatar_id=dd5dfb5d738d5b5fb1c9a8b234945ea6&size=16'//'id:transrain' |
| 63 | | , 'tomyhero' : 'id:tomyhero' |
| 64 | | , 'hetappi' : 'id:hetappi' |
| 65 | | , 'coji' : 'id:coji' |
| 66 | | , 'takemaru' : 'id:teahut' |
| 67 | | , 'akasata' : 'id:akasata' |
| 68 | | , 'okuryu' : 'id:okuryu' |
| 69 | | , 'tasuku' : 'id:tasukuchan' |
| 70 | | , 'snj14' : 'id:snj14' |
| 71 | | , 'shachi' : 'id:shachi_kk' |
| 72 | | , 'omoon' : 'id:omoon' |
| 73 | | , 'aerith' : 'id:aerith' |
| 74 | | , 'clouder' : 'id:clouder' |
| 75 | | , 'takkyun' : 'id:simpleboxes' |
| 76 | | , 'naoya_t' : 'http://ntzone.info/misc/keroro.gif' |
| 77 | | , 'takefumi' : 'id:takefumi' |
| 78 | | , 'walf443' : 'id:walf443' |
| 79 | | , 'psychs' : 'id:Psychs' |
| 80 | | , 'ewigkeit' : 'id:Ewigkeit' |
| 81 | | , 'yoshiori' : 'id:Yoshiori' |
| 82 | | , 'dev0000' : 'http://www.developer0000.jp/16.jpg' |
| 83 | | , 'machu' : 'id:kmachu' |
| 84 | | , 'norio_s' : 'id:norio_s' |
| 85 | | , 'hsbt' : 'id:h-sbt' |
| 86 | | , 'nori090' : 'id:nori090' |
| 87 | | , 'lyokato' : 'id:lyokato' |
| 88 | | , 'drgqst' : 'id:drgqst' |
| 89 | | , 'mrkn' : 'id:mrkn' |
| 90 | | , 'tfunato' : 'id:tfunato' |
| 91 | | , 'tsuka' : 'id:tsuka05' |
| 92 | | , 'niw' : 'id:niw' |
| 93 | | , 'tomi-ru' : 'id:tomi-ru' |
| 94 | | , 'yto' : 'id:yto' |
| 95 | | , 'motemen' : 'id:motemen' |
| 96 | | , 'shyouhei' : 'http://mput.dip.jp/mput/images/icon.jpg' |
| 97 | | , 'm-takagi' : 'http://www.gravatar.com/avatar.php?gravatar_id=c3f5a6e729b57f99cb9e7b3ca60152aa&size=16' |
| 98 | | , 'takano32' : 'id:takano32' |
| 99 | | , 'kakutani' : 'id:kakutani' |
| 100 | | , 'poppen' : 'id:poppen' |
| 101 | | , 'kotas' : 'id:kotas' |
| 102 | | , 'nekokak' : 'id:nekokak' |
| 103 | | , 'tosik' : 'id:tosik' |
| 104 | | , 'fbis' : 'id:fbis' |
| 105 | | , 'rsk' : 'id:rsky' |
| 106 | | , 'mallowlabs' : 'id:mallowlabs' |
| 107 | | , 'nakamud' : 'http://s3.amazonaws.com/twitter_production/profile_images/35752262/SP_mu-toko_mini.jpg' |
| 108 | | , 'chiba' : 'id:nihen' |
| 109 | | , 'funaki' : 'id:nob_funaki' |
| 110 | | , 'dzfl' : 'id:dzfl' |
| 111 | | , 'shimooka' : 'id:shimooka' |
| 112 | | // , 'noriaki' : 'http://s3.amazonaws.com/twitter_production/profile_images/40454132/2f94929d_mini.jpg' |
| 113 | | , 'suztomo' : 'id:suztomo' |
| 114 | | , 'klm' : 'id:k1m' |
| 115 | | , 'akio0911' : 'id:akio0911' |
| 116 | | , 'cactusman' : 'id:cactusman' |
| 117 | | , 'vkgtaro' : 'id:vkgtaro' |
| 118 | | , 'todesking' : 'http://data.tumblr.com/avatar_1fe558be2f23_16.gif' |
| 119 | | , 'sho' : 'id:sho' |
| 120 | | , 'a2c' : 'id:a2c' |
| 121 | | , 'hidek' : 'http://www.gravatar.com/avatar.php?gravatar_id=7d55041891ece2f35375108aa2d27255&size=16'//'id:hide-K'' |
| 122 | | , 'yhara' : 'id:yhara' |
| 123 | | , 'PoohKid' : 'id:PoohKid' |
| 124 | | , 'samurai20000' : 'id:samurai20000' |
| 125 | | , 'yasuyuki' : 'id:YaSuYuKi' |
| 126 | | , 'mootoh' : 'id:moira' |
| 127 | | , 'tokada' : 'id:tokada' |
| 128 | | , 'llamerada' : 'id:llamerada' |
| 129 | | , 'shn' : 'id:shn' |
| 130 | | , 'nejimaki' : 'id:firewood' |
| 131 | | , 'kan' : 'id:mikihoshi' |
| 132 | | , 'hideden' : 'id:hideden' |
| 133 | | , 'niku' : 'http://niku.name/favicon.ico' |
| 134 | | , 'ohac' : 'id:ohac' |
| 135 | | , 'hio' : 'http://www.gravatar.com/avatar.php?gravatar_id=a72d2120c066d47ad3d29c17b2f4db72&size=16' |
| 136 | | , 'os0x' : 'id:os0x' |
| 137 | | , 'akiyan' : 'id:akiyan' |
| 138 | | , 'inudog' : 'http://eringi.com/favicon.ico' |
| 139 | | , 'suzuki' : 'id:zatsubun' |
| 140 | | , 'haruka' : 'http://drumsoft.com/favicon.ico' |
| 141 | | , 'syttru' : 'id:syttru' |
| 142 | | , 'iskwrsk' : 'id:iskwrsk' |
| 143 | | , 'komatsuna' : 'http://data.tumblr.com/avatar_82a9ef4053ec_30.gif' |
| 144 | | , 'tarchan' : 'id:tarchan' |
| 145 | | , 'tyoro' : 'id:tyoro1210' |
| 146 | | , 'Sore_0' : 'id:Sore_0' |
| 147 | | , 'teramako' : 'id:teramako' |
| 148 | | , 'kamipo' : 'id:kamipo' |
| 149 | | , 'ihag' : 'id:ihag' |
| 150 | | , 'valda' : 'http://data.tumblr.com/avatar_a5fb0192ec7d_16.gif' |
| 151 | | , 'gan2' : 'id:gan2' |
| 152 | | , 'sasezaki' : 'id:sasezaki' |
| 153 | | } |
| 154 | | |
| 155 | | , installAll : function () { |
| 156 | | TracUtils.addJumpToReposLink(); |
| 157 | | TracUtils.clickableCodeArea(); |
| 158 | | TracUtils.addBodyClass(); |
| 159 | | TracUtils.addCommitterRecentCommits(); |
| 160 | | TracUtils.addRecentChangesForProject(); |
| 161 | | TracUtils.addUserscriptsUtils(); |
| 162 | | TracUtils.AuthorIcons.showAuthorIcons(); |
| 163 | | } |
| 164 | | |
| 165 | | , isWikiStart : function () { |
| 166 | | var pn = location.pathname |
| 167 | | return ( |
| 168 | | pn == "/share/wiki/WikiStart" || |
| 169 | | pn == "/share/wiki/" || |
| 170 | | pn == "/share/wiki" || |
| 171 | | pn == "/share/" || |
| 172 | | pn == "/share" |
| 173 | | ); |
| 174 | | } |
| 175 | | |
| 176 | | , getSourcePath : function (tracPath) { |
| 177 | | return String(tracPath).replace(TracUtils.TRAC_BASE + "/browser", TracUtils.SVN_REPOS_BASE).replace(/\?.*/, ''); |
| 178 | | } |
| 179 | | |
| 180 | | /** |
| 181 | | * Browse Source のときに該当する svn web にすぐ翔べるリンクと |
| 182 | | * ?rev= をはずすリンクを追加 |
| 183 | | */ |
| 184 | | , addJumpToReposLink : function () { |
| 185 | | var aboutLink = $("#metanav li.last a"); |
| 186 | | if (location.pathname.indexOf("/share/browser") == 0) { |
| 187 | | var sourcePath = TracUtils.getSourcePath(location); |
| 188 | | aboutLink.replaceWith( |
| 189 | | $("<a title='Jump to Repository'>SVN Web</a>").attr("href", sourcePath) |
| 190 | | ); |
| 191 | | $("#ctxtnav li:first").after($("<li/>").append($("<a>SVN Web</a>").attr("href", sourcePath))); |
| 192 | | $("#ctxtnav li:first").after($("<li/>").append($("<a>Latest Revision</a>").attr("href", location.pathname))); |
| 193 | | } else { |
| 194 | | aboutLink.replaceWith( |
| 195 | | $("<a title='Jump to Repository'>SVN Web</a>").attr("href", TracUtils.SVN_REPOS_BASE) |
| 196 | | ); |
| 197 | | } |
| 198 | | } |
| 199 | | |
| 200 | | /** |
| 201 | | * Wiki に書かれた JS のコードを実行可能に |
| 202 | | * 冒頭に //Executable と書くと実行できるようになる。 |
| 203 | | */ |
| 204 | | , clickableCodeArea : function () { |
| 205 | | var start = "//Executable"; |
| 206 | | $("//*[@id='content']//div[@class='code']/pre[contains(.//span[@class='code-comment'],'"+start+"')]").each(function () { |
| 207 | | var e = $(this); |
| 208 | | var js = e.text(); |
| 209 | | var a = $("<a href='javascript:void(156)'>Click to execute.</a>").click(function () { |
| 210 | | eval(js); |
| 211 | | }).css({ |
| 212 | | fontSize : "80%", |
| 213 | | fontWeight : "bold", |
| 214 | | border : "1px solid #ccc", |
| 215 | | display : "block", |
| 216 | | width : "10em", |
| 217 | | padding : "0.2em", |
| 218 | | margin : "0 auto 0.2em 0", |
| 219 | | textAlign : "center" |
| 220 | | }).insertBefore(e.parent()); |
| 221 | | }); |
| 222 | | } |
| 223 | | |
| 224 | | /** |
| 225 | | * CSS 補佐用 (IE6 で CSS セレクタの対応が貧弱なため) |
| 226 | | */ |
| 227 | | , addBodyClass : function () { |
| 228 | | if (location.pathname.indexOf("/share/wiki/Committers") == 0) { |
| 229 | | document.body.className = "committer"; |
| 230 | | } |
| 231 | | if (TracUtils.isWikiStart()) { |
| 232 | | $("//*[@id='Committers']/following-sibling::ul[1]").addClass("committer-list"); |
| 233 | | $("//*[@id='Projects']/following-sibling::ul[1]").addClass("project-list"); |
| 234 | | } |
| 235 | | } |
| 236 | | |
| 237 | | /** |
| 238 | | * コミッタページにその人の最近のコミットリストを表示する。 |
| 239 | | * Trac の検索機能を使っているので、コミットログに名前をかきまくると |
| 240 | | * 検索結果の1ページ目 == 10個しかみていないので |
| 241 | | * その人の最近のコミットがなかったことになるいじめができる。 |
| 242 | | */ |
| 243 | | , addCommitterRecentCommits : function () { |
| 244 | | if (!location.search && !/^\/share\/wiki\/Committers\/([^\/]{3,})/.test(location.pathname)) return; |
| 245 | | var author = RegExp.$1; |
| 246 | | $.get(TracUtils.TRAC_BASE+"/search?q="+author+"&noquickjump=1&changeset=on", {}, function (data) { |
| 247 | | $("<div class='recent-commits'><h2>Recent Commits</h2></div>").append( |
| 248 | | $(data).xfind(".//dl") |
| 249 | | .xfind("dd[span[@class='author'] != 'By "+author+"']") |
| 250 | | .xfind("preceding-sibling::dt[1] | preceding-sibling::dd[1]").remove().end() |
| 251 | | .remove() |
| 252 | | .end() |
| 253 | | ).appendTo($("#searchable, #content").get(0)); |
| 254 | | }); |
| 255 | | } |
| 256 | | |
| 257 | | /** |
| 258 | | * プロジェクトページへ最近のコミットリストを表示する。 |
| 259 | | * {{{ |
| 260 | | * svn co http://svn.coderepos.org/share/... |
| 261 | | * }}} |
| 262 | | * のように co と checkout, export の書いてあるページが対象。 |
| 263 | | */ |
| 264 | | , addRecentChangesForProject : function () { |
| 265 | | // IE だとなぜかどうしようもなく遅いので処理しない |
| 266 | | if ($.browser.msie || !TracUtils.isWikiStart() && location.pathname.indexOf("/share/wiki/") != 0) return; |
| 267 | | var target_re = RegExp("svn\\s+(?:c(?:o|heckout)|export)\\s+"+TracUtils.SVN_REPOS_BASE+"(\\S+)"); |
| 268 | | $("#searchable pre").each(function () { |
| 269 | | var m = $(this).text().match(target_re); |
| 270 | | if (!m) return; |
| 271 | | var path = m[1].replace(/\/trunk\/?$/, ""); |
| 272 | | var url = TracUtils.TRAC_BASE + "/log" + path; |
| 273 | | $.get(url, {}, function (data) { |
| 274 | | // 高速化と、jQuery がだす getElementsByTagName がないという |
| 275 | | // エラーを回避するため正規表現 |
| 276 | | data = data.match(/<table id="chglist"[\S\s]+<\/table>/)[0]; |
| 277 | | $("<div><h2><a href='"+url+"'>Project Recent Changes</a></h2></div>") |
| 278 | | .append( |
| 279 | | $(data) |
| 280 | | .find("tr:gt(10)").remove().end() |
| 281 | | .find("th.diff, td.diff, th.change, td.change, th.rev, td.rev").remove().end() |
| 282 | | ) |
| 283 | | .appendTo("#searchable"); |
| 284 | | }); |
| 285 | | return false; |
| 286 | | }); |
| 287 | | } |
| 288 | | |
| 289 | | /** |
| 290 | | * Userscripts のユーティリティ |
| 291 | | */ |
| 292 | | , addUserscriptsUtils : function () { |
| 293 | | if (($.browser.mozilla || $.browser.safari)) { |
| 294 | | // 尻? |
| 295 | | var isUserJS = function(path) { |
| 296 | | return /\.user\.js$/.test(path); |
| 297 | | }; |
| 298 | | // user.js のページがインストール画面でてうざいのをなんとかする。 |
| 299 | | // あんまり広範囲にやりたくないので決め打ち |
| 300 | | if (location.pathname.substring(0, 42) == "/share/browser/lang/javascript/userscripts") { |
| 301 | | $("a").each(function () { |
| 302 | | if (isUserJS(this.href)) this.href += "?"; |
| 303 | | }); |
| 304 | | } |
| 305 | | |
| 306 | | // user.js のページにインストールURLを追加する. |
| 307 | | if (isUserJS(location.pathname)) { |
| 308 | | var uri = TracUtils.getSourcePath(location); |
| 309 | | $('<a/>').attr({ |
| 310 | | href : uri, |
| 311 | | title : uri.split('/').slice(-1) + ' をインストールする' |
| 312 | | }) |
| 313 | | .text('インストール - ' + uri) |
| 314 | | .insertAfter($('h1:first')); |
| 315 | | } |
| 316 | | } |
| 317 | | } |
| 318 | | |
| 319 | | /** |
| 320 | | * Trac のあらゆるところに設定されたアイコンを表示する。 |
| 321 | | * TracAuthorIcon.js を jQuery/XPath 依存にして簡略化したもの |
| 322 | | */ |
| 323 | | , AuthorIcons : { |
| 324 | | showAuthorIcons : function () { |
| 325 | | var authors = []; |
| 326 | | switch ($("#content").attr("class")) { |
| 327 | | case 'browser': |
| 328 | | $('//*[@id="info"]//th').each(function () { |
| 329 | | authors.push([this, $(this).text().match(/checked in by ([^,]+)/)[1]]); |
| 330 | | }); |
| 331 | | $('//*[@id="dirlist"]//span[@class="author"]').each(function () { |
| 332 | | authors.push([this, $(this).text().match(/^([^:]+):/)[1]]); |
| 333 | | }); |
| 334 | | break; |
| 335 | | case 'timeline': |
| 336 | | $('//*[@id="content"]//dt/a').each(function () { |
| 337 | | authors.push([this, this.lastChild.nodeValue.match(/by\s+(.+)$/)[1]]); |
| 338 | | }); |
| 339 | | break; |
| 340 | | case 'log': |
| 341 | | case 'changeset': |
| 342 | | authors = $('(//*[@id="overview"] | //*[@id="chglist"])//*[@class="author"]'); |
| 343 | | break; |
| 344 | | case 'wiki': |
| 345 | | if (/^\/share\/wiki\/Committers\/([^\/]+)/.test(location.pathname)) { |
| 346 | | var author = RegExp.$1; |
| 347 | | var iconurl = TracUtils.AuthorIcons.getIconByAuthor(author); |
| 348 | | if (!iconurl) break; |
| 349 | | var img = $("<img width='16' height='16' alt='' class='committer-icon'/>").attr("src", iconurl); |
| 350 | | var h1 = $("//*[@id='searchable']/h1[1]"); |
| 351 | | if (h1.length) { |
| 352 | | h1.append(img); |
| 353 | | } else { |
| 354 | | $("#content").prepend(img); |
| 355 | | } |
| 356 | | } else |
| 357 | | if (TracUtils.isWikiStart()) { |
| 358 | | // This is for committer list of CodeRepos. |
| 359 | | authors = $("//*[@id='Committers']/following-sibling::ul[1]//a[contains(@href, '/share/wiki/Committers/')]"); |
| 360 | | } |
| 361 | | break; |
| 362 | | default: break; |
| 363 | | } |
| 364 | | |
| 365 | | for (var i = 0, n = authors.length; i < n; i++) { |
| 366 | | TracUtils.AuthorIcons.insertIcon(authors[i]); |
| 367 | | } |
| 368 | | |
| 369 | | $("#metanav ul li.first").each(function () { |
| 370 | | var uname = $(this).text().match(/logged in as ([^,]+)/); |
| 371 | | if (uname) { |
| 372 | | var a = $("<a/>").attr("href", TracUtils.AuthorIcons.getAuthorPage(uname[1])).append(uname[1]); |
| 373 | | a.appendTo( |
| 374 | | $(this).empty().append("logged in as ") |
| 375 | | ); |
| 376 | | TracUtils.AuthorIcons.insertIcon(a); |
| 377 | | } |
| 378 | | }); |
| 379 | | } |
| 380 | | |
| 381 | | , getIconByAuthor : function (author) { |
| 382 | | var iconUrl = TracUtils.AUTHOR_ICONS[author] || TracUtils.AUTHOR_ICONS["*default*"]; |
| 383 | | |
| 384 | | // Hatena ID |
| 385 | | iconUrl = iconUrl.replace(/^id:(([\w-]{2})[\w-]*)/, 'http://www.hatena.ne.jp/users/$2/$1/profile_s.gif'); |
| 386 | | |
| 387 | | return iconUrl; |
| 388 | | } |
| 389 | | |
| 390 | | , insertIcon : function (authorEOrArray) { |
| 391 | | var authorE, author; |
| 392 | | if (authorEOrArray instanceof Array) { |
| 393 | | authorE = $(authorEOrArray[0]); |
| 394 | | author = authorEOrArray[1]; |
| 395 | | } else { |
| 396 | | authorE = $(authorEOrArray); |
| 397 | | author = authorE.text().replace(/^\s+|\??\s*$/g, ''); |
| 398 | | } |
| 399 | | |
| 400 | | var iconurl = TracUtils.AuthorIcons.getIconByAuthor(author); |
| 401 | | if (!iconurl) return; |
| 402 | | |
| 403 | | var img = $("<img width='16' height='16' alt='' class='committer-icon'/>") |
| 404 | | .attr("src", iconurl) |
| 405 | | .css("margin-right", "0.5em"); |
| 406 | | |
| 407 | | var a = $("<a style='background-image: none ! important; padding-left: 0pt; border: none;'/>") |
| 408 | | .attr("href", TracUtils.AuthorIcons.getAuthorPage(author)) |
| 409 | | .append(img); |
| 410 | | |
| 411 | | authorE.prepend(a); |
| 412 | | } |
| 413 | | |
| 414 | | , getAuthorPage : function (author) { |
| 415 | | return TracUtils.TRAC_BASE + "/wiki/Committers/" + author; |
| 416 | | } |
| 417 | | } |
| | 14 | SVN_REPOS_BASE : 'http://svn.coderepos.org/share', |
| | 15 | TRAC_BASE : 'http://coderepos.org/share', |
| | 16 | AUTHOR_ICONS : { |
| | 17 | //'tomoyo' : 'http://www.hatena.ne.jp/users/ma/mayuki/profile_s.gif' |
| | 18 | //'tomoyo' : 'id:mayuki' |
| | 19 | '*default*' : 'http://coderepos.org/share/htdocs/default-author-icon.png' |
| | 20 | , 'mayuki' : 'id:mayuki' |
| | 21 | , 'yappo' : 'id:yappo' |
| | 22 | , 'typester' : 'http://www.gravatar.com/avatar.php?gravatar_id=fbc6511bcc0649366086c0445fb456d3&size=16'//'id:typester' |
| | 23 | , 'kentaro' : 'id:antipop' |
| | 24 | , 'mizzy' : 'id:gosukenator' |
| | 25 | , 'charsbar' : 'id:charsbar' |
| | 26 | , 'secondlife' : 'id:secondlife' |
| | 27 | , 'kazeburo' : 'id:kazeburo' |
| | 28 | , 'otsune' : 'id:otsune' |
| | 29 | , 'hirose31' : 'id:hirose31' |
| | 30 | , 'nipotan' : 'id:nipotan' |
| | 31 | , 'itkz' : 'id:itkz' |
| | 32 | , 'xcezx' : 'id:xcezx' |
| | 33 | , 'nyarla' : 'id:nyarla-net' |
| | 34 | , 'tokuhirom' : 'id:tokuhirom' |
| | 35 | , 'daisuke' : 'id:lestrrat' |
| | 36 | , 'kana' : 'id:ka-nacht' |
| | 37 | , 'cho45' : 'id:cho45' |
| | 38 | , 'kan' : 'id:kan' |
| | 39 | , 'zigorou' : 'id:ZIGOROu' |
| | 40 | , 'masaki' : 'id:ikasam_a' |
| | 41 | , 'holidays-l' : 'id:holidays-l' |
| | 42 | , 'yoko' : 'id:yksk' |
| | 43 | , 'mattn' : 'id:mattn' |
| | 44 | , 'lopnor' : 'id:lopnor' |
| | 45 | , 'gyuque' : 'id:gyuque' |
| | 46 | , 'yugui' : 'id:yugui' |
| | 47 | , 'akihito' : 'id:t-akihito' |
| | 48 | , 'fujiwara' : 'id:sfujiwara' |
| | 49 | , 'yusukebe' : 'id:kamawada' |
| | 50 | , 'miyagawa' : 'id:miyagawa' |
| | 51 | , 'topia' : 'id:topia' |
| | 52 | , 'woremacx' : 'id:woremacx' |
| | 53 | , 'amachang' : 'id:amachang' |
| | 54 | , 'takesako' : 'id:TAKESAKO' |
| | 55 | , 'eto' : 'id:eto' |
| | 56 | , 'dankogai' : 'id:dankogai' |
| | 57 | , 'jknaoya' : 'id:jknaoya' |
| | 58 | , 'yasu' : 'id:hirata_yasuyuki' |
| | 59 | , 'holygrail' : 'id:HolyGrail' |
| | 60 | , 'elim' : 'id:elim' |
| | 61 | , 'cheebow' : 'id:cheebow' |
| | 62 | , 'ariela' : 'http://www.gravatar.com/avatar.php?gravatar_id=dd5dfb5d738d5b5fb1c9a8b234945ea6&size=16'//'id:transrain' |
| | 63 | , 'tomyhero' : 'id:tomyhero' |
| | 64 | , 'hetappi' : 'id:hetappi' |
| | 65 | , 'coji' : 'id:coji' |
| | 66 | , 'takemaru' : 'id:teahut' |
| | 67 | , 'akasata' : 'id:akasata' |
| | 68 | , 'okuryu' : 'id:okuryu' |
| | 69 | , 'tasuku' : 'id:tasukuchan' |
| | 70 | , 'snj14' : 'id:snj14' |
| | 71 | , 'shachi' : 'id:shachi_kk' |
| | 72 | , 'omoon' : 'id:omoon' |
| | 73 | , 'aerith' : 'id:aerith' |
| | 74 | , 'clouder' : 'id:clouder' |
| | 75 | , 'takkyun' : 'id:simpleboxes' |
| | 76 | , 'naoya_t' : 'http://ntzone.info/misc/keroro.gif' |
| | 77 | , 'takefumi' : 'id:takefumi' |
| | 78 | , 'walf443' : 'id:walf443' |
| | 79 | , 'psychs' : 'id:Psychs' |
| | 80 | , 'ewigkeit' : 'id:Ewigkeit' |
| | 81 | , 'yoshiori' : 'id:Yoshiori' |
| | 82 | , 'dev0000' : 'http://www.developer0000.jp/16.jpg' |
| | 83 | , 'machu' : 'id:kmachu' |
| | 84 | , 'norio_s' : 'id:norio_s' |
| | 85 | , 'hsbt' : 'id:h-sbt' |
| | 86 | , 'nori090' : 'id:nori090' |
| | 87 | , 'lyokato' : 'id:lyokato' |
| | 88 | , 'drgqst' : 'id:drgqst' |
| | 89 | , 'mrkn' : 'id:mrkn' |
| | 90 | , 'tfunato' : 'id:tfunato' |
| | 91 | , 'tsuka' : 'id:tsuka05' |
| | 92 | , 'niw' : 'id:niw' |
| | 93 | , 'tomi-ru' : 'id:tomi-ru' |
| | 94 | , 'yto' : 'id:yto' |
| | 95 | , 'motemen' : 'id:motemen' |
| | 96 | , 'shyouhei' : 'http://mput.dip.jp/mput/images/icon.jpg' |
| | 97 | , 'm-takagi' : 'http://www.gravatar.com/avatar.php?gravatar_id=c3f5a6e729b57f99cb9e7b3ca60152aa&size=16' |
| | 98 | , 'takano32' : 'id:takano32' |
| | 99 | , 'kakutani' : 'id:kakutani' |
| | 100 | , 'poppen' : 'id:poppen' |
| | 101 | , 'kotas' : 'id:kotas' |
| | 102 | , 'nekokak' : 'id:nekokak' |
| | 103 | , 'tosik' : 'id:tosik' |
| | 104 | , 'fbis' : 'id:fbis' |
| | 105 | , 'rsk' : 'id:rsky' |
| | 106 | , 'mallowlabs' : 'id:mallowlabs' |
| | 107 | , 'nakamud' : 'http://s3.amazonaws.com/twitter_production/profile_images/35752262/SP_mu-toko_mini.jpg' |
| | 108 | , 'chiba' : 'id:nihen' |
| | 109 | , 'funaki' : 'id:nob_funaki' |
| | 110 | , 'dzfl' : 'id:dzfl' |
| | 111 | , 'shimooka' : 'id:shimooka' |
| | 112 | // , 'noriaki' : 'http://s3.amazonaws.com/twitter_production/profile_images/40454132/2f94929d_mini.jpg' |
| | 113 | , 'suztomo' : 'id:suztomo' |
| | 114 | , 'klm' : 'id:k1m' |
| | 115 | , 'akio0911' : 'id:akio0911' |
| | 116 | , 'cactusman' : 'id:cactusman' |
| | 117 | , 'vkgtaro' : 'id:vkgtaro' |
| | 118 | , 'todesking' : 'http://data.tumblr.com/avatar_1fe558be2f23_16.gif' |
| | 119 | , 'sho' : 'id:sho' |
| | 120 | , 'a2c' : 'id:a2c' |
| | 121 | , 'hidek' : 'http://www.gravatar.com/avatar.php?gravatar_id=7d55041891ece2f35375108aa2d27255&size=16'//'id:hide-K'' |
| | 122 | , 'yhara' : 'id:yhara' |
| | 123 | , 'PoohKid' : 'id:PoohKid' |
| | 124 | , 'samurai20000' : 'id:samurai20000' |
| | 125 | , 'yasuyuki' : 'id:YaSuYuKi' |
| | 126 | , 'mootoh' : 'id:moira' |
| | 127 | , 'tokada' : 'id:tokada' |
| | 128 | , 'llamerada' : 'id:llamerada' |
| | 129 | , 'shn' : 'id:shn' |
| | 130 | , 'nejimaki' : 'id:firewood' |
| | 131 | , 'kan' : 'id:mikihoshi' |
| | 132 | , 'hideden' : 'id:hideden' |
| | 133 | , 'niku' : 'http://niku.name/favicon.ico' |
| | 134 | , 'ohac' : 'id:ohac' |
| | 135 | , 'hio' : 'http://www.gravatar.com/avatar.php?gravatar_id=a72d2120c066d47ad3d29c17b2f4db72&size=16' |
| | 136 | , 'os0x' : 'id:os0x' |
| | 137 | , 'akiyan' : 'id:akiyan' |
| | 138 | , 'inudog' : 'http://eringi.com/favicon.ico' |
| | 139 | , 'suzuki' : 'id:zatsubun' |
| | 140 | , 'haruka' : 'http://drumsoft.com/favicon.ico' |
| | 141 | , 'syttru' : 'id:syttru' |
| | 142 | , 'iskwrsk' : 'id:iskwrsk' |
| | 143 | , 'komatsuna' : 'http://data.tumblr.com/avatar_82a9ef4053ec_30.gif' |
| | 144 | , 'tarchan' : 'id:tarchan' |
| | 145 | , 'tyoro' : 'id:tyoro1210' |
| | 146 | , 'Sore_0' : 'id:Sore_0' |
| | 147 | , 'teramako' : 'id:teramako' |
| | 148 | , 'kamipo' : 'id:kamipo' |
| | 149 | , 'ihag' : 'id:ihag' |
| | 150 | , 'valda' : 'http://data.tumblr.com/avatar_a5fb0192ec7d_16.gif' |
| | 151 | , 'gan2' : 'id:gan2' |
| | 152 | , 'sasezaki' : 'id:sasezaki' |
| | 153 | , 'kdoya' : 'id:kdoya' |
| | 154 | } |
| | 155 | |
| | 156 | , installAll : function () { |
| | 157 | TracUtils.addJumpToReposLink(); |
| | 158 | TracUtils.clickableCodeArea(); |
| | 159 | TracUtils.addBodyClass(); |
| | 160 | TracUtils.addCommitterRecentCommits(); |
| | 161 | TracUtils.addRecentChangesForProject(); |
| | 162 | TracUtils.addUserscriptsUtils(); |
| | 163 | TracUtils.AuthorIcons.showAuthorIcons(); |
| | 164 | } |
| | 165 | |
| | 166 | , isWikiStart : function () { |
| | 167 | var pn = location.pathname |
| | 168 | return ( |
| | 169 | pn == "/share/wiki/WikiStart" || |
| | 170 | pn == "/share/wiki/" || |
| | 171 | pn == "/share/wiki" || |
| | 172 | pn == "/share/" || |
| | 173 | pn == "/share" |
| | 174 | ); |
| | 175 | } |
| | 176 | |
| | 177 | , getSourcePath : function (tracPath) { |
| | 178 | return String(tracPath).replace(TracUtils.TRAC_BASE + "/browser", TracUtils.SVN_REPOS_BASE).replace(/\?.*/, ''); |
| | 179 | } |
| | 180 | |
| | 181 | /** |
| | 182 | * Browse Source のときに該当する svn web にすぐ翔べるリンクと |
| | 183 | * ?rev= をはずすリンクを追加 |
| | 184 | */ |
| | 185 | , addJumpToReposLink : function () { |
| | 186 | var aboutLink = $("#metanav li.last a"); |
| | 187 | if (location.pathname.indexOf("/share/browser") == 0) { |
| | 188 | var sourcePath = TracUtils.getSourcePath(location); |
| | 189 | aboutLink.replaceWith( |
| | 190 | $("<a title='Jump to Repository'>SVN Web</a>").attr("href", sourcePath) |
| | 191 | ); |
| | 192 | $("#ctxtnav li:first").after($("<li/>").append($("<a>SVN Web</a>").attr("href", sourcePath))); |
| | 193 | $("#ctxtnav li:first").after($("<li/>").append($("<a>Latest Revision</a>").attr("href", location.pathname))); |
| | 194 | } else { |
| | 195 | aboutLink.replaceWith( |
| | 196 | $("<a title='Jump to Repository'>SVN Web</a>").attr("href", TracUtils.SVN_REPOS_BASE) |
| | 197 | ); |
| | 198 | } |
| | 199 | } |
| | 200 | |
| | 201 | /** |
| | 202 | * Wiki に書かれた JS のコードを実行可能に |
| | 203 | * 冒頭に //Executable と書くと実行できるようになる。 |
| | 204 | */ |
| | 205 | , clickableCodeArea : function () { |
| | 206 | var start = "//Executable"; |
| | 207 | $("//*[@id='content']//div[@class='code']/pre[contains(.//span[@class='code-comment'],'"+start+"')]").each(function () { |
| | 208 | var e = $(this); |
| | 209 | var js = e.text(); |
| | 210 | var a = $("<a href='javascript:void(156)'>Click to execute.</a>").click(function () { |
| | 211 | eval(js); |
| | 212 | }).css({ |
| | 213 | fontSize : "80%", |
| | 214 | fontWeight : "bold", |
| | 215 | border : "1px solid #ccc", |
| | 216 | display : "block", |
| | 217 | width : "10em", |
| | 218 | padding : "0.2em", |
| | 219 | margin : "0 auto 0.2em 0", |
| | 220 | textAlign : "center" |
| | 221 | }).insertBefore(e.parent()); |
| | 222 | }); |
| | 223 | } |
| | 224 | |
| | 225 | /** |
| | 226 | * CSS 補佐用 (IE6 で CSS セレクタの対応が貧弱なため) |
| | 227 | */ |
| | 228 | , addBodyClass : function () { |
| | 229 | if (location.pathname.indexOf("/share/wiki/Committers") == 0) { |
| | 230 | document.body.className = "committer"; |
| | 231 | } |
| | 232 | if (TracUtils.isWikiStart()) { |
| | 233 | $("//*[@id='Committers']/following-sibling::ul[1]").addClass("committer-list"); |
| | 234 | $("//*[@id='Projects']/following-sibling::ul[1]").addClass("project-list"); |
| | 235 | } |
| | 236 | } |
| | 237 | |
| | 238 | /** |
| | 239 | * コミッタページにその人の最近のコミットリストを表示する。 |
| | 240 | * Trac の検索機能を使っているので、コミットログに名前をかきまくると |
| | 241 | * 検索結果の1ページ目 == 10個しかみていないので |
| | 242 | * その人の最近のコミットがなかったことになるいじめができる。 |
| | 243 | */ |
| | 244 | , addCommitterRecentCommits : function () { |
| | 245 | if (!location.search && !/^\/share\/wiki\/Committers\/([^\/]{3,})/.test(location.pathname)) return; |
| | 246 | var author = RegExp.$1; |
| | 247 | $.get(TracUtils.TRAC_BASE+"/search?q="+author+"&noquickjump=1&changeset=on", {}, function (data) { |
| | 248 | $("<div class='recent-commits'><h2>Recent Commits</h2></div>").append( |
| | 249 | $(data).xfind(".//dl") |
| | 250 | .xfind("dd[span[@class='author'] != 'By "+author+"']") |
| | 251 | .xfind("preceding-sibling::dt[1] | preceding-sibling::dd[1]").remove().end() |
| | 252 | .remove() |
| | 253 | .end() |
| | 254 | ).appendTo($("#searchable, #content").get(0)); |
| | 255 | }); |
| | 256 | } |
| | 257 | |
| | 258 | /** |
| | 259 | * プロジェクトページへ最近のコミットリストを表示する。 |
| | 260 | * {{{ |
| | 261 | * svn co http://svn.coderepos.org/share/... |
| | 262 | * }}} |
| | 263 | * のように co と checkout, export の書いてあるページが対象。 |
| | 264 | */ |
| | 265 | , addRecentChangesForProject : function () { |
| | 266 | // IE だとなぜかどうしようもなく遅いので処理しない |
| | 267 | if ($.browser.msie || !TracUtils.isWikiStart() && location.pathname.indexOf("/share/wiki/") != 0) return; |
| | 268 | var target_re = RegExp("svn\\s+(?:c(?:o|heckout)|export)\\s+"+TracUtils.SVN_REPOS_BASE+"(\\S+)"); |
| | 269 | $("#searchable pre").each(function () { |
| | 270 | var m = $(this).text().match(target_re); |
| | 271 | if (!m) return; |
| | 272 | var path = m[1].replace(/\/trunk\/?$/, ""); |
| | 273 | var url = TracUtils.TRAC_BASE + "/log" + path; |
| | 274 | $.get(url, {}, function (data) { |
| | 275 | // 高速化と、jQuery がだす getElementsByTagName がないという |
| | 276 | // エラーを回避するため正規表現 |
| | 277 | data = data.match(/<table id="chglist"[\S\s]+<\/table>/)[0]; |
| | 278 | $("<div><h2><a href='"+url+"'>Project Recent Changes</a></h2></div>") |
| | 279 | .append( |
| | 280 | $(data) |
| | 281 | .find("tr:gt(10)").remove().end() |
| | 282 | .find("th.diff, td.diff, th.change, td.change, th.rev, td.rev").remove().end() |
| | 283 | ) |
| | 284 | .appendTo("#searchable"); |
| | 285 | }); |
| | 286 | return false; |
| | 287 | }); |
| | 288 | } |
| | 289 | |
| | 290 | /** |
| | 291 | * Userscripts のユーティリティ |
| | 292 | */ |
| | 293 | , addUserscriptsUtils : function () { |
| | 294 | if (($.browser.mozilla || $.browser.safari)) { |
| | 295 | // 尻? |
| | 296 | var isUserJS = function(path) { |
| | 297 | return /\.user\.js$/.test(path); |
| | 298 | }; |
| | 299 | // user.js のページがインストール画面でてうざいのをなんとかする。 |
| | 300 | // あんまり広範囲にやりたくないので決め打ち |
| | 301 | if (location.pathname.substring(0, 42) == "/share/browser/lang/javascript/userscripts") { |
| | 302 | $("a").each(function () { |
| | 303 | if (isUserJS(this.href)) this.href += "?"; |
| | 304 | }); |
| | 305 | } |
| | 306 | |
| | 307 | // user.js のページにインストールURLを追加する. |
| | 308 | if (isUserJS(location.pathname)) { |
| | 309 | var uri = TracUtils.getSourcePath(location); |
| | 310 | $('<a/>').attr({ |
| | 311 | href : uri, |
| | 312 | title : uri.split('/').slice(-1) + ' をインストールする' |
| | 313 | }) |
| | 314 | .text('インストール - ' + uri) |
| | 315 | .insertAfter($('h1:first')); |
| | 316 | } |
| | 317 | } |
| | 318 | } |
| | 319 | |
| | 320 | /** |
| | 321 | * Trac のあらゆるところに設定されたアイコンを表示する。 |
| | 322 | * TracAuthorIcon.js を jQuery/XPath 依存にして簡略化したもの |
| | 323 | */ |
| | 324 | , AuthorIcons : { |
| | 325 | showAuthorIcons : function () { |
| | 326 | var authors = []; |
| | 327 | switch ($("#content").attr("class")) { |
| | 328 | case 'browser': |
| | 329 | $('//*[@id="info"]//th').each(function () { |
| | 330 | authors.push([this, $(this).text().match(/checked in by ([^,]+)/)[1]]); |
| | 331 | }); |
| | 332 | $('//*[@id="dirlist"]//span[@class="author"]').each(function () { |
| | 333 | authors.push([this, $(this).text().match(/^([^:]+):/)[1]]); |
| | 334 | }); |
| | 335 | break; |
| | 336 | case 'timeline': |
| | 337 | $('//*[@id="content"]//dt/a').each(function () { |
| | 338 | authors.push([this, this.lastChild.nodeValue.match(/by\s+(.+)$/)[1]]); |
| | 339 | }); |
| | 340 | break; |
| | 341 | case 'log': |
| | 342 | case 'changeset': |
| | 343 | authors = $('(//*[@id="overview"] | //*[@id="chglist"])//*[@class="author"]'); |
| | 344 | break; |
| | 345 | case 'wiki': |
| | 346 | if (/^\/share\/wiki\/Committers\/([^\/]+)/.test(location.pathname)) { |
| | 347 | var author = RegExp.$1; |
| | 348 | var iconurl = TracUtils.AuthorIcons.getIconByAuthor(author); |
| | 349 | if (!iconurl) break; |
| | 350 | var img = $("<img width='16' height='16' alt='' class='committer-icon'/>").attr("src", iconurl); |
| | 351 | var h1 = $("//*[@id='searchable']/h1[1]"); |
| | 352 | if (h1.length) { |
| | 353 | h1.append(img); |
| | 354 | } else { |
| | 355 | $("#content").prepend(img); |
| | 356 | } |
| | 357 | } else |
| | 358 | if (TracUtils.isWikiStart()) { |
| | 359 | // This is for committer list of CodeRepos. |
| | 360 | authors = $("//*[@id='Committers']/following-sibling::ul[1]//a[contains(@href, '/share/wiki/Committers/')]"); |
| | 361 | } |
| | 362 | break; |
| | 363 | default: break; |
| | 364 | } |
| | 365 | |
| | 366 | for (var i = 0, n = authors.length; i < n; i++) { |
| | 367 | TracUtils.AuthorIcons.insertIcon(authors[i]); |
| | 368 | } |
| | 369 | |
| | 370 | $("#metanav ul li.first").each(function () { |
| | 371 | var uname = $(this).text().match(/logged in as ([^,]+)/); |
| | 372 | if (uname) { |
| | 373 | var a = $("<a/>").attr("href", TracUtils.AuthorIcons.getAuthorPage(uname[1])).append(uname[1]); |
| | 374 | a.appendTo( |
| | 375 | $(this).empty().append("logged in as ") |
| | 376 | ); |
| | 377 | TracUtils.AuthorIcons.insertIcon(a); |
| | 378 | } |
| | 379 | }); |
| | 380 | } |
| | 381 | |
| | 382 | , getIconByAuthor : function (author) { |
| | 383 | var iconUrl = TracUtils.AUTHOR_ICONS[author] || TracUtils.AUTHOR_ICONS["*default*"]; |
| | 384 | |
| | 385 | // Hatena ID |
| | 386 | iconUrl = iconUrl.replace(/^id:(([\w-]{2})[\w-]*)/, 'http://www.hatena.ne.jp/users/$2/$1/profile_s.gif'); |
| | 387 | |
| | 388 | return iconUrl; |
| | 389 | } |
| | 390 | |
| | 391 | , insertIcon : function (authorEOrArray) { |
| | 392 | var authorE, author; |
| | 393 | if (authorEOrArray instanceof Array) { |
| | 394 | authorE = $(authorEOrArray[0]); |
| | 395 | author = authorEOrArray[1]; |
| | 396 | } else { |
| | 397 | authorE = $(authorEOrArray); |
| | 398 | author = authorE.text().replace(/^\s+|\??\s*$/g, ''); |
| | 399 | } |
| | 400 | |
| | 401 | var iconurl = TracUtils.AuthorIcons.getIconByAuthor(author); |
| | 402 | if (!iconurl) return; |
| | 403 | |
| | 404 | var img = $("<img width='16' height='16' alt='' class='committer-icon'/>") |
| | 405 | .attr("src", iconurl) |
| | 406 | .css("margin-right", "0.5em"); |
| | 407 | |
| | 408 | var a = $("<a style='background-image: none ! important; padding-left: 0pt; border: none;'/>") |
| | 409 | .attr("href", TracUtils.AuthorIcons.getAuthorPage(author)) |
| | 410 | .append(img); |
| | 411 | |
| | 412 | authorE.prepend(a); |
| | 413 | } |
| | 414 | |
| | 415 | , getAuthorPage : function (author) { |
| | 416 | return TracUtils.TRAC_BASE + "/wiki/Committers/" + author; |
| | 417 | } |
| | 418 | } |