MOD_Seiga

ニコニコ静画のUIをいじる

目前为 2015-10-06 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name MOD_Seiga
  3. // @namespace https://github.com/segabito/
  4. // @description ニコニコ静画のUIをいじる
  5. // @include http://seiga.nicovideo.jp/seiga/*
  6. // @include http://seiga.nicovideo.jp/tag/*
  7. // @include http://seiga.nicovideo.jp/illust/*
  8. // @include http://lohas.nicoseiga.jp/o/*
  9. // @version 0.3.4
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. // ver 0.2.20
  14. // ver 0.2.21
  15. // - 新バージョンに対応
  16.  
  17. // ver 0.2.13
  18. // - クリップの向きが変わったので、クリップメニューの位置を設定できるようにした
  19.  
  20. // ver 0.2.12
  21. // - コメント一覧で一番下のコメントが見きれる問題二を勝手に直す
  22. // - タグ検索時にキーワード検索フォームに自動でタグのテキストを入れる
  23.  
  24. // ver 0.2.11
  25. // - コメント中の動画・静画IDやURLへのリンクに対応
  26. // - 春画でも説明文のURL自動リンクに対応
  27. // - 切れないサムネをAutopagerizeに対応
  28.  
  29. // ver 0.2.10
  30. // - ヘッダ固定の時の自動スクロール修正
  31. // - タグ検索時にカウンターが常時表示されるように変更
  32. // - ページ下側の投稿者アイコンを隠す設定 (右上だけあればいい人用)
  33.  
  34. // ver 0.2.9
  35. // - 動画タイトルの位置に自動スクロールする対応
  36. // - おもにwindows等、縦ホイールしかない環境で横スクロールしやすくする。Firefoxでうまくいかない
  37. // - ウィンドウ幅が狭いときはページ一番上に戻るボタンを出さなくする設定
  38.  
  39. // ver 0.2.8
  40. // - クリップボタンの位置を上にしてみる
  41. // - 右上の投稿者アイコンを大きくしてみる
  42.  
  43. // ver 0.2.7
  44. // - 全画面表示時に画像クリックでズームが切り替わる対応
  45.  
  46. // ver 0.2.6
  47. // - サムネイルがカットされなくする対応をタグ検索とイラストトップにも適用
  48.  
  49. // ver 0.2.5
  50. // - サムネイルがカットされなくする対応。 設定で無効にも出来ます
  51.  
  52. // ver 0.2.4
  53. // - 右カラム広告のせいで無駄に横スクロールが発生しているのを勝手に直す
  54.  
  55. // ver 0.2.3
  56. // - 市場を近づけた
  57.  
  58. // ver 0.2.2
  59. // - ホバーしなくてもタイトルと説明文が出るように
  60.  
  61. // ver 0.2.1
  62. // - タグを説明文の下・説明文の右に置けるように
  63.  
  64. // ver 0.2.0
  65. // - 動かなくなっていたのでとりあえずまた動くようにした
  66.  
  67. // ver 0.1.0
  68. // - 設定パネルを追加
  69. // - 投稿者を右上に出せるようにした
  70.  
  71. // ver 0.0.2
  72. // - ホバーしなくてもタイトルと説明文が出るように
  73. // - 見えないところでタグが増殖していたのを修正
  74.  
  75. // ver 0.0.1 最初のバージョン
  76.  
  77. (function() {
  78. var monkey = (function(){
  79. 'use strict';
  80. var $ = window.jQuery;
  81.  
  82. var A4_WIDTH = 210, A4_HEIGHT = 297;
  83.  
  84.  
  85. window.MOD_Seiga = {
  86. initialize: function() {
  87. this.initializeUserConfig();
  88. var path = location.pathname;
  89. if (path.indexOf('/seiga/') === 0) {
  90. this.initializeSeigaView();
  91. } else
  92. if (path.indexOf('/illust/') === 0 && path.indexOf('ranking') < 0) {
  93. this.initializeIllustTop();
  94. } else
  95. if (path.indexOf('/tag/') === 0) {
  96. this.initializeTagSearch();
  97. } else
  98. if (path.indexOf('/o/') === 0) {
  99. this.initializeFullView();
  100. }
  101.  
  102. },
  103. initializeSeigaView: function() {
  104. if ($('#content').length > 0) {
  105. this.initializeBaseLayout();
  106.  
  107. this.initializeScrollTop();
  108. this.initializeDescription();
  109. this.initializeCommentLink();
  110. this.initializeThumbnail();
  111. this.initializePageTopButton();
  112. this.initializeKnockout();
  113. this.initializeFullScreenRequest();
  114.  
  115. this.initializeOther();
  116. this.initializeSettingPanel();
  117.  
  118. $('body').addClass('MOD_Seiga_View');
  119. this.initializeCss();
  120. } else {
  121. // 春画っぽい。説明文の自動リンクだけやる
  122. this.initializeDescription();
  123. }
  124.  
  125. },
  126. initializeIllustTop: function() {
  127. this.initializeThumbnail();
  128. this.initializeSettingPanel();
  129.  
  130. this.initializePageTopButton();
  131. $('body').addClass('MOD_Seiga_Top');
  132. this.initializeCss();
  133. },
  134. initializeTagSearch: function() {
  135. this.initializeThumbnail();
  136. this.initializeSettingPanel();
  137.  
  138. this.initializePageTopButton();
  139. setTimeout(function() {
  140. var $search = $('#bar_search');
  141. if (
  142. $search.val() === 'イラストを検索' ||
  143. $search.val() === '春画を検索') {
  144. $search.val($('#ko_tagwatch_min').attr('data-query')).addClass('edited').css({color: '#000'});
  145. }
  146. }, 1000);
  147. $('body').addClass('MOD_Seiga_TagSearch');
  148. this.initializeCss();
  149. },
  150. initializeFullView: function() {
  151. $('body').addClass('MOD_Seiga_FullView');
  152. this.initializeFullscreenImage();
  153. this.initializeCss();
  154. },
  155. addStyle: function(styles, id) {
  156. var elm = document.createElement('style');
  157. elm.type = 'text/css';
  158. if (id) { elm.id = id; }
  159.  
  160. var text = styles.toString();
  161. text = document.createTextNode(text);
  162. elm.appendChild(text);
  163. var head = document.getElementsByTagName('head');
  164. head = head[0];
  165. head.appendChild(elm);
  166. return elm;
  167. },
  168. fullScreen: {
  169. now: function() {
  170. if (document.fullScreenElement || document.mozFullScreen || document.webkitIsFullScreen) {
  171. return true;
  172. }
  173. return false;
  174. },
  175. request: function(target) {
  176. var elm = typeof target === 'string' ? document.getElementById(target) : target;
  177. if (!elm) { return; }
  178. if (elm.requestFullScreen) {
  179. elm.requestFullScreen();
  180. } else if (elm.webkitRequestFullScreen) {
  181. elm.webkitRequestFullScreen();
  182. } else if (elm.mozRequestFullScreen) {
  183. elm.mozRequestFullScreen();
  184. }
  185. },
  186. cancel: function() {
  187. if (document.cancelFullScreen) {
  188. document.cancelFullScreen();
  189. } else if (document.webkitCancelFullScreen) {
  190. document.webkitCancelFullScreen();
  191. } else if (document.mozCancelFullScreen) {
  192. document.mozCancelFullScreen();
  193. }
  194. }
  195. },
  196. initializeCss: function() {
  197. var __common_css__ = (function() {/*
  198. .MOD_SeigaSettingMenu a {
  199. font-weight: bolder; color: darkblue !important;
  200. }
  201. #MOD_SeigaSettingPanel {
  202. position: fixed;
  203. bottom: 2000px; right: 8px;
  204. z-index: -1;
  205. width: 500px;
  206. background: #f0f0f0; border: 1px solid black;
  207. padding: 8px;
  208. transition: bottom 0.4s ease-out;
  209. text-align: left;
  210. }
  211. #MOD_SeigaSettingPanel.open {
  212. display: block;
  213. bottom: 8px;
  214. box-shadow: 0 0 8px black;
  215. z-index: 10000;
  216. }
  217. #MOD_SeigaSettingPanel .close {
  218. position: absolute;
  219. cursor: pointer;
  220. right: 8px; top: 8px;
  221. }
  222. #MOD_SeigaSettingPanel .panelInner {
  223. background: #fff;
  224. border: 1px inset;
  225. padding: 8px;
  226. min-height: 300px;
  227. overflow-y: scroll;
  228. max-height: 500px;
  229. }
  230. #MOD_SeigaSettingPanel .panelInner .item {
  231. border-bottom: 1px dotted #888;
  232. margin-bottom: 8px;
  233. padding-bottom: 8px;
  234. }
  235. #MOD_SeigaSettingPanel .panelInner .item:hover {
  236. background: #eef;
  237. }
  238. #MOD_SeigaSettingPanel .windowTitle {
  239. font-size: 150%;
  240. }
  241. #MOD_SeigaSettingPanel .itemTitle {
  242. }
  243. #MOD_SeigaSettingPanel label {
  244. margin-right: 12px;
  245. }
  246. #MOD_SeigaSettingPanel small {
  247. color: #666;
  248. }
  249. #MOD_SeigaSettingPanel .expert {
  250. margin: 32px 0 16px;
  251. font-size: 150%;
  252. background: #ccc;
  253. }
  254.  
  255. .comment_info .mod_link, .description .otherSite {
  256. text-decoration: underline;
  257. font-weight: bolder;
  258. }
  259.  
  260. {* 画面が狭いときに操作不能になる部分などを直す *}
  261. @media screen and (max-width: 1023px) {
  262. .mod_hidePageTopButton.MOD_Seiga .comment_all .comment_all_inner .illust_main .illust_side .illust_comment .comment_list {
  263. position: fixed;
  264. right: 25px;
  265. top: 105px; bottom: 105px; overflow-y: auto;
  266. }
  267. .mod_hidePageTopButton.MOD_Seiga .comment_all .comment_all_inner .illust_main .illust_side .illust_comment .comment_list .text {
  268. margin: 0 16px 0 0;
  269. }
  270. .mod_hidePageTopButton.MOD_Seiga .comment_all .comment_all_inner .illust_main .illust_side .illust_comment .res .inner {
  271. position: fixed;
  272. bottom: 0; right: 5px;
  273. }
  274. .mod_hidePageTopButton.MOD_Seiga .comment_all .comment_all_header .control{
  275. position: fixed; top: 35px; right: 25px; {* 横幅が狭いと閉じるを押せない問題の対応 *}
  276. }
  277. }
  278. @media screen and (max-width: 1183px) {
  279. .mod_hidePageTopButton #pagetop { display: none !important; }
  280. }
  281.  
  282. @media print {
  283.  
  284. body {
  285. background: #000 !important; {* 背景を黒にしたい場合は「背景画像を印刷」にチェック *}
  286. margin: 0;
  287. padding: 0;
  288. overflow: hidden;
  289. width: 210mm;
  290. {* height: calc(297mm - 19mm); *} {* 19mmは印刷マージン *}
  291. }
  292. body.landscape {
  293. width: 297mm;
  294. {* height: calc(210mm - 19mm); *}
  295. }
  296. .toggleFullScreen, .control {
  297. display: none !important;
  298. opacity: 0 !important;
  299. }
  300.  
  301. .MOD_Seiga_FullView .illust_view_big img {
  302. top: 0 !important;
  303. left: 0 !important;
  304. transform: inherit !important;
  305. -webkit-transform: inherit !important;
  306. }
  307.  
  308. .MOD_Seiga_FullView:not(.landscape) .illust_view_big img {
  309. width: auto;
  310. height: auto;
  311. }
  312. .MOD_Seiga_FullView:not(.landscape).fitV .illust_view_big img {
  313. {*width: auto;
  314. height: calc(297mm - 19mm); *}
  315. }
  316. .MOD_Seiga_FullView.landscape .illust_view_big img {
  317. {*width: 297mm;
  318. height: auto; *}
  319. }
  320. .MOD_Seiga_FullView.landscape.fitV .illust_view_big img {
  321. {*width: auto;
  322. height: calc(210mm - 19mm); *}
  323. margin-top: 0;
  324. }
  325. }
  326.  
  327.  
  328. */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1].replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
  329.  
  330. var __css__ = (function() {/*
  331.  
  332.  
  333. {* マイページや投稿へのリンクがあっても、すぐ上にniconico共通のヘッダーがあるのでいらないと思う。ということで省スペース優先で消す。*}
  334. #header { background: #fff; }
  335. #header .sg_global_bar {
  336. display: none;
  337. }
  338. #header_cnt { width: 1004px; }
  339.  
  340. {* サムネのホバー調整 *}
  341. .list_item_cutout.middle {
  342. height: 154px;
  343. text-align: center;
  344. }
  345. .list_item_cutout.middle a {
  346. height: 100%;
  347. overflow: visible;
  348. }
  349. .list_item_cutout.middle a .illust_info, .list_item_cutout.middle a .illust_info:hover {
  350. bottom: 0;
  351. }
  352.  
  353. {* サムネのカットなくすやつ。 *}
  354. .list_item_cutout.mod_no_trim .thum img {
  355. display: none;
  356. }
  357.  
  358.  
  359. .list_item_cutout.mod_no_trim .thum {
  360. display: block;
  361. width: 100%;
  362. height: calc(100% - 40px);
  363. background-repeat: no-repeat;
  364. background-position: center center;
  365. background-size: contain;
  366. -moz-background-size: contain;
  367. -webkit-background-size: contain;
  368. -o-background-size: contain;
  369. -ms-background-size: contain;
  370. }
  371.  
  372. .list_item.mod_no_trim .thum img {
  373. display: none;
  374. }
  375.  
  376. .list_item.mod_no_trim .thum {
  377. display: block;
  378. width: 100%;
  379. height: 0;
  380. background-repeat: no-repeat;
  381. background-position: center center;
  382. background-size: contain;
  383. -moz-background-size: contain;
  384. -webkit-background-size: contain;
  385. -o-background-size: contain;
  386. -ms-background-size: contain;
  387. }
  388. .MOD_Seiga_View .list_item.mod_no_trim .thum {
  389. }
  390. .list_item.mod_no_trim .thum:hover, .list_item_cutout.mod_no_trim .thum:hover {
  391. background-size: cover;
  392. }
  393.  
  394. .MOD_Seiga_Top .list_item_cutout.mod_no_trim .thum {
  395. height: calc(100% - 50px);
  396. }
  397. .MOD_Seiga_Top .list_item_cutout.mod_no_trim a {
  398. height: 100%;
  399. width: 100%;
  400. }
  401. .MOD_Seiga_Top .list_item_cutout.mod_no_trim.large a .illust_info {
  402. bottom: 0px !important;
  403. background-color: rgba(60, 60, 60, 1);
  404. padding: 10px 40px;
  405. }
  406. .MOD_Seiga_Top .list_item_cutout.mod_no_trim.large {
  407. width: 190px;
  408. height: 190px;
  409. }
  410. .MOD_Seiga_Top .rank_box .item_list.mod_no_trim .more_link a {
  411. width: 190px;
  412. }
  413.  
  414. {* タグ検索時、カウンタなどが常時見えるように修正 *}
  415. .MOD_Seiga_TagSearch .list_item.large a .illust_count {
  416. opacity: 1;
  417. }
  418. .MOD_Seiga_TagSearch .list_item.large a {
  419. height: 321px;
  420. }
  421. .MOD_Seiga_TagSearch .list_item.large {
  422. height: 351px;
  423. }
  424.  
  425. {* タイトルと説明文・投稿者アイコンだけコンクリートの地面に置いてあるように感じたので絨毯を敷いた *}
  426. .MOD_Seiga .im_head_bar .inner {
  427. background-color: #FFFFFF;
  428. border-color: #E8E8E8;
  429. border-radius: 5px;
  430. border-style: solid;
  431. border-width: 0 0 1px;
  432. box-shadow: 0 0 15px rgba(0, 0, 0, 0.05);
  433. display: block;
  434. margin-top: 20px;
  435. {*margin-bottom: 20px;*}
  436. margin-left: auto;
  437. margin-right: auto;
  438. padding: 15px;
  439. position: relative;
  440. width: 974px;
  441. }
  442.  
  443.  
  444. {* タグの位置調整 *}
  445. .illust_main .mod_tag-top.illust_sub_info {
  446. padding-bottom: 25px;
  447. padding-top: 0;
  448. }
  449.  
  450.  
  451. .illust_sub_info.mod_tag-description-bottom {
  452. margin-top: 15px;
  453. }
  454. .im_head_bar .illust_tag h2 {
  455. float: left;
  456. font-size: 116.7%;
  457. line-height: 120%;
  458. margin: 4px 10px 0 -2px;
  459. overflow: hidden;
  460. }
  461. .im_head_bar .illust_sub_info input#tags {
  462. margin-bottom: 15px;
  463. margin-top: 5px;
  464. padding: 4px 10px;
  465. width: 280px;
  466. }
  467. .im_head_bar .illust_sub_info ul li.btn {
  468. bottom: 15px;
  469. position: absolute;
  470. right: 15px;
  471. }
  472.  
  473. {* タグ右上 *}
  474. .description.mod_tag-description-right {
  475. float: left;
  476. }
  477. .illust_sub_info.mod_tag-description-right {
  478. width: 300px;
  479. float: right;
  480. margin: 0;
  481. }
  482. .mod_tag-description-right .tag {
  483. background: none repeat scroll 0 0 rgba(0, 0, 0, 0);
  484. border: medium none;
  485. margin: 0;
  486. }
  487. .mod_tag-description-right .tag a {
  488. padding: 0 5px;
  489. }
  490. .mod_tag-description-right .tag li {
  491. }
  492. .mod_tag-description-right .tag li a {
  493. padding: 0 5px 0 0;
  494. border: 0;
  495. }
  496. .im_head_bar .illust_sub_info.mod_tag-description-right ul li.btn.active {
  497. }
  498. {* 右下だと被ることがあるので仕方なく *}
  499. .im_head_bar .illust_sub_info.mod_tag-description-right ul li.btn {
  500. display: inline-block;
  501. position: relative;
  502. bottom: auto; right: auto;
  503. }
  504.  
  505. #ichiba_box {
  506. width: 1004px;
  507. margin: 0 auto 20px;
  508. border: 1px solid #ddd;
  509. border-radius: 8px;
  510. }
  511.  
  512. #content.illust { padding: 0; }
  513.  
  514. #related_info .ad_tag { display: none;}
  515.  
  516. {* 右カラム広告のせいで無駄に横スクロールが発生しているのを修正 *}
  517. .related_info .sub_info_side {
  518. overflow-x: hidden;
  519. }
  520.  
  521.  
  522. .illust_main .illust_side .clip.mod_top {
  523. padding: 10px 10px 0;
  524. }
  525.  
  526.  
  527. .MOD_Seiga_FullView #content.illust_big .illust_view_big {
  528. margin: 0 auto;
  529. }
  530.  
  531. .MOD_Seiga_FullView .control {
  532. position: absolute;
  533. right: 0;
  534. top: 0;
  535. z-index: 1000;
  536. opacity: 0;
  537. transition: opacity 0.5s ease;
  538. }
  539.  
  540. .MOD_Seiga_FullView:hover .control {
  541. opacity: 1;
  542. }
  543.  
  544. .MOD_Seiga_FullView .illust_view_big img {
  545. {*transform: scale(1); -webkit-transform: scale(1);
  546. transition: transform 0.3s ease, -webkit-transform 0.3s ease;*}
  547. }
  548.  
  549. .MOD_Seiga_FullView:not(.mod_noScale) .illust_view_big img {
  550. position: absolute;
  551. top: 0;
  552. left: 0;
  553. transform-origin: 0 0 0;
  554. -webkit-transform-origin: 0 0 0;
  555. }
  556.  
  557. .MOD_Seiga_FullView.mod_contain {
  558. overflow: hidden;
  559. }
  560. .MOD_Seiga_FullView.mod_cover {
  561. }
  562. .MOD_Seiga_FullView.mod_contain .illust_view_big img,
  563. .MOD_Seiga_FullView.mod_cover .illust_view_big img {
  564. {*display: none;*}
  565. }
  566.  
  567. .MOD_Seiga_FullView .illust_view_big {
  568. background-repeat: no-repeat;
  569. background-position: center center;
  570. }
  571. .MOD_Seiga_FullView.mod_contain .illust_view_big {
  572. background-size: contain;
  573. }
  574. .MOD_Seiga_FullView.mod_cover .illust_view_big {
  575. background-size: cover;
  576. }
  577.  
  578. .MOD_Seiga .toggleFullScreen {
  579. display: block;
  580. width: 200px;
  581. margin: auto;
  582. transition: 0.4s opacity, 0.4s box-shadow;
  583. }
  584. .MOD_Seiga_FullView .toggleFullScreen {
  585. position: fixed;
  586. top: 0;
  587. left: 0;
  588. z-index: 1000;
  589. margin: 0;
  590. padding: 4px;
  591. cursor: pointer;
  592. border: none;
  593. background: transparent;
  594. color: #0CA5D2;
  595. font-weight: bolder;
  596. }
  597. .MOD_Seiga .toggleFullScreen:hover {
  598. box-shadow: 2px 2px 2px #333;
  599. }
  600.  
  601. .MOD_Seiga_FullView .toggleFullScreen button {
  602. opacity: 0;
  603. margin: 0;
  604. padding: 0;
  605. cursor: pointer;
  606. transition: 0.4s opacity, 0.4s box-shadow;
  607. border: 1px solid #000;
  608. background: #fff;
  609. color: #0CA5D2;
  610. font-weight: bolder;
  611. }
  612. .MOD_Seiga_FullView .toggleFullScreen.show button,
  613. .MOD_Seiga_FullView .toggleFullScreen button:hover {
  614. opacity: 1;
  615. box-shadow: 2px 2px 2px #333;
  616. }
  617. .MOD_Seiga_FullView:fullscreen .toggleFullScreen {
  618. display: none;
  619. }
  620.  
  621. #ko_watchlist_info.mod_hide { display: none !important; }
  622.  
  623. .fullScreenRequestFrame {
  624. position: fixed;
  625. width: 100px;
  626. height: 100px;
  627. left: -999px;
  628. top: -999px;
  629. }
  630.  
  631. .MOD_Seiga_FullView .closeButton {
  632. opacity: 0;
  633. transition: 0.4s opacity ease;
  634. }
  635.  
  636. .MOD_Seiga_FullView .closeButton:hover {
  637. opacity: 1;
  638. }
  639.  
  640. body.fullScreenFrame {
  641. background: #000;
  642. }
  643.  
  644. body.MOD_Seiga_FullView img {
  645. cursor: none;
  646. }
  647.  
  648. body.MOD_Seiga_FullView.mouseMoving img{
  649. cursor: default;
  650. }
  651.  
  652.  
  653. */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1].replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
  654.  
  655.  
  656. this.addStyle(__common_css__);
  657.  
  658. if (this.config.get('applyCss')) {
  659. this.addStyle(__css__);
  660. }
  661. },
  662. initializeUserConfig: function() {
  663. var prefix = 'MOD_Seiga_';
  664. var conf = {
  665. applyCss: true,
  666. topUserInfo: true,
  667. tagPosition: 'description-bottom',
  668. noTrim: true,
  669. hidePageTopButton: true,
  670. clipPosition: 'bottom',
  671. hideBottomUserInfo: false
  672. };
  673.  
  674. this.config = {
  675. get: function(key) {
  676. try {
  677. if (window.localStorage.hasOwnProperty(prefix + key)) {
  678. return JSON.parse(window.localStorage.getItem(prefix + key));
  679. }
  680. return conf[key];
  681. } catch (e) {
  682. return conf[key];
  683. }
  684. },
  685. set: function(key, value) {
  686. window.localStorage.setItem(prefix + key, JSON.stringify(value));
  687. }
  688. };
  689. },
  690. initializeBaseLayout: function() {
  691. var $description = $('#content .description, #content .discription').addClass('description');
  692. $('.controll').addClass('control');
  693.  
  694. $('#related_info').after($('#ichiba_box'));
  695.  
  696. if (this.config.get('hideBottomUserInfo') === true) {
  697. $('#ko_watchlist_info').addClass('mod_hide');
  698. }
  699.  
  700. },
  701. initializeScrollTop: function() {
  702. var $document = $(document), $body = $('body'); //, $bar = $('#bar');
  703.  
  704. var reset = this.resetScrollTop = function() {
  705. var nofix = $body.hasClass('nofix');
  706. var commonHeaderHeight = nofix ? 0 : 36; //$bar.outerHeight();
  707. $document.scrollTop(Math.max(
  708. $document.scrollTop(),
  709. $('#content .im_head_bar').offset().top -commonHeaderHeight
  710. ));
  711. };
  712. setTimeout(reset, 100);
  713. reset();
  714. },
  715. initializeDescription: function() {
  716. var $description = $('#content .description, #content .discription, .illust_user_exp');
  717. if ($description.length < 1) { return; }
  718. var html = $description.html();
  719.  
  720. // 説明文中のURLの自動リンク
  721. var linkmatch = /<a.*?<\/a>/, links = [], n;
  722. html = html.split('<br />').join(' <br /> ');
  723. while ((n = linkmatch.exec(html)) !== null) {
  724. links.push(n);
  725. html = html.replace(n, ' <!----> ');
  726. }
  727. html = html.replace(/(https?:\/\/[\x21-\x3b\x3d-\x7e]+)/gi, '<a href="$1" target="_blank" class="otherSite">$1</a>');
  728. for (var i = 0, len = links.length; i < len; i++) {
  729. html = html.replace(' <!----> ', links[i]);
  730. }
  731. html = html.split(' <br /> ').join('<br />');
  732.  
  733. var $desc = $('<div>' + html + '</div>');
  734. $description.empty().append($desc);
  735.  
  736. },
  737. initializeCommentLink: function() {
  738. var videoReg = /((sm|nm|so)\d+)/g;
  739. var seigaReg = /(im\d+)/g;
  740. var bookReg = /((bk|mg)\d+)/g;
  741. var urlReg = /(https?:\/\/[\x21-\x3b\x3d-\x7e]+)/gi;
  742.  
  743. var autoLink = function(text) {
  744. text = text
  745. .replace(videoReg, '<a href="//www.nicovideo.jp/watch/$1" class="video mod_link">$1</a>')
  746. .replace(seigaReg, '<a href="/seiga/$1" class="illust mod_link">$1</a>')
  747. .replace(bookReg, '<a href="/watch/$1" class="book mod_link">$1</a>')
  748. .replace(urlReg, '<a href="$1" target="_blank" class="otherSite mod_link">$1</a>');
  749. return text;
  750. };
  751. var commentLink = function(selector) {
  752. $(selector).each(function() {
  753. var $this = $(this);
  754. var html = $this.html(), linked = autoLink(html);
  755. if (html !== linked) {
  756. $this.html(linked);
  757. }
  758. $this.addClass('mod_linked');
  759. });
  760. };
  761.  
  762. setTimeout(function() {
  763. commentLink('#comment_list .comment_info .text:not(.mod_linked)');
  764. var updateTimer = null;
  765. document.body.addEventListener('DOMNodeInserted', function(e) {
  766. if (e.target.className && e.target.className.indexOf('comment_list_item') >= 0) {
  767. if (updateTimer) {
  768. updateTimer = clearTimeout(updateTimer);
  769. }
  770. updateTimer = setTimeout(function() {
  771. updateTimer = clearTimeout(updateTimer);
  772. commentLink('#comment_list .comment_info .text:not(.mod_linked)');
  773. //var $text = $(e.target).find('.text');
  774. //if (!$text.hasClass('mod_linked')) $text.html(autoLink($text.text())).addClass('mod_linked');
  775. }, 100);
  776. }
  777. });
  778.  
  779. }, 100);
  780. },
  781. initializeThumbnail: function() {
  782. if (this.config.get('noTrim') !== true) { return; }
  783.  
  784. var treg = /^(http:\/\/lohas.nicoseiga.jp\/+thumb\/+.\d+)([a-z\?]*)/;
  785. var noTrim = function() {
  786. $('.list_item_cutout, #main .list_item:not(.mod_no_trim)').each(function() {
  787. var $this = $(this);
  788. var $thum = $this.find('.thum');
  789. var $img = $thum.find('img');
  790. var src = $img.attr('src') || '';
  791. if ($thum.length * $img.length < 1 || !treg.test(src)) return;
  792. // TODO: 静画のサムネの種類を調べる
  793. var url = RegExp.$1 + 'q?';//RegExp.$2 === 't' ? src : RegExp.$1 + 'q?';
  794. $thum.css({'background-image': 'url("' + url + '")'});
  795. $this.addClass('mod_no_trim');
  796. });
  797. };
  798. noTrim();
  799. document.body.addEventListener('AutoPagerize_DOMNodeInserted', function() {
  800. setTimeout(function() {
  801. noTrim();
  802. }, 500);
  803. });
  804. },
  805. initializePageTopButton: function() {
  806. $('body').toggleClass('mod_hidePageTopButton', this.config.get('hidePageTopButton'));
  807. },
  808. initializeKnockout: function() {
  809. },
  810. initializeFullScreenRequest: function() {
  811. var $body = $('body');
  812. var $iframe = $('<iframe allowfullscreen="on" class="fullScreenRequestFrame" name="fullScreenRequestFrame"></iframe>');
  813.  
  814. $body.append($iframe);
  815.  
  816. var $fullScreenButton = $([
  817. '<button class="toggleFullScreen btn normal" title="フルスクリーン表示に切り換えます(Fキー)">',
  818. '<span>フルスクリーン</span>',
  819. '</button>',
  820. ''].join(''));
  821. $('.illust_main .illust_wrapper .inner .thum_large:first').append($fullScreenButton);
  822. var toggleFullScreen = $.proxy(function() {
  823. if (this.fullScreen.now()) {
  824. this.fullScreen.cancel();
  825. } else {
  826. $iframe[0].contentWindow.location.replace($('#illust_link').attr('href'));
  827. this.fullScreen.request($iframe[0]);
  828. }
  829. }, this);
  830. $fullScreenButton.on('click', function(e) {
  831. e.preventDefault();
  832. e.stopPropagation();
  833. toggleFullScreen();
  834. });
  835.  
  836. var onMessage = function(event) {
  837. if (event.origin.indexOf('nicoseiga.jp') < 0) return;
  838. try {
  839. var data = JSON.parse(event.data);
  840. if (data.id !== 'MOD_Seiga') { return; }
  841. if (data.command === 'toggleFullScreen') {
  842. toggleFullScreen();
  843. }
  844. } catch (e) {
  845. console.log('Exception', e);
  846. console.trace();
  847. }
  848. };
  849.  
  850. window.addEventListener('message', onMessage);
  851. $body.on('keydown.watchItLater', function(e) {
  852. if (e.target.tagName === 'SELECT' || e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
  853. return;
  854. }
  855. if (e.keyCode === 70) { // F
  856. toggleFullScreen();
  857. }
  858. });
  859.  
  860. },
  861. initializeOther: function() {
  862. $('body').addClass('MOD_Seiga');
  863. },
  864. initializeSettingPanel: function() {
  865. var $menu = $('<li class="MOD_SeigaSettingMenu"><a href="javascript:;" title="MOD_Seigaの設定変更">MOD_Seiga設定</a></li>');
  866. var $panel = $('<div id="MOD_SeigaSettingPanel" />');//.addClass('open');
  867. var $button = $('<button class="toggleSetting playerBottomButton">設定</botton>');
  868.  
  869. $button.on('click', function(e) {
  870. e.stopPropagation(); e.preventDefault();
  871. $panel.toggleClass('open');
  872. });
  873.  
  874. var config = this.config;
  875. $menu.find('a').on('click', function() { $panel.toggleClass('open'); });
  876.  
  877. var __tpl__ = (function() {/*
  878. <div class="panelHeader">
  879. <h1 class="windowTitle">MOD_Seigaの設定</h1>
  880. <p>設定はリロード後に反映されます</p>
  881. <button class="close" title="閉じる">×</button>
  882. </div>
  883. <div class="panelInner">
  884. <!--<div class="item" data-setting-name="topUserInfo" data-menu-type="radio">
  885. <h3 class="itemTitle">投稿者情報を右上に移動 </h3>
  886. <label><input type="radio" value="true" > する</label>
  887. <label><input type="radio" value="false"> しない</label>
  888. </div>-->
  889.  
  890. <div class="item" data-setting-name="noTrim" data-menu-type="radio">
  891. <h3 class="itemTitle">サムネイルの左右カットをやめる </h3>
  892. <label><input type="radio" value="true" >やめる</label>
  893. <label><input type="radio" value="false">やめない</label>
  894. </div>
  895.  
  896. <div class="item" data-setting-name="hidePageTopButton" data-menu-type="radio">
  897. <h3 class="itemTitle">ウィンドウ幅が狭いときはページトップに戻るボタンを隠す</h3>
  898. <label><input type="radio" value="true" >隠す</label>
  899. <label><input type="radio" value="false">隠さない</label>
  900. </div>
  901.  
  902. <div class="item" data-setting-name="hideBottomUserInfo" data-menu-type="radio">
  903. <h3 class="itemTitle">ページ下側の投稿者情報を隠す</h3>
  904. <small>右上だけでいい場合など</small><br>
  905. <label><input type="radio" value="true" >隠す</label>
  906. <label><input type="radio" value="false">隠さない</label>
  907. </div>
  908.  
  909. <div class="item" data-setting-name="clipPosition" data-menu-type="radio">
  910. <h3 class="itemTitle">クリップ登録メニューの位置(旧verのみ)</h3>
  911. <label><input type="radio" value="&quot;top&quot;" >上</label>
  912. <label><input type="radio" value="&quot;bottom&quot;">下</label>
  913. </div>
  914. <!--
  915. <div class="item" data-setting-name="tagPosition" data-menu-type="radio">
  916. <h3 class="itemTitle">タグの位置(旧verのみ) </h3>
  917. <label><input type="radio" value="&quot;description-bottom&quot;">説明文の下</label>
  918. <label><input type="radio" value="&quot;description-right&quot;">説明文の右</label>
  919. <label><input type="radio" value="&quot;top&quot;">画像の上</label>
  920. <label><input type="radio" value="&quot;default&quot;">画像の下(標準)</label>
  921. </div>
  922. -->
  923.  
  924. <div class="expert">
  925. <h2>上級者向け設定</h2>
  926. </div>
  927. <div class="item" data-setting-name="applyCss" data-menu-type="radio">
  928. <h3 class="itemTitle">MOD_Seiga標準のCSSを使用する</h3>
  929. <small>他のuserstyleを使用する場合は「しない」を選択してください</small><br>
  930. <label><input type="radio" value="true" > する</label>
  931. <label><input type="radio" value="false"> しない</label>
  932. </div>
  933. </div>
  934. */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1].replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
  935. $panel.html(__tpl__);
  936. $panel.find('.item').on('click', function(e) {
  937. var $this = $(this);
  938. var settingName = $this.attr('data-setting-name');
  939. var value = JSON.parse($this.find('input:checked').val());
  940. console.log('seting-name', settingName, 'value', value);
  941. config.set(settingName, value);
  942. }).each(function(e) {
  943. var $this = $(this);
  944. var settingName = $this.attr('data-setting-name');
  945. var value = config.get(settingName);
  946. $this.addClass(settingName);
  947. $this.find('input').attr('name', settingName).val([JSON.stringify(value)]);
  948. });
  949. $panel.find('.close').click(function() {
  950. $panel.removeClass('open');
  951. });
  952.  
  953.  
  954. $('#siteHeaderRightMenuFix').after($menu);
  955. $('body').append($panel);
  956. },
  957. initializeFullscreenImage: function() {
  958. var $body = $('body'), $container = $('.illust_view_big'), $img = $container.find('img'), scale = 1;
  959. var $fullScreenButton = $([
  960. '<div class="toggleFullScreen show">',
  961. '<button title="フルスクリーン表示に切り換えます">',
  962. '<span>フルスクリーン</span>',
  963. '</button>',
  964. '</div>',
  965. ''].join(''));
  966. var $window = $(window);
  967. $('.controll').addClass('control');
  968.  
  969. var clearCss = function() {
  970. $body.removeClass('mod_contain mod_cover mod_noScale');
  971. $container.css({width: '', height: ''});
  972. $img.css({'transform': '', '-webkit-transform': '', top: '', left: ''});
  973. };
  974.  
  975. // ウィンドウの内枠フィット (画面におさまる範囲で最大化)
  976. var contain = function() {
  977. clearCss();
  978. $body.addClass('mod_contain');
  979. scale = Math.min(
  980. $window.innerWidth() / $img.outerWidth(),
  981. $window.innerHeight() / $img.outerHeight()
  982. );
  983. scale = Math.min(scale, 10);
  984. $img.css({
  985. 'transform': 'scale(' + scale + ')',
  986. '-webkit-transform': 'scale(' + scale + ')',
  987. 'left': ($window.innerWidth() - $img.outerWidth() * scale) / 2 + 'px',
  988. 'top': ($window.innerHeight() - $img.outerHeight() * scale) / 2 + 'px'
  989. });
  990. $container.width($window.innerWidth());
  991. $container.height($window.innerHeight());
  992. // $container.css('background-image', 'url("' + $img.attr('src') + '")');
  993. };
  994.  
  995. // ウィンドウの外枠フィット
  996. var cover = function() {
  997. clearCss();
  998. $body.addClass('mod_cover').css('overflow', 'scroll');
  999. scale = Math.max(
  1000. $window.innerWidth() / $img.outerWidth(),
  1001. $window.innerHeight() / $img.outerHeight()
  1002. );
  1003. scale = Math.min(scale, 10);
  1004. $img.css({
  1005. 'transform': 'scale(' + scale + ')',
  1006. '-webkit-transform': 'scale(' + scale + ')',
  1007. });
  1008. // ウィンドウサイズの計算にスクロールバーの幅を含めるための措置 おもにwindows用
  1009. $body.css('overflow', '');
  1010. };
  1011.  
  1012. // 原寸大表示
  1013. var noScale = function() {
  1014. clearCss();
  1015. $body.addClass('mod_noScale');
  1016. scale = 1;
  1017. $container.css('background-image', '');
  1018. };
  1019.  
  1020. // クリックごとに表示を切り替える処理
  1021. var onClick = function(e) {
  1022. if (e.button > 0) { return; }
  1023. // TODO: クリックした位置が中心になるようにスクロール
  1024. if ($body.hasClass('mod_noScale')) {
  1025. contain();
  1026. } else
  1027. if ($body.hasClass('mod_contain')) {
  1028. cover();
  1029. } else {
  1030. noScale();
  1031. }
  1032. };
  1033. // ウィンドウがリサイズされた時などの再計算用
  1034. var update = function() {
  1035. if ($body.hasClass('mod_contain')) {
  1036. contain();
  1037. } else
  1038. if ($body.hasClass('mod_cover')) {
  1039. cover();
  1040. }
  1041. };
  1042.  
  1043. // モニターいっぱい表示を切り換える
  1044. var toggleFullScreen = $.proxy(function() {
  1045. if (window.name === 'fullScreenRequestFrame') {
  1046. parent.postMessage(JSON.stringify({
  1047. id: 'MOD_Seiga',
  1048. command: 'toggleFullScreen'
  1049. }),
  1050. 'http://seiga.nicovideo.jp');
  1051. return;
  1052. }
  1053.  
  1054. if (this.fullScreen.now()) {
  1055. this.fullScreen.cancel(document.documentElement);
  1056. } else {
  1057. this.fullScreen.request(document.documentElement);
  1058. }
  1059. }, this);
  1060.  
  1061. window.setTimeout($.proxy(function() {
  1062. $fullScreenButton.removeClass('show');
  1063. }, this), 2000);
  1064.  
  1065. // /seiga/imXXXXXXからiframeで呼ばれてる時の処理
  1066. if (window.name === 'fullScreenRequestFrame') {
  1067. $('img[src$="btn_close.png"]')
  1068. .addClass('closeButton')
  1069. .off()
  1070. .on('click', function() {
  1071. toggleFullScreen();
  1072. });
  1073. $('body').addClass('fullScreenFrame');
  1074. }
  1075.  
  1076. $fullScreenButton.on('click', function(e) {
  1077. e.preventDefault();
  1078. e.stopPropagation();
  1079. toggleFullScreen();
  1080. });
  1081. $body.append($fullScreenButton);
  1082.  
  1083.  
  1084. // マウスを動かさない時はカーソルを消す
  1085. var mousemoveStopTimer = null;
  1086. var showMouseNsec = function() {
  1087. $body.addClass('mouseMoving');
  1088. if (mousemoveStopTimer) {
  1089. window.clearTimeout(mousemoveStopTimer);
  1090. mousemoveStopTimer = null;
  1091. }
  1092. mousemoveStopTimer = window.setTimeout(function() {
  1093. $body.removeClass('mouseMoving');
  1094. mousemoveStopTimer = null;
  1095. }, 1000);
  1096. };
  1097. $body
  1098. .on('mousemove.MOD_Seiga', showMouseNsec)
  1099. .on('mousedown.MOD_Seiga', showMouseNsec);
  1100.  
  1101.  
  1102. contain();
  1103. $img.on('click', onClick);
  1104. $window.on('resize', update);
  1105. var onImageLoad = $.proxy(function() {
  1106. this.initializePrintCss($img.clone());
  1107. contain();
  1108. $img.off('load.MOD_Seiga');
  1109. }, this);
  1110.  
  1111. if ($img[0] && $img[0].complete) {
  1112. onImageLoad();
  1113. } else {
  1114. $img.on('load.MOD_Seiga', onImageLoad);
  1115. }
  1116.  
  1117.  
  1118. // おもにwindows等、縦ホイールしかない環境で横スクロールしやすくする
  1119. // Firefoxでうまくいかない
  1120. var hasWheelDeltaX = false;
  1121. $(document).on('mousewheel', function(e) {
  1122. var delta = 0;
  1123.  
  1124. if ($body.hasClass('mod_contain')) { return; }
  1125.  
  1126. if (document.body.scrollHeight > window.innerHeight) { return; }
  1127.  
  1128. if (hasWheelDeltaX) { return; }
  1129.  
  1130. if (!e.originalEvent) { return; }
  1131. var oe = e.originalEvent;
  1132.  
  1133. if (typeof oe.wheelDelta === 'number') {
  1134. if (typeof oe.wheelDeltaX === 'number' && oe.wheelDeltaX !== 0) {
  1135. hasWheelDeltaX = true;
  1136. return; // ホイールで横スクロールできる環境だとかえって邪魔なのでなにもしない
  1137. }
  1138.  
  1139. delta = e.originalEvent.wheelDelta / Math.abs(e.originalEvent.wheelDelta);
  1140. }
  1141. if (delta === 0) return;
  1142.  
  1143. e.preventDefault();
  1144. e.stopPropagation();
  1145.  
  1146. var scrollLeft = $body.scrollLeft() - (delta * $window.innerWidth() / 10);
  1147. $body.scrollLeft(Math.max(scrollLeft, 0));
  1148. });
  1149. },
  1150. initializePrintCss: function($img) {
  1151. this.initializePrintCss = function() {};
  1152. var self = this;
  1153.  
  1154. $img.css({
  1155. width: 'auto', height: 'auto',
  1156. transform: '', left: '100%', top: '100%', opacity: 0, position: 'fixed'
  1157. });
  1158.  
  1159. var $body = $('body');
  1160. $body.append($img);
  1161.  
  1162. window.setTimeout(function() {
  1163. var width = $img.outerWidth(), height = $img.outerHeight();
  1164. $img.remove();
  1165.  
  1166. // TODO: 用紙サイズ変更
  1167. var paperMarginV = 0; //0.1; // 19; // 紙送りマージン?
  1168. var imageRatio = height / Math.max(width, 1);
  1169. var paperRatio = (A4_HEIGHT - paperMarginV) / A4_WIDTH;
  1170. var landscapeRatio = (A4_WIDTH - paperMarginV) / A4_HEIGHT;
  1171. var isLandscape =
  1172. Math.abs(paperRatio - imageRatio) > Math.abs(landscapeRatio - imageRatio);
  1173.  
  1174. paperRatio = isLandscape ? landscapeRatio : paperRatio;
  1175.  
  1176. var isFitV = paperRatio < imageRatio;
  1177. var paperWidth = isLandscape ? A4_HEIGHT : A4_WIDTH;
  1178. var paperHeight = (isLandscape ? A4_WIDTH : A4_HEIGHT) - paperMarginV;
  1179. var marginLeft = 0, marginTop = 0, imageWidth = paperWidth, imageHeight = paperHeight;
  1180.  
  1181. if (isFitV) { // タテ合わせ
  1182. imageWidth = paperHeight / imageRatio;
  1183. marginLeft = (paperWidth - imageWidth) / 2;
  1184. } else { // ヨコ合わせ
  1185. imageHeight = paperWidth * imageRatio;
  1186. marginTop = (paperHeight - imageHeight) / 2;
  1187. }
  1188. var pageSize = isLandscape ? 'A4 lanscape' : 'A4';
  1189. var css = [
  1190. '@page { margin: 0; size: ', pageSize, '; }\n\n ',
  1191. '@media print {\n',
  1192. '\t.MOD_Seiga_FullView .illust_view_big img {\n ',
  1193. '\t\tmargin-left: ', marginLeft, 'mm; ',
  1194. '\t\tmargin-top: ', marginTop, 'mm; ',
  1195. '\t\twidth:', imageWidth, 'mm !important; ',
  1196. '\t\theight:', imageHeight, 'mm !important;',
  1197. '\t\n}\n',
  1198. '}',
  1199. ].join('');
  1200.  
  1201. //console.log('paper?', paperWidth, paperHeight, imageWidth, imageHeight);
  1202. //console.log('ratio?', width, height, isLandscape, paperRatio, imageRatio);
  1203. console.log('print css\n', css);
  1204.  
  1205. self._printCss = self.addStyle(css, 'MOD_Seiga_print');
  1206. $body
  1207. .toggleClass('landscape', isLandscape)
  1208. .toggleClass('fitV', isFitV);
  1209. }, 100);
  1210. }
  1211. };
  1212.  
  1213. window.MOD_Seiga.initialize();
  1214.  
  1215. });
  1216.  
  1217. var script = document.createElement("script");
  1218. script.id = "MOD_SeigaLoader";
  1219. script.setAttribute("type", "text/javascript");
  1220. script.setAttribute("charset", "UTF-8");
  1221. script.appendChild(document.createTextNode("(" + monkey + ")()"));
  1222. document.body.appendChild(script);
  1223.  
  1224. })();