honjarake blog

自分用にテキトーにまとめる

ニコニコ動画概要から動画リンクだけ抽出して表示するスクリプト

ノートPC買おう…

前回のスクリプトと同時進行で作っていたモノ(暫定

これからの課題

  • windowのresize(拡大縮小を交互に速めに行う)で動画プレイヤーが右にずれていく問題
    • 現時点で、ブラウザの全画面表示、サイズ変更でリセットされるのを確認
      最悪、ツールチップやメッセージでその旨を表示して対応
  • 疑似クラス化
    • 今は困難。一個、一から作って試す必要あり。
  • 次の動画、前の動画の表示が実際のpart数と異なるパターンが存在する
    • 動画が修正版や再アップの場合は正確に取得できない('/watch/sm数字'の数字部分の大小だけで表示する動画を決定している為)
      動画説明の動画すべて載せるように修正した方が早い

以下、ソースコード

続きを読む

ウィンドウサイズを変えたとき

[jQuery] ウインドウのリサイズ操作が終わった時にだけ処理を実行する | CreativeStyle

この前、$(window).resize に body内に追加した要素のtopを変更する処理を追加したら画面が大幅に崩れたんだけど
ついでにこれを入れてみようと思う

top位置変えてるだけなんだけどなあ
もしかしたら、サイトのcssの問題かもしれないのでそっちも調査

ソースあったのではっつけ

var resizeDisp = (function () {
  try {
    $(window).resize(function () {
      var list = document.getElementById('scroll_parts');
      var wih = window.innerHeight - (list.clientHeight + 30);
      list.style.top = wih + 'px';
    });
  } catch (e) {
    console.log('resizeDisp:' + e);
  }
}) ();

↓こんな感じか

var resizeDisp = (function () {
  try {
    var timer = false;
    $(window).resize(function () {
      if (timer !== false) {
        clearTimeout(timer);
      }
      timer = setTimeout(function () {
        var list = document.getElementById('scroll_parts');
        var wih = window.innerHeight - (list.clientHeight + 30);
        list.style.top = wih + 'px';
      }, 200);
    });
  } catch (e) {
    console.log('resizeDisp:' + e);
  }
}) ();

iframe.contentDocument.location.replace

インラインフレーム(iframe)の参照(src)を書き換えるとブラウザの履歴に残る

iframe.src = url;

同じページ内のiframeにサムネを表示するスクリプトを作ったときに発覚
(iframe表示しているページが履歴に何個も残っていた)

解決方法

iframeのlocationをreplaceで変更する
【(location.replace(replace_path)でページ移動すると実行したページが履歴に残らない】

$('#N2GNV_list a').hover(function () {
    var iframe = document.getElementById('target');
    var src = 'http://target.co.jp/' + tail;
    //履歴残さない
    iframe.contentDocument.location.replace(src);
    }
    samne.style.display = 'block';
  }, function () {
    samne.style.display = 'none';
  }
);

だが、しかし!
これだとhover一回目は正常に処理されるのに、hover二回目にエラーが発生してしまった

エラー:「iframe.contentDocument が null」

…なんでだ?
(ちなみにこのとき、iframe 自体は null じゃありませんでした)
どういうこと?

解決方法
$('#N2GNV_list a').hover(function () {
    var iframe = document.getElementById('target');
    <~省略~>
    if (iframe.contentDocument == null) {
      var iframed = (iframe.contentWindow || iframe.contentDocument);
      iframed.location.replace(src);
    } else {
      iframe.contentDocument.location.replace(src);
    }
    samne.style.display = 'block';
  }, function () {
    samne.style.display = 'none';
  }
);

※if文はデバッグの名残

var iframed = (iframe.contentWindow || iframe.contentDocument);
iframed.location.replace(src);

こうすれば問題なく動いたがよくわからない

追記

本来はクロスブラウザ用の対策なんだと思う…
関係ありそうなページ?
local MDC: chrome コードでウィンドウを取り扱う (/ja/working_with_windows_in_chrome_code)

そのドキュメントには browser.contentDocument を、そのドキュメントの Window オブジェクトには browser.contentWindow を使ってアクセスできます。

二回目のresizeではドキュメントを参照できず、ウィンドウオブジェクトを参照しないといけないのか?
※環境:firefox 32.0 greasemonkey2.2

はてブ整理 増田まとめ ~9/20

圧迫してくるといやなので
http://b.hatena.ne.jp/entry/excel-databace.hatenablog.com/entry/2014/09/04/094049 かなり不快だ..
「手に職」って詐欺みたいなもんなんだな
ぜんぶかいてみた

カテゴリはなんだろう?

ニコニコ静画(漫画)にNGワード設定機能を付与するgreasemonkeyスクリプト

縦にスクロールするタイプのみ
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 {
      '&': '&amp;',
      '"': '&quot;',
      '<': '&lt;',
      '>': '&gt;',
      ',': '&#044;',
      '\'': '&#039;'
    }
    [
      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(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#039;/g, '\'').replace(/&#044;/g, ',').replace(/&amp;/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);
  }
}

我ながらきったねえコードだ…
これからの課題

  1. prototypeで疑似クラス化
  2. 無駄がありそうな処理を修正
  3. 各部品のスタイルをcssに任せるか?
  4. 問題がすべて解決したらログ出力行をコメントアウト

元々、VB(6.0)や、VBA くらいしか触ってこなかったわけで
クラスらしいクラスを組んだことがないので、ここから未知の領域
動かなくなったら嫌だなあ

JavaScript document.evaluate

Vector-Link.user.jsというグリモンのスクリプトで使われていて
何をやってるんだろうと思っていたが
こんなものもあるんだ!という驚き

とか書きつつ

//meta[@name='download']

の記述の意味がパッと見わからない
<meta name='download'>の行を取得してるのかな
このページにそういう記述があるからだろうけど
短いソースコードでよくできてるなあ

スクリプトの namespaceに、はてダURLが載っている
そういえば、他にも色々なところで見たような気がする



別件:
何個か記事にスターもらっていたけど
なんか挨拶とかするべきなんだろうか
はてな文化わからない

イベント監視 メモ2

外部jsファイルの読み込み - honjarake blog
prototype.jsを読み込んでから下記を実行

var handler = function (event) {
  //console.log(this);
  try {
    var event = event || window.event;
    var target = event.target || event.srcElement;
    console.log('handler : ' + target.tagName);
  } catch (e) {
    console.log('handler : ' + e);
  }
}
var eventWatch = (function () {
  //console.log('eventWatch start');
  try {
    var html = document.getElementsByTagName('html') [0];
    Event.observe(html, 'click', handler);
  } catch (e) {
    console.log('eventWatch : ' + e);
  }
  //console.log('eventWatch end');
}) ();

jqueryなら特定のタグエレメント監視でできるんだろうな