Google Reader Key Customize

By fxwiki Last update May 10, 2009 — Installed 679 times. Daily Installs: 5, 5, 5, 2, 3, 7, 6, 6, 2, 2, 4, 3, 4, 3, 5, 5, 2, 2, 2, 4, 3, 2, 3, 2, 2, 2, 2, 3, 3, 3, 2, 2

There are 3 previous versions of this script.

// ==UserScript==
// @name  Google Reader Key Customize
// @namespace  http://fxwiki.blog63.fc2.com/
// @description  Customize keyboard shortcuts in Google Reader.
// @version 1.1
// @include  http://www.google.tld/reader/*
// @include  https://www.google.tld/reader/*
// ==/UserScript==
// http://userscripts.org/scripts/show/48220

(function() {
var g_timeout = 2000;
var key = {}, $ = function(id) { return document.getElementById(id); }
var init = function() {
  var ja = [
    'キーボードショートカットのカスタマイズ',
    '"g"以外の英数字を登録。(例 b: bキーで動作 B: shift+bキーで動作)',
    'ナビゲーション', 'アイテム', 'ジャンプ', 'アプリケーション', 'その他',
    'j', '次のアイテムを表示 ( j )',
    'k', '前のアイテムを表示 ( k )',
    'n', '次のアイテムを選択 ( n )',
    'p', '前のアイテムを選択 ( p )',
    'N', '次のフィード/フォルダを選択 ( N )',
    'P', '前のフィード/フォルダを選択 ( P )',
    'O', '選択したフィード/フォルダを開く ( O )',
    'NO', '次のフィード/フォルダを開く ( N-O )',
    'PO', '前のフィード/フォルダを開く ( P-O )',
    'X', 'フォルダを開閉する ( X )',
    'c', 'アイテムにメモを追加 ( c )',
    'e', 'アイテムをメールで送信 ( e )',
    'm', 'アイテムを既読/未読にする ( m )',
    'o', 'アイテムを開閉する ( o )',
    's', 'アイテムにスターを付ける ( s )',
    't', 'アイテムにタグを付ける ( t )',
    'v', 'アイテムのソースページを開く ( v )',
    'A', 'アイテムをすべて既読にする ( A )',
    'C', 'メモを表示 ( C )',
    'D', 'アイテムにメモをして共有する ( D )',
    'S', 'アイテムを共有する ( S )',
    'ga', '「すべてのアイテム」に移動 ( g-a )',
    'gc', '「Comment view」に移動 ( g-c )',
    'gd', '「フィードを検索」に移動 ( g-d )',
    'gf', '友だち選択ツールを表示 ( g-f )',
    'gh', '「ホーム」に移動 ( g-h )',
    'gs', '「スター付きアイテム」に移動 ( g-s )',
    'gu', 'フィード選択ツールを表示 ( g-u )',
    'gt', 'タグ選択ツールを表示 ( g-t )',
    'gF', '「友だちの共有アイテム」に移動 ( g-F )',
    'gS', '「共有アイテム」に移動 ( g-S )',
    'gT', '「トレンド」に移動 ( g-T )',
    'stuff', '「コンテンツ」に移動',
    'notes', '「メモ」に移動',
    '_1', '全文表示に切り替える ( 1 )',
    '_2', 'リスト表示に切り替える ( 2 )',
    'a', 'フィードを登録 ( a )',
    'r', '更新 ( r )',
    'u', '全画面表示の切り替え ( u )',
    'U', 'ナビゲーションパネルをポップアップ ( U )',
    'plus', '選択アイテムの文字サイズを大きく ( + )',
    'minus', '選択アイテムの文字サイズを小さく ( - )',
    'slash', 'カーソルを検索ボックスに置く ( / )',
    'pUp', '上に1ページ分スクロール ( PageUp )',
    'pDown', '下に1ページ分スクロール ( PageDown )',
    'Home', '先頭にスクロール ( Home )',
    'End', '末尾にスクロール ( End )',
    'up', '上に1行分スクロール ( ↑ )',
    'down', '下に1行分スクロール ( ↓ )',
    'space', '次のアイテムにスクロール ( Space )',
    'SPACE', '前のアイテムにスクロール ( Shift+Space )',
    'newItem', '新着アイテムを表示',
    'allItem', 'すべてのアイテムを表示'
  ];
  var en = [
    'Customize keyboard shortcuts',
    'An alphanumeric character except "g". (for example, b: b, B: shift-b)',
    'Navigation', 'Items', 'Jumping', 'Application', 'Others',
    'j', 'next item ( j )',
    'k', 'previous item ( k )',
    'n', 'item scan down ( n )',
    'p', 'item scan up ( p )',
    'N', 'next subscription ( N )',
    'P', 'previous subscription ( P )',
    'O', 'open subscription or folder ( O )',
    'NO', 'next & open subscription or folder ( N-O )',
    'PO', 'previous & open subscription or folder ( P-O )',
    'X', 'expand folder ( X )',
    'c', 'add comment ( c )',
    'e', 'email item ( e )',
    'm', 'mark item as read/unread ( m )',
    'o', 'expand/collapse item ( o )',
    's', 'star item ( s )',
    't', 'tag item ( t )',
    'v', 'view original ( v )',
    'A', 'mark all as read ( A )',
    'C', 'view comments ( C )',
    'D', 'share item with note ( D )',
    'S', 'share item ( S )',
    'ga', 'go to all items ( g-a )',
    'gc', 'go to comment view ( g-c )',
    'gd', 'go to discovery page ( g-d )',
    'gf', 'open friend selector ( g-f )',
    'gh', 'go home ( g-h )',
    'gs', 'go to starred items ( g-s )',
    'gu', 'open subscription selector ( g-u )',
    'gt', 'open tag selector ( g-t )',
    'gF', 'go to friends\' shared items ( g-F )',
    'gS', 'go to shared items ( g-S )',
    'gT', 'go to trends page ( g-T )',
    'stuff', 'go to your stuff page',
    'notes', 'go to your notes page',
    '_1', 'switch to expanded view ( 1 )',
    '_2', 'switch to list view ( 2 )',
    'a', 'add a subscription ( a )',
    'r', 'refresh ( r )',
    'u', 'toggle full screen mode ( u )',
    'U', 'popup navigation pane ( U )',
    'plus', 'increase magnification ( + )',
    'minus', 'decrease magnification ( - )',
    'slash', 'move cursor to search box ( / )',
    'pUp', 'scroll page up ( PageUp )',
    'pDown', 'scroll page down ( PageDown )',
    'Home', 'scroll top ( Home )',
    'End', 'scroll end ( End )',
    'up', 'scroll line up ( ↑ )',
    'down', 'scroll line down ( ↓ )',
    'space', 'scroll next item ( Space )',
    'SPACE', 'scroll previous item ( Shift+Space )',
    'newItem', 'view new items',
    'allItem', 'view all items'
  ];
  
  var css = '\
    #grkc_setting {color: white; padding: 0 0 1em 0;\
      position: absolute; top: 20px; left: 20px; z-index: 1234;\
      background: rgba(10%, 15%, 10%, 0.9); -moz-border-radius: 10px; }\
    #grkc_setting input { margin-right: 0.5em; text-align: center; width: 1.2em; }\
    #grkc_titlebar { background: rgba(40%, 40%, 60%, 0.5);\
      -moz-border-radius: 10px 10px 0 0; padding: 2px 10px; }\
    #grkc_title a { font-weight: bold; color: white; text-decoration: none; }\
    #grkc_title a:hover { color: #FF9; }\
    #grkc_btn { float: right; position: absolute; right: 10px; }\
    #grkc_desc { padding: 0 0.5em; margin: 0.5em 0 1em 0; }\
    #grkc_tab { padding: 0 0.5em; margin: 1em 0; }\
    #grkc_tab span { border: 1px solid #999; padding: 2px 8px;\
      -moz-border-radius: 8px 8px 0 0; cursor: pointer; }\
    #grkc_tab span:hover { background: rgba(100%, 100%, 80%, 0.2); }\
    #grkc_form { padding: 0.5em; }\
    #grkc_item, #grkc_jump, #grkc_app, #grkc_etc { display: none; }\
    .grkc_row { float: left; padding: 0 5px; }\
    #grkc_ok { margin-right: 0.5em; padding: 0 3ex; }\
    #grkc_cancel { padding: 0 1ex; }\
    #grkc_ok, #grkc_cancel { font-size: 90%; border: 1px solid #999; }\
    #grkc_ok:hover, #grkc_cancel:hover { cursor: pointer;\
      background: rgba(80%, 100%, 80%, 0.2); }\
  ';
  var link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = "data:text/css," + escape(css);
  document.getElementsByTagName("head")[0].appendChild(link);
  var div = document.createElement('div');
  div.id = 'grkc_setting';
  div.style.display = 'none';
  document.body.appendChild(div);
  if (document.title.match(/Google\s?リーダー/)) var a = ja;
  else var a = en;
  var tabID = ['nav', 'item', 'jump', 'app', 'etc'];
  var s = '<div id="grkc_titlebar"><span id="grkc_title">'
    + '<a href="http://userscripts.org/scripts/show/48220" target="_blank">'
    + a[0] + '</a></span><span id="grkc_btn"><span id="grkc_ok">OK</span>'
    + '<span id="grkc_cancel">Cancel</span></span></div><div id="grkc_desc">'
    + a[1] + '</div><div id="grkc_tab">';
  for (var i=0; i<tabID.length; i++) s += '<span id="grkc_tab_' + tabID[i] + '">' + a[i+2] + '</span>';
  s += '</div><div id="grkc_form">';
  var addLabel = function(n1, n2, n3, id) {
    s += '<div id="grkc_' + id + '"><span class="grkc_row">';
    for (var i=n1; i<n2; i=i+2) s += '<label><input id="'
      + a[i] + '" type="text" maxlength="1">' + a[i+1] + '</label><br>';
    s += '</span><span class="grkc_row">';
    for (var i=n2; i<n3; i=i+2) s += '<label><input id="'
      + a[i] + '" type="text" maxlength="1">' + a[i+1] + '</label><br>';
    s += '</span></div>';
  }
  addLabel(7, 17, 27, tabID[0]);
  addLabel(27, 39, 49, tabID[1]);
  addLabel(49, 63, 75, tabID[2]);
  addLabel(75, 85, 93, tabID[3]);
  addLabel(93, 103, 113, tabID[4]);
  s += '</div>';
  $('grkc_setting').innerHTML = s;
  var addEvent = function(id) {
    var tab = $('grkc_tab_' + id);
    var col = 'rgba(80%, 100%, 80%, 0.2)';
    if (id == 'nav') tab.style.background = col;
    tab.addEventListener('click', function() {
      for (var i=0; i<tabID.length; i++) {
        $('grkc_' + tabID[i]).style.display = 'none';
        $('grkc_tab_' + tabID[i]).style.background = '';
      }
      $('grkc_' + id).style.display = 'block';
      tab.style.background = col;
    }, false);
  }
  for (var i=0; i<tabID.length; i++) addEvent(tabID[i]);
  var loadKey = function() {
    key = eval(GM_getValue("key")) || {};
    var e = document.evaluate('id("grkc_form")/div/span/label/input', document, null, 7, null);
    var i = 0;
    for (var p in key) {
      e.snapshotItem(i).value = (key[p]) ? key[p] : '';
      i ++;
    }
    for (var p in key) {
      if (key[p].match(/[A-Z]/)) key[p] = '@' + key[p];
      else key[p] = key[p].toUpperCase();
    }
  }
  $('grkc_ok').addEventListener('click', function() {
    $('grkc_setting').style.display = 'none';
    var e = document.evaluate('id("grkc_form")/div/span/label/input', document, null, 7, null);
    for (var n=0,d={}; n<e.snapshotLength; n++) {
      if (! e.snapshotItem(n).value.match(/[0-9a-fh-zA-Z]/)) e.snapshotItem(n).value = '';
      d[e.snapshotItem(n).id] = e.snapshotItem(n).value;
    }
    GM_setValue("key",d.toSource());
    loadKey();
  }, false);
  $('grkc_cancel').addEventListener('click', function() {
    document.getElementById('grkc_setting').style.display = 'none';
    loadKey();
  }, false);
  loadKey();
}

var grKeyCustomize = function(e) {
  var set = $('grkc_setting');
  if (! set) return;
  if (e.ctrlKey && e.shiftKey && e.keyCode == 191) {
    if (set.style.display != 'block') set.style.display = 'block';
    else set.style.display = 'none';
  }
  if (e.ctrlKey || e.altKey || e.metaKey || set.style.display == 'block'
    || e.target.tagName.match(/input|textarea/i)) return;
  var code = String.fromCharCode(e.keyCode), evt, cha;
  if (e.shiftKey) code = '@' + code;
  if (code == 'G') {
    document.removeEventListener('keydown', grKeyCustomize, true);
    setTimeout(function() {
      document.addEventListener('keydown', grKeyCustomize, true);
    }, g_timeout);
    return;
  }
  switch (code) {
  case key.a: case key.A: case key.ga:
    cha = 'A'; break;
  case key.c: case key.C: case key.gc:
    cha = 'C'; break;
  case key.D: case key.gd:
    cha = 'D'; break;
  case key.e:
    cha = 'E'; break;
  case key.gf: case key.gF:
    cha = 'F'; break;
  case key.gh:
    cha = 'H'; break;
  case key.j:
    cha = 'J'; break;
  case key.k:
    cha = 'K'; break;
  case key.m:
    cha = 'M'; break;
  case key.n: case key.N: case key.NO:
    cha = 'N'; break;
  case key.o: case key.O:
    cha = 'O'; break;
  case key.p: case key.P: case key.PO:
    cha = 'P'; break;
  case key.r:
    cha = 'R'; break;
  case key.s: case key.S: case key.gs: case key.gS:
    cha = 'S'; break;
  case key.t: case key.gt: case key.gT:
    cha = 'T'; break;
  case key.u: case key.U: case key.gu:
    cha = 'U'; break;
  case key.v:
    cha = 'V'; break;
  case key.X:
    cha = 'X'; break;
  case key.pUp:
    cha = 33; break;
  case key.pDown:
    cha = 34; break;
  case key.Home:
    cha = 36; break;
  case key.End:
    cha = 35; break;
  case key.up:
    cha = 38; break;
  case key.down:
    cha = 40; break;
  case key._1:
    cha = 49; break;
  case key._2:
    cha = 50; break;
  case key.plus:
    cha = 107; break;
  case key.minus:
    cha = 109; break;
  case key.slash:
    cha = 191; break;
  case key.stuff: case key.notes: case key.newItem: case key.allItem:
  case key.space: case key.SPACE:
    cha = -1; break;
  defalut: return;
  }
  if (! cha) return;
  if (cha && isNaN(cha)) cha = cha.charCodeAt();
  e.stopPropagation();
  evt = document.createEvent('KeyboardEvent');
  switch (code) {
  case key.a: case key.c: case key.e: case key.j: case key.k: case key.m:
  case key.n: case key.o: case key.p: case key.r: case key.s: case key.t:
  case key.u: case key.v: case key._1: case key._2: case key.slash:
  case key.plus: case key.minus: case key.pUp:  case key.pDown:
  case key.Home: case key.End: case key.up: case key.down:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 0, 0, cha, 0);
    break;
  case key.A: case key.C: case key.D: case key.N: case key.O:
  case key.P: case key.S: case key.U: case key.X:
  case key.NO: case key.PO:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 1, 0, cha, 0);
    break;
  case key.ga: case key.gc: case key.gd: case key.gf:
  case key.gh: case key.gs: case key.gt: case key.gu:
  case key.gF: case key.gS: case key.gT:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 0, 0, 71, 0);
    break;
  case key.space:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 0, 0, 32, 0);
    break;
  case key.SPACE:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 1, 0, 32, 0);
    break;
  case key.stuff: case key.notes: case key.newItem: case key.allItem:
    evt = document.createEvent('MouseEvents');
    evt.initEvent('click', 1, 1);
    break;
  default: return;
  }
  switch (code) {
  case key.stuff:
    $('your-items-tree-item-0-link').dispatchEvent(evt);
    return;
  case key.notes:
    $('your-items-tree-item-2-link').dispatchEvent(evt);
    return;
  case key.newItem:
    $('show-new').dispatchEvent(evt);
    return;
  case key.allItem:
    $('show-all').dispatchEvent(evt);
    return;
  }
  document.dispatchEvent(evt);
  switch (code) {
  case key.NO: case key.PO:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 1, 0, 79, 0);
    break;
  case key.ga: case key.gc: case key.gd: case key.gf:
  case key.gh: case key.gs: case key.gt: case key.gu:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 0, 0, cha, 0);
    break;
  case key.gF: case key.gS: case key.gT:
    evt.initKeyEvent('keypress', 1, 1, null, 0, 0, 1, 0, cha, 0);
    break;
  default: return;
  }
  document.dispatchEvent(evt);
}

window.addEventListener('load', function() {
  document.addEventListener('keydown', grKeyCustomize, true);
  init();
}, false);
window.removeEventListener('unload', function() {
  document.removeEventListener('keydown', grKeyCustomize, true);
}, false);
})();