縦にスクロールするタイプのみ
IDが表示されないので、作っている最中から誰得だなと感じていたが
とりあえず、形になったのでバックアップも兼ねて
もう、この時点でやりたかったことをやり切ったような雰囲気が出てきている…
現時点で、統一感がない部分(特に関数のreturnや条件分岐の書き方とか)は反省点
// ==UserScript== // @name NicoNicoSeiga(manga)Helper // @namespace http://dummy.ne.jp/ // @description ニコニコ静画(漫画)スクロールタイプ拡張機能 // @include http://seiga.nicovideo.jp/watch* // @include https://seiga.nicovideo.jp/watch* // @version 0.0.1 // @grant none // ==/UserScript== /////////////////////////////////////////////////////////////////// /* global */ ngstyle = document.createElement('style'); ngstyle.type = 'text/css'; ngstyle.id = 'NNSH_ngstyle'; var _CONTROLS = { type: 'new', style: 'comment_list', list: 'li', top: 300, left: 600 }; /////////////////////////////////////////////////////////////////// // define NNSH_NG_Hidden = 'NNSH_NG_Hidden'; NNSH_NG_None = 'NNSH_NG_None'; NNSH_NG_Stop = 'NNSH_NG_Stop'; /////////////////////////////////////////////////////////////////// // prototype if (!String.prototype.trim) { String.prototype.trim = function () { return this.toString().replace(/^\s+|\s+$/g, ''); }; } /////////////////////////////////////////////////////////////////// /* initializer */ var NNSH_init = (function () { if (window != parent) { return; } var head = document.getElementsByTagName('head') [0]; if (head) { head.appendChild(ngstyle); } NNSH_NGStyleUpdate(); try { //IE9+, Other Browsers window.addEventListener('load', NNSH_load, false); //window.addEventListener('scroll', NNSH_getRunComment, false); } catch (e) { //for IE8- window.attachEvent('onload', NNSH_load, false); //window.attachEvent('onscroll', NNSH_getRunComment); } $(function () { $('li[id^=comment_row]').bind('contextmenu', function () { $(this).text('右クリックされました!!'); $(this).css({ background: '#fed9c2', border: 'solid 3px #fb5901' }); return false; }); }); }) (); function NNSH_load() { if (!document.getElementById('ko_controls')) { _CONTROLS.type = 'old'; _CONTROLS.style = 'controls'; _CONTROLS.list = 'tr'; } else { _CONTROLS.type = 'new'; _CONTROLS.style = 'inner'; _CONTROLS.list = 'li'; } NNSH_getCommentID(); NNSH_addOptionButton(); } /////////////////////////////////////////////////////////////////// /* option screen */ /////////////////////// // add option button function NNSH_addOptionButton() { try { var setbtn = document.getElementById('setting_button'); var btn = setbtn.cloneNode(true); btn.id = 'NNSH_option_button'; btn.innerHTML = 'NG'; btn.title = 'NG設定を表示します'; btn.onclick = NNSH_openOption; setbtn.parentNode.insertBefore(btn, setbtn); } catch (e) { console.log(e); } } function NNSH_openOption() { var opt = document.getElementById('NNSH_NG_Option'); var cl = document.getElementById('comment_list'); if (!cl) cl = document.getElementById('comment_viewer'); try { if (!opt) { opt = document.createElement('div'); opt.id = 'NNSH_NG_Option' opt.className = _CONTROLS.style; opt.style.left = cl.style.top; opt.style.position = 'fixed'; opt.style.zIndex = '101'; //close button var bclose = document.createElement('span'); bclose.title = 'NG設定を閉じます'; bclose.id = 'NNSH_NG_Close'; bclose.className = 'icon_ad_close'; bclose.style.cssFloat = 'right'; bclose.style.fontSize = '20px'; bclose.style.cursor = 'pointer'; var tnode = document.createTextNode(' [ × ] '); bclose.appendChild(tnode); bclose.onclick = NNSH_closeOption; //description label var lbNG = document.createElement('label'); lbNG.innerHTML = '↓NGワードを入力して下さい(部分一致):'; //textarea var taNG = document.createElement('textarea'); var optcss = (opt.currentStyle || document.defaultView.getComputedStyle(opt, '')); taNG.id = 'NNSH_NG_TA'; taNG.title = 'NGワードは改行で区切って複数指定できます。'; taNG.style.width = optcss.width; taNG.style.height = '220px'; taNG.value = NNSH_getlist() + '\n'; //save button var ibSave = document.createElement('input'); ibSave.id = 'NNSH_NG_Save'; ibSave.type = 'button'; ibSave.value = '保存'; ibSave.title = 'NG保存ワードを保存します'; ibSave.onclick = NNSH_Save; //choeckbox var ulCBset = document.createElement('ul'); var liCBset = document.createElement('li'); var cbNG_w = document.createElement('input'); cbNG_w.style.setProperty('margin', '0px', 'important'); cbNG_w.type = 'checkbox'; var cbNG_n = cbNG_w.cloneNode(true); var cbNG_s = cbNG_w.cloneNode(true); cbNG_w.id = NNSH_NG_Hidden; cbNG_n.id = NNSH_NG_None; cbNG_s.id = NNSH_NG_Stop; var lbNG_w = lbNG.cloneNode(true); var lbNG_n = lbNG.cloneNode(true); var lbNG_s = lbNG.cloneNode(true); lbNG_w.innerHTML = 'NGコメント:背景と同じ色にする'; lbNG_n.innerHTML = 'NGコメント:行を非表示にする'; lbNG_s.innerHTML = 'NGコメント機能を停止する'; var nSet = [ { cb: cbNG_w, lb: lbNG_w }, { cb: cbNG_n, lb: lbNG_n }, { cb: cbNG_s, lb: lbNG_s } ]; //console.log(nSet.length); var c_id = getValue('NNSH_NG_TYPE', NNSH_NG_Hidden); for (var i = 0; i < nSet.length; i++) { var li = liCBset.cloneNode(true); nSet[i]['cb'].addEventListener('click', NNSH_cbSetClick, false); if (nSet[i]['cb'].id == c_id) nSet[i]['cb'].checked = true; li.appendChild(nSet[i]['cb']); li.appendChild(nSet[i]['lb']); ulCBset.appendChild(li); } //append opt.appendChild(bclose); opt.appendChild(lbNG); opt.appendChild(taNG); opt.appendChild(ulCBset); opt.appendChild(ibSave); cl.parentNode.insertBefore(opt, cl); return; } } catch (e) { console.log(e); } //console.log(opt.innerHTML); NNSH_closeOption(); } //checkbox toggle function NNSH_cbSetClick() { var me = this; //console.log('cbSetClick.this : ' + me); switch (me.id) { case NNSH_NG_Hidden: var n = document.getElementById(NNSH_NG_None); var s = document.getElementById(NNSH_NG_Stop); n.checked = false; s.checked = false; break; case NNSH_NG_None: var h = document.getElementById(NNSH_NG_Hidden); var s = document.getElementById(NNSH_NG_Stop); h.checked = false; s.checked = false; break; case NNSH_NG_Stop: var h = document.getElementById(NNSH_NG_Hidden); var n = document.getElementById(NNSH_NG_None); h.checked = false; n.checked = false; break; } } function NNSH_closeOption() { var opt = document.getElementById('NNSH_NG_Option'); if (!opt) { return; } opt.remove(); } function NNSH_Save() { var ta = document.getElementById('NNSH_NG_TA'); setValue('NNSH_NG_TYPE', NNSH_check_toggle()); var ctrl = document.getElementById('NNSH_NG_Option'); getElemAbsolutePosition(ctrl); if (ta.value.replace(/\n$/, '').trim().length > 0) { var sd = NNSH_escapeHTML(ta.value).replace(/\n$/, '').trim().split('\n').join(','); //console.log(sd); setValue('NNSH_NGLIST', sd); NNSH_NGStyleUpdate(); NNSH_getCommentID(); //console.log('left:' + _CONTROLS.left + ' top:' + _CONTROLS.top); NNSH_resultTip('保存しました', _CONTROLS.left, _CONTROLS.top); } else { NNSH_resultTip('NGワードが空です', _CONTROLS.left, _CONTROLS.top); } } function NNSH_check_toggle() { var w = document.getElementById(NNSH_NG_Hidden); var n = document.getElementById(NNSH_NG_None); var s = document.getElementById(NNSH_NG_Stop); var c_id = NNSH_NG_Hidden; try { if (w.checked) c_id = w.id; if (n.checked) c_id = n.id; if (s.checked) c_id = s.id; } catch (e) { console.log(e); } //console.log('checked : ' + c_id); return c_id; } /////////////////////////////////////////////////////////////////// /* escape */ // HTMLエスケープ function NNSH_escapeHTML(str) { return str.replace(/[&"<>,']/g, function (c) { //console.log('esc:' + c); return { '&': '&', '"': '"', '<': '<', '>': '>', ',': ',', '\'': ''' } [ c ]; }); } // 特殊記号エスケープ function NNSH_escapeEx(str) { var tmp = str.replace('\\', '\\\\'); tmp = tmp.replace('\'', '\\\''); tmp = tmp.replace('"', '\\"'); return tmp; } /////////////////////////////////////////////////////////////////// /* decode */ function NNSH_decodeHTML(str) { return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '\'').replace(/,/g, ',').replace(/&/g, '&'); } /////////////////////////////////////////////////////////////////// // NG list function NNSH_getlist() { var tmp; var data = getValue('NNSH_NGLIST'); //console.log(data); if (typeof data == 'undefined') { data = ''; } if (data == '') { //console.log('NNSH_getlist no data'); tmp = data; } else { data = data.split(','); tmp = data; //console.log('NNSH_getlist exist data : ' + data + '(' + typeof data + ')'); for (var j = 0; j < data.length; j++) { tmp[j] = NNSH_decodeHTML(data[j]); } //console.log('escaped : ' + tmp); tmp = tmp.join('\n'); } return tmp; } /////////////////////////////////////////////////////////////////// /* NGComment Style */ // make / update function NNSH_NGStyleUpdate() { var tstyle = ''; var nglist = NNSH_getlist(); //console.log('update:\'' + nglist + '\':_len : ' + nglist.lenght); if (typeof nglist.length == 'undefined') { return; } if (nglist.indexOf('\n') > - 1) nglist = nglist.split('\n'); // style初期化 ngstyle.innerHTML = ''; // NG判定 var NG_TYPE = getValue('NNSH_NG_TYPE', NNSH_NG_Hidden); if (NG_TYPE == NNSH_NG_Stop) return; //console.log('NNSH_NGStyleUpdate : ' + nglist + '(' + typeof nglist + ')'); var tmp = [ ]; (typeof nglist == 'string') ? tmp[0] = nglist : tmp = nglist; for (var n = 0; n < tmp.length; n++) { // 今は部分一致 正規表現を使う場合はここで判定して分岐 tstyle += 'div[title*="' + NNSH_escapeEx(tmp[n]) + '"]{ display:none !important; }\n'; } if (tstyle.length > 0) { var nodes = document.createTextNode(tstyle); ngstyle.appendChild(nodes); //console.log(ngstyle.parentNode.innerHTML); } } /////////////////////////////////////////////////////////////////// /* Get Commentlist & Add NG Style */ function NNSH_getCommentID() { var cl = document.getElementById('comment_list'); if (!cl) cl = document.getElementById('comment_viewer'); //comment_list add NG_STYLE var NG_TYPE = getValue('NNSH_NG_TYPE', NNSH_NG_Hidden); var tr = cl.getElementsByTagName(_CONTROLS.list); for (var i = 0; i < tr.length; i++) { var ti = tr[i]; var cid = ti.id.replace('_row', ''); //console.log('"' + cid + '",' + i + '/' + tr.length); if (!cid) continue; var cin = ti.getElementsByClassName('comment'); //console.log('cin:' + cin.length); try { if (cin[0].style.removeProperty) cin[0].style.removeProperty('color'); if (ti.style.removeProperty) ti.style.removeProperty('display'); if (cin[0].style.removeAttribute) cin[0].style.removeAttribute('color'); if (ti.style.removeAttribute) ti.style.removeAttribute('display'); } catch (e) { /*何もしない*/ } if (NG_TYPE == NNSH_NG_Stop) continue; if (NNSH_IsNG(cin[0].innerHTML)) { if (NG_TYPE == NNSH_NG_Hidden) cin[0].style.color = '#ffffff'; if (NG_TYPE == NNSH_NG_None) ti.style.display = 'none'; } } } // Check NG comment function NNSH_IsNG(com) { //console.log(com); // list初期化 var nglist = NNSH_getlist(); //console.log('NNSH_IsNG : ' + nglist.length); if (nglist.length <= 0) { return false; } if (nglist.indexOf('\n') >= - 1) nglist = nglist.split('\n'); if (com.length > 0) { for (var n = 0; n < nglist.length; n++) { if (com.indexOf(nglist[n]) > - 1) { //console.log('hit'); return true; } } } //console.log('nohit'); return false; } /////////////////////////////////////////////////////////////////// // scroll get comment (DEBUG) function NNSH_getRunComment() { var nobr = document.getElementsByTagName('nobr'); function NNSH_readProperty(obj) { var prop = [ ]; for (var o in obj) { prop = prop.concat(o); } console.log(prop); } for (var i = 0; i < nobr.length; i++) { var n = nobr[i]; if (n.className == 'bpn_price') { continue; } var ni = n.innerHTML; if (ni.length > 0) { if (ni.indexOf('コメント') < 0 && ni.indexOf('ページ') < 0) { console.log('NNSH_getRunComment:' + n.parentNode.tagName + '#' + n.parentNode.id + '.' + n.tagName + '.' + n.className + ':' + n.innerHTML ); //console.log(n.parentNode.tagName + " title:" + n.parentNode.title); //NNSH_readProperty(n); } } } } /////////////////////////////////////////////////////////////////// /* IO */ //====================================================== //set //------------------------------------------------------ function setValue(key, data) { if (window.JSON == false) { alert('Your Web Browser is not supported JSON.'); return; } if (key != null && data != null) localStorage.setItem(key, data); } //====================================================== //get //------------------------------------------------------ function getValue(key, defValue) { var data = ''; if (window.JSON == false) { alert('Your Web Browser is not supported JSON.'); return data; } data = localStorage.getItem(key); if (data == null) (typeof defValue == 'undefined') ? data = '' : data = defValue; //alert(data); return data; } //====================================================== //result //------------------------------------------------------ function NNSH_resultTip(str, x, y) { //------------------------------------------------------------- //console.log('resultTip start'); //------------------------------------------------------------- var sc_x; var sc_y; var tip = document.getElementById('resultTip'); //------------------------------------------------------------- //console.log(' getElement ok'); //------------------------------------------------------------- (typeof x == 'undefined') ? sc_x = 50 : sc_x = x; (typeof y == 'undefined') ? sc_y = 380 : sc_y = y; //------------------------------------------------------------- //console.log(' position x:' + sc_x + ', y:' + sc_y + ' set ok'); //------------------------------------------------------------- if (!tip) { tip = document.createElement('div'); //console.log(' create ok'); tip.id = 'resultTip'; tip.className = 'tooltip-content'; document.body.appendChild(tip); } tip.innerHTML = str; //------------------------------------------------------------- //console.log(' append node ok'); //------------------------------------------------------------- tip.style.left = sc_x + 'px'; tip.style.top = sc_y + 'px'; tip.style.position = 'fixed'; tip.style.zIndex = 1001; tip.style.backgroundColor = '#ffffe1'; tip.style.border = '1px black solid'; tip.style.padding = '2px'; tip.style.width = '150px'; //------------------------------------------------------------- //console.log(' set style ok'); //------------------------------------------------------------- setTimeout(function tip_remove() { tip.remove(); //console.log('tip_remove ok'); }, 3000); //------------------------------------------------------------- //console.log('resultTip end'); //------------------------------------------------------------- } function getElemAbsolutePosition(ctrl) { try { var rect = (function (elem) { var html = document.documentElement; var rect = elem.getBoundingClientRect(); var left = rect.left - html.clientLeft; var top = rect.top - html.clientTop; return { left: left, top: top }; }) (this.ctrl); _CONTROLS.top = rect.top; _CONTROLS.left = rect.left; } catch (e) { console.log(e); } }
我ながらきったねえコードだ…
これからの課題
- prototypeで疑似クラス化
- 無駄がありそうな処理を修正
- グローバルになっているもの → メンバ変数
、クロージャに変更 とかも
参考:クラスの落とし穴2 - メソッドとクロージャ - Qiita
- グローバルになっているもの → メンバ変数
- 各部品のスタイルをcssに任せるか?
- 問題がすべて解決したらログ出力行をコメントアウト
元々、VB(6.0)や、VBA くらいしか触ってこなかったわけで
クラスらしいクラスを組んだことがないので、ここから未知の領域
動かなくなったら嫌だなあ