cytube_emote_float_window

エモートをウィンドウで常に表示(ダブルクリックすると直接送信)

目前為 2020-07-06 提交的版本,檢視 最新版本

// ==UserScript==
// @name         cytube_emote_float_window
// @namespace    https://cytube.xyz/
// @version      0.6
// @description  エモートをウィンドウで常に表示(ダブルクリックすると直接送信)
// @author       utubo
// @match        *://cytube.xyz/*
// @grant        none
// ==/UserScript==
// cytubeならjQueryもjQuryUIも読み込まれてるはずだから@requireしないでいいか…

(window.unsafeWindow || window).eval(` // ← チャンネルのJSにセットするときはこの行(と最後の行)を削除
(function() {
// 2重起動されたら古いのはクリアする(位置とサイズは覚えておく)
var emoteFloatWindow = $('#GM_emote_float_window');
var offset = null;
var width = 500;
var height = 160;
if (emoteFloatWindow[0]) {
  offset = emoteFloatWindow.offset();
  width = emoteFloatWindow.width();
  height = emoteFloatWindow.height();
  emoteFloatWindow.remove();
  $('#GM_emote_float_window_button').remove();
}

// ボタン初回クリック時の位置設定
var setupSartPosition = () => {
  var btn = $('#GM_emote_float_window_button');
  offset = btn.offset();
  offset.left += 30 + window.scrollX;
  offset.top += -10 + window.scrollY;
  emoteFloatWindow.offset(offset);
  width = Math.min(width, $('#leftcontrols').width());
  emoteFloatWindow.width(width);
};

// フロートウィンドウの外枠を作成
emoteFloatWindow =
  $('<div id="GM_emote_float_window" style="' +
      'position: absolute;' +
      'z-index: 2;' +
      'top: 10px;' +
      'left: 10px;' +
      'width: ' + width + 'px;' +
      'height: ' + height + 'px;' +
      'overflow: hidden;' +
      'border: 1px solid;' +
      'padding: 10px;' +
      'display: none;' +
      '">' +
      '<div id="GM_emote_float_window_content" style="width:100%;height:100%;overflow:auto;">' +
    '</div>')
  .appendTo($('body'))
;
if (offset) {
  emoteFloatWindow.offset(offset);
}
emoteFloatWindow
  .resizable()
  .draggable({
    scroll: false,
    stop: function(e, ui) {
      // windowリサイズで位置がおかしくならないようにする
      var p = ui.helper.parent();
      var x = ui.position.left / p.width() * 100;
      var y = ui.position.top / p.height() * 100;
      ui.helper.css('left', x + '%');
      ui.helper.css('top', y + '%');
    }
  })
;
document.body.style.position = 'relative';

// エモートをクリックorダブルクリックしたときの処理
var chatline = $('#chatline');
var singleClickEventTimer = null;
emoteFloatWindow.on('click', 'img', ev => {
  var title = ev.target.getAttribute('title');
  singleClickEventTimer = setTimeout(() => {
    var value = chatline[0].value;
    chatline[0].value = value + (value ? ' ' : '') + title;
  }, 100);
});
emoteFloatWindow.on('dblclick', 'img', ev => {
  clearTimeout(singleClickEventTimer);
  var evt = $.Event('keydown');
  evt.keyCode = 13;
  chatline.trigger(evt);
});

// リスト更新
var content = $('#GM_emote_float_window_content');
var refreshList = () => {
  emoteFloatWindow.css('backgroundColor', getComputedStyle(document.body, null).getPropertyValue('background-color'));
  content.empty();
  for (var emote of CHANNEL.emotes) {
    $('<img style="max-width:50px;max-height:50px;vertical-align:bottom;" title="' + emote.name + '" src="' + emote.image + '">')
    .appendTo(content);
  }
};

// 表示切替ボタン
$('<button id="GM_emote_float_window_button" class="btn btn-sm btn-default"><span class="glyphicon glyphicon-new-window"></span></button>')
  .on('click', ev => {
    if (emoteFloatWindow.css('display') == 'none') {
      refreshList();
      if (!offset) { setupSartPosition() };
    }
    emoteFloatWindow.toggle();
  })
  .insertAfter($('#emotelistbtn'))
;
})();
`); // ← チャンネルのJSにセットするときはこの行も削除