Yet Another Weibo Filter

新浪微博根据关键词、作者、话题、来源等过滤微博;修改版面。 新浪微博根據關鍵字、作者、話題、來源等篩選微博;修改版面。 filter Sina Weibo by keywords, original, topic, source, etc.; modify layout

当前为 2014-07-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Yet Another Weibo Filter
  3. // @namespace https://github.com/tiansh
  4. // @description 新浪微博根据关键词、作者、话题、来源等过滤微博;修改版面。 新浪微博根據關鍵字、作者、話題、來源等篩選微博;修改版面。 filter Sina Weibo by keywords, original, topic, source, etc.; modify layout
  5. // @include http://weibo.com/*
  6. // @include http://www.weibo.com/*
  7. // @version 0.1.25 alpha
  8. // @author 田生
  9. // @copyright 2013+, 田生
  10. // @license The MIT License (MIT); http://opensource.org/licenses/MIT
  11. // @grant GM_xmlhttpRequest
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // @grant GM_addStyle
  15. // @grant GM_registerMenuCommand
  16. // @grant GM_info
  17. // @grant unsafeWindow
  18. // @run-at document-start
  19. // ==/UserScript==
  20.  
  21. // 图片
  22. var images = {
  23. 'filter': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAFEUExURUxpcZ6eno6OjpmZmf////v7+/j4+Pr6+vr6+uzs7MvLy8rKyuzs7Ly8vLy8vO7u7r29vb29ve7u7unp6by8vOrq6ufn5+/v776+vry8vO3t7ejo6Ojo6Ovr6+/v7729ve7u7ry8vO/v7+vr6+jo6L6+vu7u7ry8vO/v7+rq6ujo6L6+vu3t7e/v77e3t+vr6+jo6Jubm5qampqamp+fn7m5uezs7MXFxe7u7p2dnZubm5+fn5ycnOzs7L6+vsDAwMLCwsHBwevr6/Ly8vr6+sPDw+3t7e/v78TExMHBwcnJycXFxff39+np6e7u7vPz8/f39/j4+O/v7/T09Ovr6/////Dw8PT09P///9zc3Pn5+fv7+////+3t7f///9ra2v///8DAwOPj49PT0////8LCwtHR0b+/v+Pj48bGxsHBwcfHx0ifhqUAAABsdFJOUwA/Skoauru8u8K7u40sLY8yMYeULoqRijIxjIiNkI42jTWQko86nDaeoJ08sLRKuLQ1Nj8yUL2twEc9Nzq6op6lqbbGn6K/wKymsqmExsO6foDKuMV+wchsm3qmF8l6l2ZWC7oWtrpSCLq2ugo9naEAAAClSURBVBjTY2DAANGsbOzsHEDAzs7G6gIUCI9Ny8rm4ubmykxNDnIGCniFxKczMjEzMzEmRvqaAwUsvYMTMkB6kyL8HYxBDCuPsLgUBgaWUD9HI4ixNp6cUTEsgZx2hjCLrF3dA3zc7E0QVptaONma6SG5RVvXQF9HHUlAVUNLU00RSUBeSUVZQRJJQEJORlaKD0lAQFxaVEgESUCQX0yYh5cBKwAASvgW88X18swAAAAASUVORK5CYII=',
  24. };
  25.  
  26. // 多行字符串
  27. var funcStr = function (f) {
  28. var s = f.toString().split(/\r\n|\r|\n/g).slice(1, -1).join('\n');
  29. return s;
  30. };
  31.  
  32. // 快速创建一段文档元素
  33. var cewih = function (tag, inner) {
  34. var d = document.createElement(tag);
  35. d.innerHTML = inner;
  36. return d;
  37. };
  38.  
  39. // 文本常量
  40. // 请以简体中文为原文,参考这些资料翻译
  41. // http://zh.wikipedia.org/wiki/Template:CGroup/IT
  42. // http://www.microsoft.com/Language/zh-cn/Search.aspx
  43. var text = {
  44. // 基本按钮
  45. 'okButtonTitle': { 'zh-cn': '确定', 'zh-hk': '確定', 'zh-tw': '確定', 'en': 'Confirm' },
  46. 'cancelButtonTitle': { 'zh-cn': '取消', 'zh-hk': '取消', 'zh-tw': '取消', 'en': 'Cancel' },
  47. 'closeButtonTitle': { 'zh-cn': '关闭', 'zh-hk': '關閉', 'zh-tw': '關閉', 'en': 'Close' },
  48. 'configStringsAdd': { 'zh-cn': '添加', 'zh-hk': '新增', 'zh-tw': '新增', 'en': 'Add' },
  49. 'configUsersAdd': { 'zh-cn': '添加', 'zh-hk': '新增', 'zh-tw': '新增', 'en': 'Add' },
  50. 'foldedWeiboText': { 'zh-cn': '"来自 @" attr(yawf-author) " 的一条微博被折叠,请点击查看"', 'zh-hk': '"來自 @" attr(yawf-author) " 的一條微博被折疊,請點擊查看"', 'zh-tw': '"來自 @" attr(yawf-author) " 的一條微博被折疊,請點擊查看"', 'en': '"A Weibo from @" attr(yawf-author) " was folded, click to view."' },
  51. // 设置框
  52. 'filter': { 'zh-cn': '过滤器', 'zh-hk': '篩選器', 'zh-tw': '篩選器', 'en': 'Filter' },
  53. 'configDialogTitle': { 'zh-cn': '过滤器设置', 'zh-hk': '篩選器設定', 'zh-tw': '篩選器設定', 'en': 'Filter Settings' },
  54. 'configRefreshNotice': { 'zh-cn': '部分设置修改需要保存后重新载入页面才能生效', 'zh-hk': '部分設定變更需要儲存後重新載入網頁才能生效', 'zh-tw': '部分設定變更需要儲存後重新載入網頁才能生效', 'en': 'Some settings need refresh webpage after save to apply' },
  55. 'whitelistFilterDesc': { 'zh-cn': '总是显示{{{typed}}}', 'zh-hk': '總是顯示{{{typed}}}', 'zh-tw': '總是顯示{{{typed}}}', 'en': 'Always show {{{typed}}}' },
  56. 'blacklistFilterDesc': { 'zh-cn': '隐藏{{{typed}}}', 'zh-hk': '隱藏{{{typed}}}', 'zh-tw': '隱藏{{{typed}}}', 'en': 'Hide {{{typed}}}' },
  57. 'foldlistFilterDesc': { 'zh-cn': '折叠{{{typed}}}', 'zh-hk': '折疊{{{typed}}}', 'zh-tw': '折疊{{{typed}}}', 'en': 'Fold {{{typed}}}' },
  58. 'blacklistActionDesc': { 'zh-cn': '隐藏', 'zh-hk': '隱藏', 'zh-tw': '隱藏', 'en': 'Hide' },
  59. 'foldlistActionDesc': { 'zh-cn': '折叠', 'zh-hk': '折疊', 'zh-tw': '折疊', 'en': 'Fold' },
  60. // 关键词
  61. 'keywordFilterGroupTitle': { 'zh-cn': '内容', 'zh-hk': '內容', 'zh-tw': '內容', 'en': 'Content' },
  62. 'keywordFilterDesc': { 'zh-cn': '关键词', 'zh-hk': '關鍵字', 'zh-tw': '關鍵字', 'en': 'Keyword' },
  63. 'keywordFilterDetails': { 'zh-cn': '包含以下关键词的微博', 'zh-hk': '包含以下關鍵字的微博', 'zh-tw': '包含以下關鍵字的微博', 'en': 'Weibo with these keywords' },
  64. // 正则表达式
  65. 'regexpFilterGroupTitle': { 'zh-cn': '正则', 'zh-hk': '正則', 'zh-tw': '正規', 'en': 'Regexp' },
  66. 'regexpFilterDesc': { 'zh-cn': '正则式', 'zh-hk': '正則式', 'zh-tw': '正規式', 'en': 'Regexp' },
  67. 'regexpFilterDetails': { 'zh-cn': '匹配以下正则表达式的微博', 'zh-hk': '匹配以下正則表達式的微博', 'zh-tw': '匹配以下正規表示式的微博', 'en': 'Weibo matches these regular expressions' },
  68. 'regexpFilterRemark': { 'zh-cn': '书写时不需要对“/”字符转义', 'zh-hk': '書寫時不需要對“/”字符轉義', 'zh-tw': '書寫時不需要對“/”字符轉義', 'en': 'Do not escape "/" in your regexp.' },
  69. 'regexpBadFormedTitle': { 'zh-cn': '非法的正则表达式', 'zh-hk': '不合法的正則表達式', 'zh-tw': '不合法的正規表示式', 'en': 'Illegal Regexp' },
  70. 'regexpBadFormed': { 'zh-cn': '您输入的/{{regexp}}/不能被正确地解析为正则表达式,请检查您的输入。如需关键词屏蔽请到内容标签页设置。', 'zh-hk': '您输入的/{{regexp}}/不能被正确地解析为正则表达式,请检查您的输入。如需关键词屏蔽请到内容标签页面设置。', 'zh-tw': '您輸入的/{{regexp}}/不能被正確地解析為正規表示式,請檢查您的輸入。如需關鍵詞屏蔽請到內容標籤頁面設置。', 'en': 'Can not parse /{{regexp}}/ as regexp. Please check your input. You may hide Weibo by keywords in Content tab page.' },
  71. // 帐号
  72. 'accountFilterGroupTitle': { 'zh-cn': '帐号', 'zh-hk': '帳號', 'zh-tw': '帳號', 'en': 'Account' },
  73. 'accountFilterDesc': { 'zh-cn': '帐号', 'zh-hk': '帳號', 'zh-tw': '帳號', 'en': 'Account' },
  74. 'accountFilterDetails': { 'zh-cn': '来自以下帐号的微博', 'zh-hk': '來自以下帳號的微博', 'zh-tw': '來自以下帳號的微博', 'en': 'Weibo from these accounts' },
  75. 'accountNotExistErrorTitle': { 'zh-cn': '帐号不存在', 'zh-hk': '帳號不存在', 'zh-tw': '帳號不存在', 'en': 'Account does not exist' },
  76. 'accountNotExistError': { 'zh-cn': '不存在名为{{name}}的账号', 'zh-hk': '不存在名為{{name}}的賬號', 'zh-tw': '不存在名為{{name}}的賬號', 'en': 'Account named {{name}} does not exist' },
  77. // 原创
  78. 'originalFilterGroupTitle': { 'zh-cn': '原创', 'zh-hk': '原創', 'zh-tw': '原創', 'en': 'Original' },
  79. 'originalFilterDesc': { 'zh-cn': '帐号', 'zh-hk': '帳號', 'zh-tw': '帳號', 'en': 'Account' },
  80. 'originalFilterDetails': { 'zh-cn': '转发自以下账号的微博', 'zh-hk': '隱藏轉發自以下帳號的微博', 'zh-tw': '隱藏轉發自以下帳號的微博', 'en': 'Hide Weibo forwarded from these accounts' },
  81. // 提到
  82. 'mentionFilterGroupTitle': { 'zh-cn': '提到', 'zh-hk': '提到', 'zh-tw': '提到', 'en': 'Mention' },
  83. 'mentionFilterDesc': { 'zh-cn': '帐号', 'zh-hk': '帳號', 'zh-tw': '帳號', 'en': 'Account' },
  84. 'mentionFilterDetails': { 'zh-cn': '提到以下账号的微博', 'zh-hk': '提到以下帳號的微博', 'zh-tw': '提到以下帳號的微博', 'en': 'Weibo mentioned these accounts' },
  85. // 话题
  86. 'topicFilterGroupTitle': { 'zh-cn': '话题', 'zh-hk': '話題', 'zh-tw': '話題', 'en': 'Topic' },
  87. 'topicFilterDesc': { 'zh-cn': '话题', 'zh-hk': '話題', 'zh-tw': '話題', 'en': 'Topic' },
  88. 'topicFilterDetails': { 'zh-cn': '包含以下话题的微博', 'zh-hk': '包含以下話題的微博', 'zh-tw': '包含以下話題的微博', 'en': 'Weibo with these topics' },
  89. // 来源
  90. 'sourceFilterGroupTitle': { 'zh-cn': '来源', 'zh-hk': '來源', 'zh-tw': '來源', 'en': 'Source' },
  91. 'sourceFilterDesc': { 'zh-cn': '来自', 'zh-hk': '來自', 'zh-tw': '來自', 'en': 'Via' },
  92. 'sourceFilterDetails': { 'zh-cn': '以下来源的微博', 'zh-hk': '以下來源的微博', 'zh-tw': '以下來源的微博', 'en': 'Weibo from these sources' },
  93. 'sourceFilterWarningTitle': { 'zh-cn': '默认来源', 'zh-hk': '預設來源', 'zh-tw': '預設來源', 'en': 'Default Source' },
  94. 'sourceFilterWarning': { 'zh-cn': '不能添加默认来源', 'zh-hk': '不能新增預設來源', 'zh-tw': '不能新增預設來源', 'en': 'You cannot add default source' },
  95. // 超链接
  96. 'hyperlinkFilterGroupTitle': { 'zh-cn': '链接', 'zh-hk': '連結', 'zh-tw': '連結', 'en': 'Link' },
  97. 'hyperlinkFilterDesc': { 'zh-cn': '超链接', 'zh-hk': '超連結', 'zh-tw': '超連結', 'en': 'Hyperlink' },
  98. 'hyperlinkFilterDetails': { 'zh-cn': '包含指向以下网站的超链接的微博', 'zh-hk': '包含指向以下站點的超連結的微博', 'zh-tw': '包含指向以下站點的超連結的微博', 'en': 'Weibo with hyperlink to these website' },
  99. // 更多
  100. 'otherFilterGroupTitle': { 'zh-cn': '更多', 'zh-hk': '其他', 'zh-tw': '其他', 'en': 'More' },
  101. // 显示
  102. 'otherWhitelistTitle': { 'zh-cn': '显示以下内容(不计入白名单)', 'zh-hk': '顯示以下內容(不計入白名單)', 'zh-tw': '顯示以下內容(不計入白名單)', 'en': 'Show following content (not regard as whitelist)' },
  103. 'showMyWeiboDesc': { 'zh-cn': '自己的微博', 'zh-hk': '自己的微博', 'zh-tw': '自己的微博', 'en': 'Weibo by myself' },
  104. 'showMyOriginalDesc': { 'zh-cn': '自己微博的转发', 'zh-hk': '自己微博的轉發', 'zh-tw': '自己微博的轉發', 'en': 'Forward of my Weibo' },
  105. 'showMentionMeDesc': { 'zh-cn': '提到自己的微博', 'zh-hk': '提到自己的微博', 'zh-tw': '提到自己的微博', 'en': 'Weibo mentioned me' },
  106. // 隐藏
  107. 'otherBlacklistTitle': { 'zh-cn': '隐藏以下内容', 'zh-hk': '以下內容', 'zh-tw': '隱藏以下內容', 'en': 'Hide following content' },
  108. 'adfeedFilterDesc': { 'zh-cn': '推广微博', 'zh-hk': '推廣微博', 'zh-tw': '推廣微博', 'en': 'Ad Weibo' },
  109. 'recommandFeedDesc': { 'zh-cn': '推荐微博', 'zh-hk': '建議微博', 'zh-tw': '建議微博', 'en': 'Recommand Weibo' },
  110. 'fakeWeiboFilterDesc': { 'zh-cn': '混入微博列表的其它内容', 'zh-hk': '混入微博列表的其它內容', 'zh-tw': '混入微博列表的其它內容', 'en': 'Other contents in Weibo list' },
  111. 'deletedForwardFilterDesc': { 'zh-cn': '已删除微博的转发', 'zh-hk': '已刪除微博的轉發', 'zh-tw': '已刪除微博的轉發', 'en': 'Forward of deleted Weibo' },
  112. 'voteWeiboFilterDesc': { 'zh-cn': '投票微博', 'zh-hk': '投票微博', 'zh-tw': '投票微博', 'en': 'Vote weibo' },
  113. // 刷屏与版聊
  114. 'otherSpammingTitle': { 'zh-cn': '刷屏与版聊', 'zh-hk': '洗版與版聊', 'zh-tw': '洗版與版聊', 'en': 'Spamming & Chating' },
  115. 'sameAccountFilterDesc': { 'zh-cn': '相同作者的微博:', 'zh-hk': '相同作者的微博:', 'zh-tw': '相同作者的微博:', 'en': 'Weibo from same account: ' },
  116. 'sameForwardFilterDesc': { 'zh-cn': '相同微博的转发:', 'zh-hk': '相同微博的轉發:', 'zh-tw': '相同微博的轉發:', 'en': 'Forward from same Weibo: ' },
  117. 'sameNumberOptionDesc': { 'zh-cn': '超过{{number}}条时', 'zh-hk': '超過{{number}}條時', 'zh-tw': '超過{{number}}條時', 'en': 'display no more than {{number}} ' },
  118. 'sameActionOptionDesc': { 'zh-cn': '{{{select}}}', 'zh-hk': '{{{select}}}', 'zh-tw': '{{{select}}}', 'en': 'or {{{select}}} it' },
  119. // 分组浏览
  120. 'otherGroupTitle': { 'zh-cn': '分组浏览', 'zh-hk': '分組流覽', 'zh-tw': '分組流覽', 'en': 'Browse by Group' },
  121. 'accountByGroup': { 'zh-cn': '分组浏览时禁用按账号隐藏', 'zh-hk': '分組流覽時禁用按帳號隱藏', 'zh-tw': '分組流覽時禁用按帳號隱藏', 'en': 'Disable hide by account filter when browsing by group' },
  122. 'sameAccountByGroup': { 'zh-cn': '浏览分组时禁用相同作者数量限制', 'zh-hk': '流覽分組時禁用相同作者數量限制', 'zh-tw': '流覽分組時禁用相同作者數量限制', 'en': 'Disable hide too many Weibo from same account filter when browsing by group' },
  123. // 模块
  124. 'layoutFilterGroupTitle': { 'zh-cn': '模块', 'zh-hk': '模組', 'zh-tw': '模組', 'en': 'Module' },
  125. 'layoutFilterGroupDesc': { 'zh-cn': '隐藏以下模块', 'zh-hk': '隱藏以下模組', 'zh-tw': '隱藏以下模組', 'en': 'Hide following modules' },
  126. // 标识图标
  127. 'layoutHideIcon': { 'zh-cn': '标识/图标', 'zh-hk': '標誌/圖示', 'zh-tw': '標誌/圖示', 'en': 'Logo / Icon' },
  128. 'layoutHideIconLevel': { 'zh-cn': '等级', 'zh-hk': 'Level', 'zh-tw': '等級', 'en': 'Level' },
  129. 'layoutHideIconMember': { 'zh-cn': '微博会员', 'zh-hk': '微博會員', 'zh-tw': '微博會員', 'en': 'Weibo VIP / Member' },
  130. 'layoutHideIconApprove': { 'zh-cn': '个人认证', 'zh-hk': '個人認證', 'zh-tw': '個人認證', 'en': 'Personal Authentication / 個人認證' },
  131. 'layoutHideIconApproveCo': { 'zh-cn': '机构认证', 'zh-hk': '企業認證', 'zh-tw': '企業認證', 'en': 'Weibo Verification / 企業認證' },
  132. 'layoutHideIconClub': { 'zh-cn': '微博达人', 'zh-hk': '微博達人', 'zh-tw': '微博達人', 'en': 'Pioneer' },
  133. 'layoutHideIconVGirl': { 'zh-cn': '微博女郎', 'zh-hk': '微博女郎', 'zh-tw': '微博女郎', 'en': 'Weibo girl' },
  134. 'layoutHideIconTaobao': { 'zh-cn': '淘宝商户', 'zh-hk': '淘寶商戶', 'zh-tw': '淘寶商戶', 'en': 'Taobao Merchant' },
  135. // 导航栏
  136. 'layoutHideNav': { 'zh-cn': '导航栏', 'zh-hk': '導覽列', 'zh-tw': '導覽列', 'en': 'Navigation Bar' },
  137. 'layoutHideNavMain': { 'zh-cn': '首页', 'zh-hk': '首頁', 'zh-tw': '首頁', 'en': 'Home' },
  138. 'layoutHideNavHot': { 'zh-cn': '热门', 'zh-hk': '熱門', 'zh-tw': '熱門', 'en': 'Hot' },
  139. 'layoutHideNavApp': { 'zh-cn': '应用', 'zh-hk': '應用', 'zh-tw': '應用', 'en': 'Apps' },
  140. 'layoutHideNavGame': { 'zh-cn': '游戏', 'zh-hk': '遊戲', 'zh-tw': '遊戲', 'en': 'Game' },
  141. 'layoutHideNavMember': { 'zh-cn': '会员菜单', 'zh-hk': '會員功能表', 'zh-tw': '會員功能表', 'en': 'VIP Menu' },
  142. // 左栏
  143. 'layoutHideLeft': { 'zh-cn': '左栏', 'zh-hk': '左欄', 'zh-tw': '左欄', 'en': 'Left Column' },
  144. 'layoutHideLeftToMe': { 'zh-cn': '发给我的', 'zh-hk': '發給我的', 'zh-tw': '發給我的', 'en': 'Send to me' },
  145. 'layoutHideLeftFriends': { 'zh-cn': '好友圈', 'zh-hk': '好友圈', 'zh-tw': '好友圈', 'en': 'Friends' },
  146. 'layoutHideLeftApp': { 'zh-cn': '应用', 'zh-hk': '应用', 'zh-tw': '应用'/* as is */, 'en': 'Apps' },
  147. // 中栏
  148. 'layoutHideMiddle': { 'zh-cn': '中栏', 'zh-hk': '中欄', 'zh-tw': '中欄', 'en': 'Middle Column' },
  149. 'layoutHideMiddleRecommendedTopic': { 'zh-cn': '热门微博(发布框上方)', 'zh-hk': '热门微博(發布框上方)', 'zh-tw': '热门微博(發布框上方)'/* as is */, 'en': '热门微博 (Hot Weibo), top of publisher' },
  150. 'layoutHideMiddleMemberTip': { 'zh-cn': '开通会员提示(底部)', 'zh-hk': '開通會員提示(底部)', 'zh-tw': '開通會員提示(底部)', 'en': 'Tip of Join Weibo VIP, bottom' },
  151. // 右栏
  152. 'layoutHideRight': { 'zh-cn': '右栏', 'zh-hk': '右欄', 'zh-tw': '右欄', 'en': 'Right Column' },
  153. 'layoutHideRightWhole': { 'zh-cn': '整个右栏', 'zh-hk': '整個右欄', 'zh-tw': '整個右欄', 'en': 'Whole Right Column' },
  154. 'layoutHideRightTemplate': { 'zh-cn': '设置模板', 'zh-hk': '背景設定', 'zh-tw': '背景設定', 'en': 'Template Settings' },
  155. 'layoutHideRightInfo': { 'zh-cn': '头像', 'zh-hk': '頭像', 'zh-tw': '頭像', 'en': 'Avatar' },
  156. 'layoutHideRightTrial': { 'zh-cn': '会员资格体验', 'zh-hk': '会员资格体验', 'zh-tw': '会员资格体验'/* as is */, 'en': '会员资格体验 (Trial of VIP)' },
  157. 'layoutHideRightAtten': { 'zh-cn': '关注/粉丝/微博数', 'zh-hk': '關注/粉絲/微博數', 'zh-tw': '關注/粉絲/微博數', 'en': 'Numbers of Following/Followers/Weibo' },
  158. 'layoutHideRightInterest': { 'zh-cn': '可能感兴趣的人', 'zh-hk': '可能感興趣的人', 'zh-tw': '可能感興趣的人', 'en': 'You may know' },
  159. 'layoutHideRightHotTopic': { 'zh-cn': '热门话题', 'zh-hk': '熱門話題', 'zh-tw': '熱門話題', 'en': 'Hot Topic' },
  160. 'layoutHideRightMember': { 'zh-cn': '会员专区', 'zh-hk': '會員專區', 'zh-tw': '會員專區', 'en': 'Weibo VIP' },
  161. 'layoutHideRightWeibo': { 'zh-cn': '热门微博', 'zh-hk': '熱門微博', 'zh-tw': '熱門微博', 'en': 'Hot Weibo' },
  162. 'layoutHideRightLocation': { 'zh-cn': '地点推荐', 'zh-hk': '地點推薦', 'zh-tw': '地點推薦', 'en': 'Location' },
  163. 'layoutHideRightMusic': { 'zh-cn': ' 热门歌曲', 'zh-hk': '熱門歌曲', 'zh-tw': '熱門歌曲', 'en': 'Hot Music' },
  164. 'layoutHideRightMovie': { 'zh-cn': '最新电影', 'zh-hk': '最新電影', 'zh-tw': '最新電影', 'en': 'Hot Movie' },
  165. 'layoutHideRightBook': { 'zh-cn': '人气图书', 'zh-hk': '人氣圖書', 'zh-tw': '人氣圖書', 'en': 'Hot Book' },
  166. 'layoutHideRightNotice': { 'zh-cn': '公告栏', 'zh-hk': '公告欄', 'zh-tw': '公告欄', 'en': 'Bulletin Board' },
  167. // 微博内
  168. 'layoutHideWeibo': { 'zh-cn': '微博内', 'zh-hk': '微博內', 'zh-tw': '微博內', 'en': 'In Weibo' },
  169. 'layoutHideWeiboRecomFeed': { 'zh-cn': '精彩微博推荐', 'zh-hk': '精彩微博推薦', 'zh-tw': '精彩微博推薦', 'en': '精彩微博推荐 (Weibo you may interested in)' },
  170. 'layoutHideWeiboTopicCard': { 'zh-cn': '话题卡片', 'zh-hk': '話題卡片', 'zh-tw': '話題卡片', 'en': 'Topic Cards' },
  171. 'layoutHideWeiboLocationCard': { 'zh-cn': '位置卡片', 'zh-hk': '位置卡片', 'zh-tw': '位置卡片', 'en': 'Location Cards' },
  172. 'layoutHideWeiboFeedTip': { 'zh-cn': '评论框提示横幅', 'zh-hk': '評論框提示橫幅', 'zh-tw': '評論框提示橫幅', 'en': 'Tips for Comment' },
  173. // 个人主页
  174. 'layoutHidePerson': { 'zh-cn': '个人主页', 'zh-hk': '個人主頁', 'zh-tw': '個人主頁', 'en': 'Ones home page' },
  175. 'layoutHidePersonCover': { 'zh-cn': '封面图', 'zh-hk': '封面圖', 'zh-tw': '封面圖', 'en': 'Cover Picture' },
  176. 'layoutHidePersonTemplate': { 'zh-cn': '模板设置', 'zh-hk': '模板設置', 'zh-tw': '模板設置', 'en': 'Template Settings' },
  177. 'layoutHidePersonBadgeIcon': { 'zh-cn': '勋章', 'zh-hk': '勳章', 'zh-tw': '勳章', 'en': 'Badges' },
  178. 'layoutHidePersonStats': { 'zh-cn': '关注/粉丝/微博数', 'zh-hk': '關注/粉絲/微博數', 'zh-tw': '關注/粉絲/微博數', 'en': 'Numbers of Following/Followers/Weibo' },
  179. 'layoutHidePersonMyData': { 'zh-cn': '我的微博人气', 'zh-hk': '我的微博人气', 'zh-tw': '我的微博人气', 'en': '我的微博人气 (My Micro World)' },
  180. 'layoutHidePersonSuggestUser': { 'zh-cn': '可能感兴趣的人', 'zh-hk': '可能感兴趣的人', 'zh-tw': '可能感兴趣的人'/* as is */, 'en': 'Suggested' },
  181. 'layoutHidePersonGroup': { 'zh-cn': '推荐的人', 'zh-hk': '推荐的人', 'zh-tw': '推荐的人'/* as is */, 'en': '推荐的人 (Suggested Group)' },
  182. 'layoutHidePersonRelation': { 'zh-cn': '微关系', 'zh-hk': '微关系', 'zh-tw': '微关系'/* as is */, 'en': 'Relationship' },
  183. 'layoutHidePersonAlbum': { 'zh-cn': '图片', 'zh-hk': '相冊', 'zh-tw': '相冊', 'en': 'Album' },
  184. 'layoutHidePersonHotTopic': { 'zh-cn': '话题', 'zh-hk': '話題', 'zh-tw': '話題', 'en': 'Topic' },
  185. 'layoutHidePersonHotWeibo': { 'zh-cn': '热门微博', 'zh-hk': '熱門微博', 'zh-tw': '熱門微博', 'en': 'Hot Weibo' },
  186. // 杂项
  187. 'layoutHideOther': { 'zh-cn': '杂项', 'zh-hk': '雜項', 'zh-tw': '雜項', 'en': 'Others' },
  188. 'layoutHideOtherAds': { 'zh-cn': '广告', 'zh-hk': '廣告', 'zh-tw': '廣告', 'en': 'Advertisement' },
  189. 'layoutHideOtherFeedRecom': { 'zh-cn': '相关微博推荐', 'zh-hk': '相关推荐', 'zh-tw': '相关推荐', 'en': '相关推荐 (Related Weibo Suggestion)' },
  190. 'layoutHideOtherFooter': { 'zh-cn': '页面底部', 'zh-hk': '頁面底部', 'zh-tw': '頁面底部', 'en': 'Footer' },
  191. 'layoutHideOtherWbIm': { 'zh-cn': '微博桌面推荐(右下)', 'zh-hk': '微博桌面推薦(右下)', 'zh-tw': '微博桌面推薦(右下)', 'en': '微博桌面2014 (Desktop Weibo), bottom right' },
  192. 'layoutHideOtherTip': { 'zh-cn': '功能提示框', 'zh-hk': '功能提示框', 'zh-tw': '功能提示框', 'en': 'Function Tips' },
  193. // 工具
  194. 'toolFilterGroupTitle': { 'zh-cn': '工具', 'zh-hk': '工具', 'zh-tw': '工具', 'en': 'Tool' },
  195. 'clearDefTopicDesc': { 'zh-cn': '清除发布框中的默认话题', 'zh-hk': '清除發布框中的預設話題', 'zh-tw': '清除發布框中的預設話題', 'en': 'Remove default topic in Publisher' },
  196. 'userstyleTitle': { 'zh-cn': '自定义CSS', 'zh-hk': '自訂CSS', 'zh-tw': '自訂CSS', 'en': 'Customize CSS' },
  197. 'userstyleEditDesc': { 'zh-cn': '编辑微博自定义CSS', 'zh-hk': '編輯微博自訂CSS', 'zh-tw': '編輯微博自訂CSS', 'en': 'Edit Weibo Customize CSS' },
  198. 'userstyleEditDetails': { 'zh-cn': 'YAWF CSS: ', 'zh-hk': 'YAWF CSS: ', 'zh-tw': 'YAWF CSS: ', 'en': 'YAWF CSS: ' },
  199. 'noFloatNav': { 'zh-cn': '禁用导航栏顶端固定', 'zh-hk': '禁用導覽列頂端固定', 'zh-tw': '禁用導覽列頂端固定', 'en': 'Make navigation scroll with page' },
  200. 'showAllGroupDesc': { 'zh-cn': '展开左栏分组', 'zh-hk': '展開左欄分組', 'zh-tw': '展開左欄分組', 'en': 'Unfold groups in left column' },
  201. 'showAllMsgNavDesc': { 'zh-cn': '展开左栏消息', 'zh-hk': '展開左欄消息', 'zh-tw': '展開左欄消息', 'en': 'Unfold news in left column' },
  202. 'unwrapTextDesc': { 'zh-cn': '微博作者和正文同行', 'zh-hk': '微博作者和正文同行', 'zh-tw': '微博作者和正文同行', 'en': 'No line break after author' },
  203. 'personalRedirectWeibo': { 'zh-cn': '访问账号主页显示微博页面', 'zh-hk': '訪問帳號主頁顯示微博頁面', 'zh-tw': '訪問帳號主頁顯示微博頁面', 'en': 'Show Weibo page instead of personal mainpage by default' },
  204. 'viewOriginalDesc': { 'zh-cn': '添加“查看原图”链接', 'zh-hk': '添加“查看原圖”連結', 'zh-tw': '添加“查看原圖”連結', 'en': 'add "Original Picture" link' },
  205. 'viewOriginalText': { 'zh-cn': '查看原图', 'zh-hk': '查看原圖', 'zh-tw': '查看原圖', 'en': 'Original Picture' },
  206. 'blockHiddenWeiboDesc': { 'zh-cn': '告知服务器被隐藏的微博以避免再次加载', 'zh-hk': '告知伺服器被隱藏的微博以避免再次載入', 'zh-tw': '告知伺服器被隱藏的微博以避免再次載入', 'en': 'Send blocked Weibo to server to avoid load it again' },
  207. 'whitelistHighlightDesc': { 'zh-cn': '以该背景色显示白名单的微博:', 'zh-hk': '以該背景色顯示白名單的微博:', 'zh-tw': '以該背景色顯示白名單的微博:', 'en': 'Show Weibo in whitelist with background color: ' },
  208. 'transparencyInput': { 'zh-cn': '透明度{{number}}%', 'zh-hk': '透明度{{number}}%', 'zh-tw': '透明度{{number}}%', 'en': ' transparency {{number}} %' },
  209. 'mainBackgroundColorOverride': { 'zh-cn': '首页背景颜色', 'zh-hk': '首頁背景色彩', 'zh-tw': '首頁背景色彩', 'en': 'Background color for home page' },
  210. 'profileBackgroundColorOverride': { 'zh-cn': '个人主页背景颜色', 'zh-hk': '個人主頁背景色彩', 'zh-tw': '個人主頁背景色彩', 'en': 'Background color for personal home page' },
  211. // 脚本
  212. 'scriptFilterGroupTitle': { 'zh-cn': '脚本', 'zh-hk': '腳本', 'zh-tw': '腳本', 'en': 'Script' },
  213. // 导入导出
  214. 'configImportAndExport': { 'zh-cn': '设置', 'zh-hk': '設定', 'zh-tw': '設定', 'en': 'Setting' },
  215. 'configImportButton': { 'zh-cn': '导入', 'zh-hk': '匯入', 'zh-tw': '匯入', 'en': 'Import' },
  216. 'configImportWarningTitle': { 'zh-cn': '设置导入', 'zh-hk': '設定匯入', 'zh-tw': '設定匯入', 'en': 'Setting Import' },
  217. 'configImportWarning': { 'zh-cn': '导入的设置会覆盖您当前已有的设置,确实要导入设置吗?', 'zh-hk': '匯入的設定會覆蓋您當前已有的設定,您確定要匯入設定嗎?', 'zh-tw': '匯入的設定會覆蓋您當前已有的設定,您確定要匯入設定嗎?', 'en': 'The imported settings may replace your current settings. Are you sure you want to import this file?' },
  218. 'configImportSuccessTitle': { 'zh-cn': '设置导入完成', 'zh-hk': '設定匯入完成', 'zh-tw': '設定匯入完成', 'en': 'Import settings' },
  219. 'configImportSuccess': { 'zh-cn': '已经成功地导入了设置', 'zh-hk': '已经成功地匯入了設定', 'zh-tw': '已经成功地匯入了設定', 'en': 'Successfully imported settings' },
  220. 'configImportFailTitle': { 'zh-cn': '设置导入失败', 'zh-hk': '設定匯入失败', 'zh-tw': '設定匯入失败', 'en': 'Import settings' },
  221. 'configImportFail': { 'zh-cn': '导入设置文件时出现错误,可能是使用了错误的文件,文件被损坏或文件的版本不支持', 'zh-hk': '匯入設定檔案時出現錯誤,可能是使用了錯誤的檔案,檔案被損壞或設定檔案的版本不支持', 'zh-tw': '匯入設定檔案時出現錯誤,可能是使用了錯誤的檔案,檔案被損壞或設定檔案的版本不支持', 'en': 'Error occurred during importing process. Wrong file may be used, the file may be broken, or the version of setting file is not supported.' },
  222. 'configExportButton': { 'zh-cn': '导出', 'zh-hk': '匯出', 'zh-tw': '匯出', 'en': 'Export' },
  223. 'configResetButton': { 'zh-cn': '重置', 'zh-hk': '重設', 'zh-tw': '重設', 'en': 'Reset' },
  224. 'configResetWarningTitle': { 'zh-cn': '设置重置', 'zh-hk': '設定重設', 'zh-tw': '設定重設', 'en': 'Setting Reset' },
  225. 'configResetWarning': { 'zh-cn': '这将会清空您当前的所有配置,确实要重置设置吗?', 'zh-hk': '這將會清空您當前的所有設定,您確定要重置設定嗎?', 'zh-tw': '這將會清空您當前的所有設定,您確定要重置設定嗎?', 'en': 'You are deleting all your settings. Are you sure you want to reset your settings?' },
  226. // 调试
  227. 'scriptDebugTitle': { 'zh-cn': '调试', 'zh-hk': '偵錯', 'zh-tw': '偵錯', 'en': 'Debug' },
  228. 'scriptDebug': { 'zh-cn': '在控制台打印调试信息', 'zh-hk': '將偵錯訊息列印到主控台', 'zh-tw': '將偵錯訊息列印到主控台', 'en': 'Print debug info to console' },
  229. // 关于
  230. 'scriptAboutTitle': { 'zh-cn': '关于', 'zh-hk': '關於', 'zh-tw': '關於', 'en': 'About' },
  231. 'scriptAbout': {
  232. 'zh-cn': '<p>YAWF (Yet Another Weibo Filter) 使用 MIT 协议授权。<br />您可以访问<a href="https://github.com/tiansh/yawf">脚本主页</a>获取详细信息。<br />如果您在使用过程中遇到任何脚本的错误,或对脚本有任何建议,您可以到<a href="https://github.com/tiansh/yawf/issues">反馈页面</a>提供报告,或直接<a href="http://weibo.com/tsh90/weibo">私信作者</a>。</p><p>本脚本参考并使用了<a href="https://code.google.com/p/weibo-content-filter/">眼不见心不烦</a>脚本的部分代码。</p>',
  233. 'zh-hk': '<p>YAWF (Yet Another Weibo Filter) 使用 MIT 协议授权。<br />您可以访问<a href="https://github.com/tiansh/yawf">脚本主页</a>获取详细信息。<br />如果您在使用过程中遇到任何脚本的错误,或对脚本有任何建议,您可以到<a href="https://github.com/tiansh/yawf/issues">反馈页面</a>提供报告,或直接<a href="http://weibo.com/tsh90/weibo">私信作者</a>。</p><p>本脚本参考并使用了<a href="https://code.google.com/p/weibo-content-filter/">眼不见心不烦</a>脚本的部分代码。</p>',
  234. 'zh-tw': '<p>YAWF (Yet Another Weibo Filter) 使用 MIT 协议授权。<br />您可以访问<a href="https://github.com/tiansh/yawf">脚本主页</a>获取详细信息。<br />如果您在使用过程中遇到任何脚本的错误,或对脚本有任何建议,您可以到<a href="https://github.com/tiansh/yawf/issues">反馈页面</a>提供报告,或直接<a href="http://weibo.com/tsh90/weibo">私信作者</a>。</p><p>本脚本参考并使用了<a href="https://code.google.com/p/weibo-content-filter/">眼不见心不烦</a>脚本的部分代码。</p>',
  235. 'en': '<p>YAWF (Yet Another Weibo Filter) is under the MIT License.<br />You may visit <a href="https://github.com/tiansh/yawf">project host page</a> for more information.<br />If you find any bugs or have feature request, please report them in the <a href="https://github.com/tiansh/yawf/issues">feedback page</a>, or <a href="http://weibo.com/tsh90/weibo">send message to author</a>. </p><p>Some codes of this script come from <a href="https://code.google.com/p/weibo-content-filter/"><span lang="zh-cn">眼不见心不烦</span> (Weibo Content Filter)</a> script.</p>',
  236. },
  237. };
  238.  
  239. // 页面常量
  240. var html = {
  241. 'cover': '<div node-type="outer" style="position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; background: #000; opacity: 0.3; z-index: 10001;"></div>',
  242. 'dialog': '<div style="position: absolute; z-index: 10001;" node-type="outer" class="W_layer yawf-Layer" id="{{id}}"><div class="bg"><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td><div node-type="layoutContent" class="content"><div node-type="title" class="title"><span node-type="title_content">{{title}}</span></div><a node-type="close" title="{{closeButtonTitle}}" class="W_close" href="javascript:void(0);"></a><div node-type="inner"></div></div></td></tr></tbody></table></div></div>',
  243. 'alert': '<div style="position: absolute; z-index: 10001;" node-type="outer" class="W_layer yawf-Layer" id="{{id}}"><div class="bg"><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td><div node-type="layoutContent" class="content"><div node-type="title" class="title" style=""><span node-type="title_content">{{title}}</span></div><a node-type="close" title="{{closeButtonTitle}}" class="W_close" href="javascript:void(0);"></a><div node-type="inner"><div class="layer_point" node-type="outer"><dl class="point clearfix"><dt><span node-type="icon" class="icon_{{icon}}M"></span></dt><dd node-type="inner"><p node-type="textLarge" class="S_txt1">{{text}}</p><p node-type="textSmall" class="S_txt2"></p></dd></dl><div class="btn"><a node-type="OK" class="W_btn_a" href="javascript:void(0)"><span class="btn_30px W_f14">{{okButtonTitle}}</span></a></div></div></div></div></td></tr></tbody></table></div></div>',
  244. 'confirm': '<div style="position: absolute; z-index: 10001;" node-type="outer" class="W_layer yawf-Layer" id="{{id}}"><div class="bg"><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td><div node-type="layoutContent" class="content"><div node-type="title" class="title" style=""><span node-type="title_content">{{title}}</span></div><a node-type="close" title="{{closeButtonTitle}}" class="W_close" href="javascript:void(0);"></a><div node-type="inner"><div class="layer_point" node-type="outer"><dl class="point clearfix"><dt><span node-type="icon" class="icon_{{icon}}M"></span></dt><dd node-type="inner"><p node-type="textLarge" class="S_txt1">{{text}}</p><p node-type="textComplex" class="S_txt2" style="display: none;"></p><p node-type="textSmall" class="S_txt2" style="display: none;"></p></dd></dl><div class="btn"><a node-type="OK" class="W_btn_a" href="javascript:void(0)"><span class="btn_30px W_f14">{{okButtonTitle}}</span></a><a node-type="cancel" class="W_btn_b" href="javascript:void(0)"><span class="btn_30px W_f14">{{cancelButtonTitle}}</span></a></div></div></div></div></td></tr></tbody></table></div></div>',
  245. 'icon': '<div class="gn_setting" node-type="filter"><i><a class="gn_tab gn_filter" href="#"><span class="ico">{{filter}}</span></a></i></div>',
  246. 'configHeaderTop': '<div class="profile_tab S_line5 yawf-config-header" node-type="yawf-config-header"><ul class="pftb_ul S_line1">',
  247. 'configHeaderItem': '<li class="pftb_itm S_line1 {{liclass}}"><a class="pftb_lk S_line5 S_txt1 {{aclass}}" action-type="tab_item" onclick="return false;" href="javascript:void(0);">{{name}}</a>',
  248. 'configHeaderBottom': '</ul></div>',
  249. 'configLayerTop': '<div node-type="yawf-config-body" class="yawf-config-body">',
  250. 'configLayerItem': '<div class="{{name}} yawf-config-layer" node-type="{{name}}" style="display: none;"></div>',
  251. 'configLayerBottom': '</div>',
  252. 'configFooter': '',
  253. 'configSubtitle': '<div class="yawf-groupSubtitle">{{{text}}}</div>',
  254. 'configText': '<div class="yawf-groupText">{{{text}}}</div>',
  255. 'configBoolean': '<div class="yawf-configBoolean yawf-configItem"><label><input id="yawf-{{key}}" class="W_checkbox yawf-configBooleanInput" type="checkbox" name="yawf-{{key}}"><span class="yawf-configDesc yawf-configBooleanDesc">{{{text}}}</span></label></div>',
  256. 'configString': '<div class="yawf-configString yawf-configItem"><label><span>{{{text}}}</span><textarea id="yawf-{{key}}" class="W_input yawf-configStringInput" name="yawf-{{key}}"></label></div>',
  257. 'configStrings': '<div class="yawf-configStrings yawf-configItem"><form action="#"><label><span class="yawf-configDesc yawf-configStringsDesc">{{{text}}}</span><input id="yawf-{{key}}" class="W_input yawf-configStringsInput" type="text" name="yawf-{{key}}"></label><button id="yawf-add-{{key}}" class="W_btn_a yawf-configAdd" type="submit"><span>{{configStringsAdd}}</span></button></form><ul class="yawf-configStringsItems"></ul></div>',
  258. 'configStringsItem': '<li class="W_btn_arrow tag yawf-configStringsItem"><span>{{[item]}}<a class="W_ico12 icon_close" href="javascript:void(0);"></a></span></li>',
  259. 'configUsers': '<div class="yawf-configUsers yawf-configItem"><form action="#"><label><span class="yawf-configDesc yawf-configUsersDesc">{{{text}}}</span><input id="yawf-{{key}}" class="W_input yawf-configUsersInput" type="text" name="yawf-{{key}}"></label><button id="yawf-add-{{key}}" class="W_btn_a yawf-configAdd" type="submit"><span>{{configUsersAdd}}</span></button></form><ul class="yawf-configUsersItems"></ul></div>',
  260. 'configUsersItem': '<li class="yawf-configUsersItem"><div class="shield_object_card"><div class="card_bg clearfix"><div class="card_pic"><span class="pic"><img class="W_face_radius" width="50" height="50" alt="" src="{{avatar}}"></span></div><div class="card_content"><div class="object_info clearfix"><p class="W_fl"><span class="object_name" uid="{{id}}" title="{{name}}">{{name}}</span></p><p class="W_fr"><a class="W_ico12 icon_close" action-data="uid={{id}}" href="javascript:void(0);"></a></p></div><div class="other_info"></div></div></div></div></li>',
  261. 'configImportExport': '<div class="yawf-configImportExport yawf-configItem"><label><input type="file" style=" width: 1px; height: 1px; margin: 0 -1px 0 0; opacity: 0;" /><span node-type="import" class="W_btn_b" action-type="import"><span class="W_f14">{{configImportButton}}</span></span></label><a node-type="export" class="W_btn_b" action-type="export" href="javascript:;"><span class="W_f14">{{configExportButton}}</span></a><a node-type="reset" class="W_btn_b" action-type="reset" href="javascript:;"><span class="W_f14">{{configResetButton}}</span></a></div>',
  262. 'viewOriginalLink': '<a target="_blank" class="show_big" suda-data="key=tblog_newimage_feed&value=view_original" action-type="maximum" href="javascript:;"><em class="W_ico12 ico_showbig"></em>{{viewOriginalText}}</a><i class="W_vline">|</i>',
  263. 'colorInput': '<input type="color" class="W_f14" style="width: 40px;" />',
  264. 'numberInput': '<input type="number" class="W_f14" style="width: 60px;" />',
  265. 'transparencyInput': '<input type="number" min="0" max="100" maxlength="3" class="W_f14" style="width: 45px; text-align: right;" /><div class="yawf-transparency-range" style="background-color: #f0f0f0; background-color: -moz-dialog; position: relative; display: inline-block; margin-left: -66px; width: 81px; margin-right: -15px; -webkit-transform: rotate(270deg); transform: rotate(270deg); top: calc(-1em - 36px); box-shadow: 0px 12px #f0f0f0, 0px -12px #f0f0f0; box-shadow: 0px 12px -moz-dialog, 0px -12px -moz-dialog;"><input type="range" style="height: 1em; width: 66px; margin-left: 7px; margin-right: 7px; " tabindex="-1" /></div>',
  266. 'select': '<select>{{options}}</select>',
  267. 'option': '<option value="{{value}}">{{{text}}}</option>',
  268. };
  269.  
  270. var url = {
  271. 'newcard': 'http://weibo.com/aj/user/newcard?type=1&{{query}}&_t=1&callback={{callback}}',
  272. 'view_ori': 'http://photo.weibo.com/{{uid}}/wbphotos/large/mid/{{mid}}/pid/{{pid}}',
  273. 'block_wb': 'http://weibo.com/aj/user/block?_wv=5&__rnd={{rnd}}',
  274. };
  275.  
  276. // 微博过滤规则
  277. var rules = (function () {
  278. var list = [];
  279. var add = function (priority, rule) {
  280. list.push({ 'priority': priority, 'rule': rule });
  281. list.sort(function (x, y) { return y.priority - x.priority; });
  282. };
  283. var parse = function (feed) {
  284. var result = null;
  285. list.some(function (item) {
  286. try { result = item.rule(feed) || result; }
  287. catch (e) { debug('error while parsing rule %o: %o', item.rule, e); }
  288. if (result) debug('%o(%o) -> %s', item.rule, feed, result);
  289. return result;
  290. });
  291. return result;
  292. };
  293. return {
  294. 'add': add,
  295. 'parse': parse,
  296. };
  297. }());
  298.  
  299. // 根据用户界面上的语言做不同调整
  300. var i18n = (function () {
  301. var defaultLang = 'zh-cn';
  302. var lang = null;
  303. var pending = [];
  304. var chose = function (langObj) {
  305. langObj.local = langObj[lang] || langObj[defaultLang];
  306. };
  307. var langs = function (langObj) {
  308. pending.push(langObj);
  309. };
  310. var setLang = function (l) {
  311. lang = l;
  312. pending.map(chose);
  313. pending = [];
  314. i18n = chose;
  315. i18n.lang = l;
  316. };
  317. langs.setLang = setLang;
  318. return langs;
  319. }());
  320.  
  321. // 将字符串用&#dd的形式转义
  322. var escapeXml = function (s) {
  323. return s.replace(/./g, function (c) { return '&#' + c.charCodeAt(0); });
  324. };
  325.  
  326. // 以参数填充字符串
  327. var fillStr = function (base) {
  328. var argdatas = Array.apply(Array, arguments).slice(1);
  329. var datas = argdatas.concat([text]);
  330. return base.replace(/{{([\[{]?([a-zA-Z0-9_-]*)[\]}]?)}}/g, function (o, i, p) {
  331. var ret = null;
  332. datas.some(function (data) {
  333. if (p in data && typeof data[p] === 'string') ret = data[p];
  334. return ret !== null;
  335. });
  336. if (ret) {
  337. if (i[0] === '{') return fillStr.bind(this, ret).apply(null, argdatas);
  338. if (i[0] === '[') return escapeXml(ret);
  339. }
  340. return ret || o;
  341. });
  342. };
  343.  
  344. // 设置项
  345. var config = function (uid) {
  346. var config = {}, keys = [], onputs = [], storageKey = 'user' + uid + 'config';
  347. var tonputs = function (key, value, oldValue) {
  348. onputs.map(function (f) { f(key, value, oldValue); });
  349. };
  350. // 写入到内存
  351. var put = function (key, value) {
  352. if (keys.indexOf(key) === -1) return;
  353. tonputs(key, value, config[key]);
  354. config[key] = value;
  355. write();
  356. return value;
  357. };
  358. // 从内存读取
  359. var get = function (key, value, type) {
  360. if (!(key in config)) return value;
  361. var val = config[key];
  362. if (typeof val === 'undefined') return value;
  363. if (type && (val === null || val.constructor !== type)) return value;
  364. return val;
  365. };
  366. // 读取到内存
  367. var read = function () {
  368. try { config = JSON.parse(GM_getValue(storageKey, '{}')); }
  369. catch (e) { config = {}; }
  370. };
  371. // 从内存写出
  372. var write = function () {
  373. GM_setValue(storageKey, JSON.stringify(config));
  374. };
  375. // 当内存配置被修改时调用
  376. var onput = function (f) {
  377. onputs.push(f);
  378. };
  379. // 从字串导入
  380. var import_ = function (s) {
  381. try {
  382. clear();
  383. s = JSON.parse(s).conf;
  384. Object.keys(s).forEach(function (key) {
  385. put(key, s[key]);
  386. });
  387. write();
  388. return true;
  389. } catch (e) { }
  390. return false;
  391. };
  392. // 导出成为字串
  393. var export_ = function () {
  394. var info = GM_info || {}, script = info.script || {};
  395. return JSON.stringify({
  396. 'ua': navigator.userAgent,
  397. 'yawf': script.name,
  398. 'ver': script.version,
  399. 'gm': (info.scriptHandler || '') + info.version,
  400. 'conf': config,
  401. }, null, 2);
  402. };
  403. // 清空设置
  404. var clear = function () {
  405. config = {};
  406. tonputs();
  407. write();
  408. };
  409. // 注册键
  410. var reg = function (key) { keys.push(key); };
  411. // 初始化
  412. read();
  413. return {
  414. 'uid': uid,
  415. 'put': put, 'get': get, 'onput': onput,
  416. 'read': read, 'write': write,
  417. 'import': import_, 'export': export_,
  418. 'clear': clear,
  419. 'reg': reg,
  420. };
  421. };
  422.  
  423. var debug = !!GM_getValue('debug', false) ?
  424. console.log.bind(console) : function () { };
  425.  
  426. // 显示右上角过滤器图标
  427. var showIcon = function () {
  428. var p = document.querySelector('.WB_global_nav .gn_person');
  429. if (!p) return setTimeout(showIcon, 100);
  430. var d = cewih('div', html.icon).firstChild;
  431. p.appendChild(d);
  432. var f = document.querySelector('.gn_filter');
  433. f.addEventListener('click', function (e) {
  434. filters.showDialog();
  435. e.preventDefault();
  436. });
  437. };
  438.  
  439. // 对话框
  440. var Form = function (dom, display, details) {
  441. var ok = dom.querySelector('[node-type="OK"]');
  442. var cancel = dom.querySelector('[node-type="cancel"]');
  443. var close = dom.querySelector('[node-type="close"]');
  444. var title = dom.querySelector('.title');
  445. var mouse = null, pos;
  446. var setPos = function (pos) {
  447. var left = pos[0], top = pos[1];
  448. left = Math.min(Math.max(0, left), document.body.clientWidth - dom.clientWidth - 2);
  449. top = Math.min(Math.max(pageYOffset, top), pageYOffset + window.innerHeight - dom.clientHeight - 2);
  450. dom.style.left = left + 'px';
  451. dom.style.top = top + 'px';
  452. return [left, top];
  453. };
  454. var dragMove = function (e) {
  455. var mouse_new = [e.clientX, e.clientY];
  456. pos[0] += mouse_new[0] - mouse[0];
  457. pos[1] += mouse_new[1] - mouse[1];
  458. setPos(pos);
  459. mouse = mouse_new;
  460. };
  461. var dragMoveDone = function () {
  462. document.removeEventListener('mousemove', dragMove);
  463. document.removeEventListener('mouseup', dragMoveDone);
  464. dom.classList.remove('yawf-drag');
  465. if (dom.releaseCapture) { dom.releaseCapture(); }
  466. pos = setPos(pos);
  467. mouse = null;
  468. };
  469. if (title) {
  470. title.style.cursor = 'move';
  471. title.addEventListener('mousedown', function (e) {
  472. mouse = [e.clientX, e.clientY];
  473. document.addEventListener('mousemove', dragMove);
  474. document.addEventListener('mouseup', dragMoveDone);
  475. dom.classList.add('yawf-drag');
  476. if (dom.setCapture) { dom.setCapture(); }
  477. });
  478. }
  479. if (details.onOk) if (ok) ok.addEventListener('click', details.onOk);
  480. if (details.onCancel) {
  481. if (cancel) cancel.addEventListener('click', details.onCancel);
  482. if (close) close.addEventListener('click', details.onCancel);
  483. }
  484. var cover = cewih('div', html.cover).firstChild;
  485. var keys = function (e) {
  486. if (e.keyCode === 13) if (ok) ok.click();
  487. if (e.keyCode === 27) if (close) close.click();
  488. };
  489. var hide = function () {
  490. document.body.removeChild(dom);
  491. document.body.removeChild(cover);
  492. document.removeEventListener('keypress', keys);
  493. };
  494. var show = function (top, left) {
  495. document.body.appendChild(cover);
  496. document.body.appendChild(dom);
  497. if (top == null) top = (window.innerHeight - dom.clientHeight) / 2;
  498. if (left == null) left = (window.innerWidth - dom.clientWidth) / 2;
  499. pos = [left, top + pageYOffset];
  500. setPos(pos);
  501. document.addEventListener('keypress', keys);
  502. document.activeElement.blur();
  503. };
  504. if (display) show();
  505. if (ok) ok.addEventListener('click', hide);
  506. if (cancel) cancel.addEventListener('click', hide);
  507. if (close) close.addEventListener('click', hide);
  508. return {
  509. 'hide': hide,
  510. 'show': show,
  511. };
  512. };
  513.  
  514. // 显示一个对话框
  515. var Dialog = function (id, title, fillFun) {
  516. var dom = cewih('div', fillStr(html.dialog, { 'id': id, 'title': title })).firstChild;
  517. var form = Form(dom, false, {});
  518. fillFun(dom.querySelector('[node-type="inner"]'));
  519. return form;
  520. };
  521.  
  522. // 显示一个提示框
  523. var Alert = function (id, details) {
  524. var dom = cewih('div', fillStr(html.alert, { 'id': id, 'title': details.title, 'text': details.text, 'icon': details.icon || 'warn' })).firstChild;
  525. var form = Form(dom, true, details);
  526. return form;
  527. };
  528.  
  529. var Confirm = function (id, details) {
  530. var dom = cewih('div', fillStr(html.confirm, { 'id': id, 'title': details.title, 'text': details.text, 'icon': details.icon || 'question' })).firstChild;
  531. var form = Form(dom, true, details);
  532. return form;
  533. };
  534.  
  535. // 延迟调用函数
  536. var call = function (f) {
  537. setTimeout.bind(this, f, 0).apply(null, Array.apply(Array, arguments).slice(1));
  538. };
  539.  
  540. // 套上try-catch
  541. var withTry = function (f, fc) {
  542. return function () {
  543. try { f.apply(this, arguments); }
  544. catch (e) {
  545. debug('Exception while run %o: %o (%o)', f, e, e.stack);
  546. if (fc) fc(e);
  547. }
  548. };
  549. };
  550.  
  551. // 管理样式
  552. var css = (function () {
  553. var styleText = '';
  554. var fun = function (css) {
  555. return function () {
  556. if (this.conf) styleText += css + '\n';
  557. };
  558. };
  559. fun.init = function () { GM_addStyle(styleText); };
  560. fun.add = function (css) { styleText += css + '\n'; };
  561. return fun;
  562. }());
  563.  
  564. // 产生一个假的回调函数
  565. var dateStr = (function () {
  566. var last = 0;
  567. return function () {
  568. return '' + (last = Math.max(last + 1, Number(new Date())));
  569. };
  570. }());
  571.  
  572. // 维护账号信息,用于显示
  573. var account = (function () {
  574. var idCache = {}, nameCache = {};
  575. var request = function (queryStr, onsucc, onerror) {
  576. GM_xmlhttpRequest({
  577. 'method': 'GET',
  578. 'url': fillStr(url.newcard, { 'query': queryStr, 'callback': 'STK_' + dateStr() }),
  579. 'onload': withTry(function (resp) {
  580. var respJson = JSON.parse(resp.responseText.replace(/^try{[^{]*\(/, '').replace(/\)}catch\(e\){};$/, ''));
  581. var namecard = cewih('div', respJson.data);
  582. var avatar = namecard.querySelector('.name dt img').getAttribute('src');
  583. var name = namecard.querySelector('.name dd a[uid]').getAttribute('title');
  584. var uid = namecard.querySelector('.name dd a[uid]').getAttribute('uid');
  585. var data = { 'avatar': avatar, 'id': uid, 'name': name };
  586. nameCache[name] = idCache[uid] = data;
  587. onsucc(data);
  588. }, onerror),
  589. 'onerror': function () { onerror(); },
  590. });
  591. return queryStr;
  592. };
  593. var byId = function (id, onsucc, onerror) {
  594. if (idCache[id]) onsucc(idCache[id]);
  595. else request('id=' + id, onsucc, onerror);
  596. };
  597. var byName = function (name, onsucc, onerror) {
  598. if (nameCache[name]) onsucc(nameCache[name]);
  599. else request('name=' + encodeURIComponent(name), onsucc, onerror);
  600. };
  601. return { 'id': byId, 'name': byName };
  602. }());
  603.  
  604. // 过滤器管理器
  605. var filters = (function () {
  606. var list = [], preinit = true;
  607. var add = function (details) {
  608. list.push(details);
  609. if (!preinit) details.init();
  610. return details;
  611. };
  612. var init = function () {
  613. list.forEach(function (x) { x.init(); });
  614. preinit = false;
  615. };
  616. var dialog = null;
  617. var lastTab = 0;
  618. var dialogTabs = function (list, inner, page) {
  619. var alist = Array.apply(Array, inner.querySelectorAll('.yawf-config-header a'));
  620. var llist = Array.apply(Array, inner.querySelectorAll('.yawf-config-body .yawf-config-layer'));
  621. var choseLList = function (i) {
  622. llist.forEach(function (l) { l.style.display = 'none'; });
  623. alist.forEach(function (a) { a.classList.remove('current'); a.classList.remove('S_bg5'); a.classList.add('S_bg1'); });
  624. llist[i].innerHTML = ''; list[i].show(llist[i]); llist[i].style.display = 'block';
  625. alist[i].classList.add('current'); alist[i].classList.remove('S_bg1'); alist[i].classList.add('S_bg5');
  626. lastTab = i;
  627. };
  628. list.map(function (filter, i) {
  629. var a = alist[i];
  630. a.addEventListener('mousedown', function () { choseLList(i); });
  631. a.addEventListener('keydown', function () { choseLList(i); });
  632. });
  633. choseLList(page);
  634. };
  635. var showDialog = function (page, count) {
  636. var showDialogInner = function (inner) {
  637. inner.innerHTML = [html.configHeaderTop,
  638. list.map(function (filter, index) {
  639. return fillStr(html.configHeaderItem, {
  640. 'name': text[filter.name + 'Title'],
  641. 'aclass': index === 0 ? 'S_bg5 current' : 'S_bg1',
  642. 'liclass': index === list.length - 1 ? 'pftb_itm_lst' : ' ',
  643. });
  644. }).join(''),
  645. html.configHeaderBottom,
  646. html.configLayerTop,
  647. list.map(function (filter, index) {
  648. return fillStr(html.configLayerItem, {
  649. 'name': filter.name + 'Layer',
  650. });
  651. }).join(''),
  652. html.configLayerBottom,
  653. html.configFooter,
  654. ].join('');
  655. call(function () {
  656. dialog.show(0);
  657. });
  658. if (list.indexOf(page) === -1) dialogTabs(list, inner, lastTab);
  659. else dialogTabs(list, inner, list.indexOf(page));
  660. };
  661. if (!(dialog = Dialog('yawf-config', fillStr('{{configDialogTitle}}'), showDialogInner))) {
  662. if (!count || count < 100) setTimeout(showDialog, 100, page, (count || 0) + 1);
  663. }
  664. };
  665. return {
  666. 'add': add,
  667. 'init': init,
  668. 'showDialog': showDialog,
  669. };
  670. }());
  671.  
  672. var bindInputValue = function (input, obj, attr, standlize) {
  673. var onchange = function () {
  674. var val = input.value, valid;
  675. if (standlize) valid = standlize(val); else valid = val;
  676. if (String(valid) !== val) input.value = valid;
  677. obj['putconf' + attr](valid);
  678. };
  679. input.value = obj['getconf' + attr]();
  680. input.addEventListener('change', onchange);
  681. return onchange;
  682. };
  683.  
  684. // 告诉服务器屏蔽被隐藏的微博
  685. var blockWeibo = (function () {
  686. var buffer = [], busy = false;
  687. var delay = function () { return 3000 + Math.round(20 * Math.random()) * 100; };
  688. var block = function (mid, callback) {
  689. var done = function () { setTimeout(callback, delay()); };
  690. debug('blocking weibo %s', mid);
  691. GM_xmlhttpRequest({
  692. 'method': 'POST',
  693. 'url': fillStr(url.block_wb, { 'rnd': dateStr() }),
  694. 'headers': {
  695. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  696. 'Cache-Control': 'no-cache',
  697. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  698. 'Cookie': document.cookie,
  699. 'Referer': location.href,
  700. 'X-Requested-With': 'XMLHttpRequest',
  701. },
  702. 'data': 'filter_type=0&mid=' + mid + '&justhide=0&location=home&_t=0',
  703. 'onload': function (resp) { debug('block %s response: %s', mid, resp.responseText); done(); },
  704. 'onerror': function () { debug('block %s network error', mid); done(); },
  705. });
  706. };
  707. var active = function () {
  708. if (!(busy = !!buffer.length)) return;
  709. var mid = buffer.shift();
  710. block(mid, active);
  711. };
  712. return function (mid) {
  713. buffer.push(mid);
  714. if (!busy) active();
  715. return mid;
  716. };
  717. }());
  718.  
  719. // 检查是否有新的节点
  720. var newNode = (function () {
  721. var callbacks = [], actived = false;
  722. var callAll = function (mutation) {
  723. callbacks.forEach(function (c) { c(mutation); });
  724. };
  725. var observe = function () {
  726. callAll();
  727. (new MutationObserver(function (mutations) {
  728. mutations.forEach(function (mutation) { callAll(mutation); });
  729. })).observe(document.body, { 'childList': true, 'subtree': true });
  730. };
  731. var add = function (callback) {
  732. callbacks.push(withTry(callback));
  733. return callback;
  734. };
  735. var remove = function (callback) {
  736. var found = false;
  737. callbacks = callbacks.filter(function (x) {
  738. if (x === callback) return found = true; return false;
  739. });
  740. };
  741. var active = function () {
  742. if (actived) return;
  743. actived = true;
  744. observe();
  745. };
  746. return {
  747. 'add': add,
  748. 'remove': remove,
  749. 'active': active,
  750. };
  751. }());
  752.  
  753. // 添加点击后展开折叠消息的事件
  754. var fixFoldWeibo = (function () {
  755. var fixOne = withTry(function (feed) {
  756. var display = feed.getAttribute('yawf-display').replace(/fold$/g, 'unfold');
  757. var showFeed = function () {
  758. feed.setAttribute('yawf-display', display);
  759. feed.removeEventListener('click', showFeed);
  760. };
  761. var author = feed.querySelector('.WB_name[usercard]').getAttribute('title');
  762. feed.setAttribute('yawf-author', author);
  763. feed.addEventListener('click', showFeed);
  764. });
  765. var fix = function (feed) {
  766. var feeds = [feed].concat(Array.apply(Array, feed.querySelectorAll('.WB_feed_type')));
  767. feeds.forEach(function (feed) {
  768. if (feed.getAttribute('yawf-display').lastIndexOf('-fold') === -1) return;
  769. if (feed.getAttribute('yawf-author')) return;
  770. fixOne(feed);
  771. });
  772. };
  773. fix.init = function () {
  774. css.add(fillStr('[node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"]::before { content: {{foldedWeiboText}}; }'));
  775. };
  776. return fix;
  777. }());
  778.  
  779. var swapParentSonWeibo = function (parent, son) {
  780. var x = cewih('div', '');
  781. ['.WB_face', '.WB_info', '.WB_text', '.WB_func'].map(function (q) {
  782. (function (a, b) {
  783. b.parentNode.replaceChild(x, b);
  784. a.parentNode.replaceChild(b, a);
  785. x.parentNode.replaceChild(a, x);
  786. }(parent.querySelector(q), son.querySelector(q)));
  787. });
  788. var mid = parent.getAttribute('mid');
  789. parent.setAttribute('mid', son.getAttribute('mid'));
  790. son.setAttribute('mid', mid);
  791. // 各种细节的修补(原网站做的太乱了……)
  792. var pf = parent.querySelector('.WB_face'), sf = son.querySelector('.WB_face');
  793. var pfa = pf.querySelector('a'), pfi = pf.querySelector('img');
  794. var sfa = sf.querySelector('a'), sfi = sf.querySelector('img');
  795. if (pfa.href.indexOf('?') === -1) pfa.href += '?from=feed&loc=avatar';
  796. if (sfa.href.indexOf('?') !== -1) sfa.href = sfa.href.slice(0, sfa.href.indexOf('?'));
  797. if (!pfa.title) pfa.title = pfi.title;
  798. if (sfa.title) sfa.removeAttribute('title');
  799. sfi.width = sfi.height = '30'; pfi.width = pfi.height = '50';
  800. return son;
  801. };
  802.  
  803. // 如果有一个微博的子微博都隐藏了,那么就隐藏这个微博的子微博框
  804. var fixSonWeiboDisplay = function (feed) {
  805. if (!feed.querySelector('.WB_feed_together')) return fixFoldWeibo(feed);
  806. var sonList = Array.apply(Array, feed.querySelectorAll('.WB_feed_together .WB_sonFeed .WB_feed_type[yawf-display]'));
  807. // 交换两个子微博
  808. var swapSon = function (p, q) {
  809. var x = sonList[p], y = sonList[q];
  810. var fakeNode = document.createElement('div');
  811. x.parentNode.insertBefore(fakeNode, x);
  812. y.parentNode.insertBefore(x, y);
  813. fakeNode.parentNode.insertBefore(y, fakeNode);
  814. fakeNode.parentNode.removeChild(fakeNode);
  815. sonList[p] = y; sonList[q] = x;
  816. };
  817. // 把子微博重新排序一下,按照从想看到不想看的顺序排列,排序算法和一趟快排差不多
  818. var p = 0, q;
  819. ['show', 'unset', 'unfold', 'fold', 'hidden'].forEach(function (display) {
  820. q = sonList.length - 1;
  821. while (p < q) {
  822. if (sonList[p].getAttribute('yawf-display').lastIndexOf(display) !== -1) p++;
  823. else if (sonList[q].getAttribute('yawf-display').lastIndexOf(display) === -1) q--;
  824. else swapSon(p, q);
  825. }
  826. });
  827. // 看看还有多少显示出来的子微博,更新一下子微博的计数
  828. var sonCount = feed.querySelectorAll('.WB_feed_together .WB_sonFeed .WB_feed_type:not([yawf-display$="-hidden"])').length;
  829. if (sonCount === 0) feed.querySelector('.WB_feed_together').setAttribute('yawf-display', 'display-hidden');
  830. else feed.querySelector('[node-type="followNum"]').textContent = sonCount;
  831. // 如果下面更多的按钮已经没用了,就藏起来吧
  832. var foldSonCount = feed.querySelectorAll('[node-type="feed_list_wrapForward"] .WB_feed_type:not([yawf-display$="-hidden"])').length;
  833. if (foldSonCount === 0 && feed.querySelector('[node-type="feed_list_wrapForward"]')) {
  834. feed.querySelector('.WB_feed_together').setAttribute('yawf-sonfold', 'display');
  835. }
  836. // 把原始微博和子微博拆开
  837. var another = feed.cloneNode(true);
  838. feed.parentNode.insertBefore(another, feed.nextSibling);
  839. feed.setAttribute('yawf-withson', 'son');
  840. another.setAttribute('yawf-display', 'display-son');
  841. fixFoldWeibo(feed);
  842. fixFoldWeibo(another);
  843. };
  844.  
  845. var weiboFilter = function () {
  846. var feeds = Array.apply(Array,
  847. document.querySelectorAll('[node-type="feed_list"] .WB_feed_type:not([yawf-display])'));
  848. feeds.forEach(function (feed) {
  849. // 同源合并的微博
  850. var sonFeeds = Array.apply(Array, feed.querySelectorAll('[node-type="feed_list"] .WB_feed_type:not([yawf-display])'));
  851. var action = null, parentAction = null;
  852. var needSwap = function (action) {
  853. if (!sonFeeds.length) return false;
  854. if (['hidden', 'fold'].indexOf(action) === -1) return false;
  855. return true;
  856. };
  857. var setAction = function (feed, action) {
  858. feed.setAttribute('yawf-display', 'display-' + action);
  859. };
  860. while (true) {
  861. action = rules.parse(feed) || 'unset';
  862. // 如果父微博被屏蔽或折叠,那么就把下面一条没被屏蔽的拉上来换个位置
  863. if (!needSwap(action)) break;
  864. setAction(swapParentSonWeibo(feed, sonFeeds.pop()), action);
  865. }
  866. parentAction = action;
  867. // 最后处理所有下面的子微博
  868. var fixSonWeibo = function (son) {
  869. var action = rules.parse(son) || 'unset';
  870. setAction(son, action);
  871. // 如果一列里面有白名单的,那么把白名单的特别换到外面去
  872. if (parentAction !== 'show' && action === 'show') {
  873. setAction(swapParentSonWeibo(feed, son), parentAction);
  874. parentAction = action;
  875. }
  876. };
  877. while (sonFeeds.length) fixSonWeibo(sonFeeds.shift());
  878. setAction(feed, parentAction);
  879. fixSonWeiboDisplay(feed);
  880. });
  881. return feeds;
  882. };
  883.  
  884. var addWeiboFilterListener = (function () {
  885. var listeners = [];
  886. // 逐条进行过滤
  887. newNode.add(function () {
  888. var feeds = weiboFilter();
  889. feeds.forEach(function (feed) {
  890. listeners.forEach(function (f) { f(feed); });
  891. });
  892. });
  893. return function (callback) {
  894. listeners.push(withTry(callback));
  895. };
  896. }());
  897.  
  898. var typedConfig = (function () {
  899. var inits = [];
  900. // 字符串
  901. var baseConfig = function (type) {
  902. return function (key) {
  903. return function (item) {
  904. var skey = item.key + (key ? '.' + key : key);
  905. if (!item['getconf' + key]) item['getconf' + key] = function () {
  906. return item['conf' + key] = config.get(skey, item['default' + key] || type(), type);
  907. };
  908. if (!item['putconf' + key]) item['putconf' + key] = function (conf) {
  909. return config.put(skey, item['conf' + key] = conf);
  910. };
  911. inits.push(function () {
  912. config.reg(skey);
  913. item['putconf' + key](item['getconf' + key]());
  914. });
  915. };
  916. };
  917. };
  918. var init = function () {
  919. while (inits.length) inits.shift()();
  920. };
  921. init.string = baseConfig(String);
  922. init.strings = baseConfig(Array);
  923. init.boolean = baseConfig(Boolean);
  924. init.users = baseConfig(Array);
  925. init.number = baseConfig(Number);
  926. return init;
  927. }());
  928.  
  929. // 根据不同类型生成带有事件的文档节点
  930. var typedHtml = (function () {
  931. // 副标题
  932. var subtitle = function (item) {
  933. return cewih('div', fillStr(html.configSubtitle, item)).firstChild;
  934. };
  935.  
  936. // 文本
  937. var text = function (item) {
  938. return cewih('div', fillStr(html.configText, item)).firstChild;
  939. };
  940.  
  941. // 真假值的设置项
  942. var boolean = function (item) {
  943. var dom = cewih('div', fillStr(html.configBoolean, item)).firstChild;
  944. var input = dom.querySelector('input');
  945. input.checked = item.getconf();
  946. input.addEventListener('change', function () {
  947. item.putconf(input.checked);
  948. });
  949. return dom;
  950. };
  951.  
  952. // 字符串的设置项
  953. var string = function (item) {
  954. var dom = cewih('div', fillStr(html.configString, item)).firstChild;
  955. var textarea = dom.querySelector('textarea');
  956. textarea.value = item.getconf();
  957. textarea.addEventListener('change', function () { item.putconf(textarea.value); });
  958. textarea.addEventListener('keypress', function () { item.putconf(textarea.value); });
  959. return dom;
  960. };
  961.  
  962. // 字符串数组设置项模板
  963. var items = function (base, genli, item) {
  964. var dom = cewih('div', fillStr(base, item)).firstChild;
  965. var form = dom.querySelector('form'), input = dom.querySelector('input'), ul = dom.querySelector('ul');
  966. var shown = {};
  967. // 将某个已经有的字符串显示到末尾
  968. var moveToEnd = function (x) {
  969. var p = x.parentNode; p.appendChild(p.removeChild(x));
  970. };
  971. // 显示一个新的字符串
  972. var showStrings = function (userinput, str, onsucc, ondone) {
  973. genli(item, userinput, str, function (str, li) {
  974. if (ondone) ondone();
  975. if (!str || !li) return;
  976. if (shown[str]) return moveToEnd(shown[str]);
  977. var del = li.querySelector('a.icon_close');
  978. del.addEventListener('click', function () {
  979. delete shown[str];
  980. if (item.del) item.del(str);
  981. li.parentNode.removeChild(li);
  982. item.putconf(item.getconf().filter(function (x) { return x !== str; }));
  983. });
  984. ul.appendChild(shown[str] = li);
  985. if (onsucc) onsucc(str);
  986. });
  987. };
  988. item.getconf().forEach(function (str) { showStrings(false, str); });
  989. form.addEventListener('submit', function (e) {
  990. e.preventDefault();
  991. var str = input.value;
  992. input.disabled = true;
  993. showStrings(true, str, function (str) {
  994. item.getconf();
  995. item.conf.push(str);
  996. item.putconf(item.conf);
  997. }, function () {
  998. input.value = '';
  999. input.disabled = false;
  1000. });
  1001. });
  1002. return dom;
  1003. };
  1004.  
  1005. // 字符串设置项
  1006. var strings = items.bind(null, html.configStrings, function (item, userinput, str, callback) {
  1007. if (userinput && item.add && !(str = item.add(str))) callback();
  1008. else callback(str, cewih('ul', fillStr(html.configStringsItem, { 'item': item.display ? item.display(str) : str })).firstChild);
  1009. });
  1010.  
  1011. // 用户列表的设置项
  1012. var users = items.bind(null, html.configUsers, function (item, userinput, str, callback) {
  1013. var showUserNotExistError = function () {
  1014. Alert('yawf-user-not-exist', {
  1015. 'title': fillStr('{{accountNotExistErrorTitle}}'),
  1016. 'text': fillStr('{{{accountNotExistError}}}', { 'name': escapeXml(str) }),
  1017. 'icon': 'error'
  1018. });
  1019. callback();
  1020. };
  1021. if (userinput) {
  1022. if (!(str = str.trim().replace(/^@/, ''))) return callback();
  1023. account.name(str, function (info) {
  1024. if (!info) showUserNotExistError();
  1025. else if (item.add && !item.add(info)) callback();
  1026. else callback(info.id, cewih('ul', fillStr(html.configUsersItem, info)).firstChild);
  1027. }, showUserNotExistError);
  1028. } else {
  1029. var emptyInfo = { 'id': str, 'name': ' ', 'avatar': ' ' };
  1030. var li = cewih('ul', fillStr(html.configUsersItem, emptyInfo)).firstChild;
  1031. callback(str, li);
  1032. account.id(str, function (info) {
  1033. var u = li.querySelector('[uid]');
  1034. u.setAttribute('uid', info.id); u.setAttribute('title', info.name); u.textContent = info.name;
  1035. var p = li.querySelector('.pic img');
  1036. p.src = info.avatar;
  1037. });
  1038. }
  1039. });
  1040.  
  1041. return {
  1042. 'subtitle': subtitle,
  1043. 'text': text,
  1044. 'string': string,
  1045. 'strings': strings,
  1046. 'boolean': boolean,
  1047. 'users': users,
  1048. };
  1049. }());
  1050.  
  1051. // 过滤器组
  1052. var filterGroup = function (groupName) {
  1053. var items = [];
  1054. // 向过滤器组里面添加一个项目
  1055. var add = function (item) {
  1056. items.push(item);
  1057. try {
  1058. if (item.type && typedConfig[item.type])
  1059. typedConfig[item.type]('')(item);
  1060. if (item.keys) Object.keys(item.keys).forEach(function (key) {
  1061. if (typedConfig[item.keys[key]]) typedConfig[item.keys[key]](key)(item);
  1062. });
  1063. } catch (e) { }
  1064. return item;
  1065. };
  1066. // 网页被初始化时初始化所有过滤器
  1067. var init = function () {
  1068. items.forEach(withTry(function (item) {
  1069. if (item.init) item.init();
  1070. if (item.rule) rules.add(item.priority || 0, item.rule.bind(item));
  1071. }));
  1072. };
  1073. // 需要显示选项时生成界面
  1074. var show = function (inner) {
  1075. items.forEach(withTry(function (item) {
  1076. var dom = null;
  1077. if (item.show) dom = item.show(dom);
  1078. else if (item.type && typedHtml[item.type])
  1079. dom = typedHtml[item.type](item);
  1080. if (dom && item.shown) item.shown(dom);
  1081. if (dom) inner.appendChild(dom);
  1082. }));
  1083. };
  1084. // 注册到过滤器分组
  1085. var group = {
  1086. 'name': groupName,
  1087. 'show': show,
  1088. 'init': init,
  1089. 'add': add
  1090. };
  1091. return filters.add(group);
  1092. };
  1093.  
  1094. var onGroupPage = function () {
  1095. return location.pathname.slice(-9) === '/mygroups';
  1096. };
  1097.  
  1098. var allInOneFilters = function (details) {
  1099. var filters = [
  1100. { 'type': 'whitelist', 'priority': 1e5, 'action': 'show' },
  1101. { 'type': 'blacklist', 'priority': 0, 'action': 'hidden' },
  1102. { 'type': 'foldlist', 'priority': -1e5, 'action': 'fold' },
  1103. ];
  1104. var typedFilterGroup = filterGroup(details.name + 'FilterGroup');
  1105. filters.forEach(function (filter) {
  1106. typedFilterGroup.add({
  1107. 'type': 'subtitle',
  1108. 'text': '{{{' + filter.type + 'FilterDesc}}}',
  1109. 'typed': '{{' + details.name + 'FilterDetails}}',
  1110. });
  1111. var rule = {
  1112. 'type': details.type || 'strings',
  1113. 'key': 'weibo.filters.' + details.name + '.' + filter.type,
  1114. 'priority': filter.priority,
  1115. 'text': '{{' + details.name + 'FilterDesc}}',
  1116. };
  1117. if (details.add) rule.add = details.add.bind(rule);
  1118. if (details.display) rule.display = details.display.bind(rule);
  1119. rule.rule = details.rule.bind(rule, filter.action);
  1120. if (details[filter.type]) {
  1121. Object.keys(details[filter.type]).forEach(function (override) {
  1122. rule[override] = details[filter.type][override](rule[override]);
  1123. });
  1124. }
  1125. typedFilterGroup.add(rule);
  1126. });
  1127. return typedFilterGroup;
  1128. };
  1129.  
  1130. var weiboContentSelector = function (feed, f) {
  1131. var content = feed.querySelector('[node-type="feed_list_content"]');
  1132. var reason = feed.querySelector('[node-type="feed_list_reason"] em');
  1133. var items = [];
  1134. if (content) items = items.concat(Array.apply(Array, f(content)));
  1135. if (reason) items = items.concat(Array.apply(Array, f(reason)));
  1136. return items;
  1137. };
  1138.  
  1139. // 关键字过滤
  1140. var keywordFilterGroup = allInOneFilters({
  1141. 'name': 'keyword',
  1142. 'add': function (s) { return s.trim(); },
  1143. 'rule': function keywordMatch(action, feed) {
  1144. var keywords = this.conf;
  1145. var texts = weiboContentSelector(feed, function (m) {
  1146. return Array.apply(Array, m.childNodes)
  1147. .filter(function (node) { return node.nodeType === Node.TEXT_NODE; })
  1148. .map(function (node) { return node.textContent; });
  1149. }).join(' ').toUpperCase();
  1150. var match = keywords.some(function (keyword) { return texts.indexOf(keyword.toUpperCase()) !== -1; });
  1151. if (match) return action; else return null;
  1152. },
  1153. });
  1154.  
  1155. // 按照正则式过滤
  1156. var regexpFilterGroup = allInOneFilters({
  1157. 'name': 'regexp',
  1158. 'add': function (s) {
  1159. s = s.trim();
  1160. if (s[0] === '/' && s[s.length - 1] === '/') s = s.slice(1, -1);
  1161. try { RegExp(s).exec(''); } catch (e) {
  1162. Alert('yawf-regexp-bad-formed', {
  1163. 'title': fillStr('{{regexpBadFormedTitle}}'),
  1164. 'text': fillStr('{{{regexpBadFormed}}}', { 'regexp': escapeXml(s) }),
  1165. 'icon': 'error'
  1166. });
  1167. s = null;
  1168. }
  1169. return s;
  1170. },
  1171. 'display': function (s) { return '/' + s + '/'; },
  1172. 'rule': function regexpMatch(action, feed) {
  1173. if (!this.regexen) this.regexen = this.conf.map(function (s) {
  1174. try { return RegExp(s); }
  1175. catch (e) { debug('erorr while compile regexp %s : %o', s, e); }
  1176. }).filter(function (x) { return x; });
  1177. var regexen = this.regexen;
  1178. var texts = weiboContentSelector(feed, function (m) {
  1179. return Array.apply(Array, m.childNodes)
  1180. .filter(function (node) { return node.nodeType === Node.TEXT_NODE; })
  1181. .map(function (node) { return node.textContent; });
  1182. }).join(' ');
  1183. var match = regexen.some(function (regexp) {
  1184. return !!(regexp.exec(texts));
  1185. });
  1186. if (match) return action; else return null;
  1187. },
  1188. });
  1189.  
  1190. // 从一条微博中找到他的作者
  1191. var getFeedAuthorId = function (feed) {
  1192. var author = feed.querySelector('.WB_name[usercard]');
  1193. if (!author) return null;
  1194. return author.getAttribute('usercard').split('=')[1];
  1195. };
  1196.  
  1197. // 作者用户过滤
  1198. var accountFilterGroup = allInOneFilters({
  1199. 'name': 'account',
  1200. 'type': 'users',
  1201. 'rule': function accountMatch(action, feed) {
  1202. var accounts = this.conf, id = getFeedAuthorId(feed);
  1203. if (!id) return null;
  1204. var match = accounts.some(function (x) { return x === id; });
  1205. if (match) return action; else return null;
  1206. },
  1207. 'blacklist': {
  1208. 'rule': function accountMatchBlacklistOverride(_super) {
  1209. return function accountMatchBlacklist(feed) {
  1210. if (!accountByGroup.conf || !onGroupPage()) return _super(feed);
  1211. return null;
  1212. };
  1213. },
  1214. },
  1215. });
  1216.  
  1217. // 从一条微博中找到他的作者
  1218. var getFeedOriginalId = function (feed) {
  1219. var originalAuthor = feed.querySelector('.WB_media_expand .WB_info .WB_name');
  1220. if (!originalAuthor) return null;
  1221. return originalAuthor.getAttribute('usercard').split('=')[1];
  1222. };
  1223.  
  1224. // 原创用户过滤
  1225. var originalFilterGroup = allInOneFilters({
  1226. 'name': 'original',
  1227. 'type': 'users',
  1228. 'rule': function originalMatch(action, feed) {
  1229. var originals = this.conf, id = getFeedOriginalId(feed);
  1230. if (!id) return null;
  1231. var match = originals.some(function (x) { return x === id; });
  1232. if (match) return action; else return null;
  1233. },
  1234. });
  1235.  
  1236. // 找到在一条微博里面被提到的人的昵称
  1237. var getFeedMentionList = function (feed) {
  1238. return weiboContentSelector(feed, function (m) {
  1239. return Array.apply(Array, m.querySelectorAll('a[usercard^="name="][href$="loc=at"]'));
  1240. }).map(function (link) {
  1241. return link.getAttribute('usercard').slice('name='.length);
  1242. });
  1243. };
  1244.  
  1245. // 提到某人的微博
  1246. var mentionFilterGroup = allInOneFilters({
  1247. 'name': 'mention',
  1248. 'type': 'strings',
  1249. 'add': function (s) { return s.trim().replace(/^@/, ''); },
  1250. 'display': function (s) { return '@' + s; },
  1251. 'rule': function mentionMatch(action, feed) {
  1252. var mentions = this.conf, users = getFeedMentionList(feed);
  1253. var match = users.some(function (name) {
  1254. return mentions.indexOf(name) !== -1;
  1255. });
  1256. if (match) return action; else return null;
  1257. },
  1258. });
  1259.  
  1260. var getFeedTopicList = function (feed) {
  1261. return weiboContentSelector(feed, function (m) {
  1262. return Array.apply(Array, m.querySelectorAll('.a_topic'));
  1263. }).map(function (topic) { return topic.textContent; });
  1264. };
  1265.  
  1266. // 话题过滤
  1267. var topicFilterGroup = allInOneFilters({
  1268. 'name': 'topic',
  1269. 'add': function (s) { return s.trim().replace(/#/g, ''); },
  1270. 'display': function (s) { return '#' + s + '#'; },
  1271. 'rule': function topicMatch(action, feed) {
  1272. var topics = this.conf;
  1273. var text = getFeedTopicList(feed).join('##');
  1274. var match = topics.some(function (topic) { return text.indexOf(topic) !== -1; });
  1275. if (match) return action; else return null;
  1276. },
  1277. });
  1278.  
  1279. // 获取一条微博的所有来源(包括转发)
  1280. var getFeedSourceList = function (feed) {
  1281. return ['[node-type="feed_list_funcLink"] [action-type="app_source"]',
  1282. '.WB_media_expand [action-type="app_source"]'].map(function (qs) {
  1283. var st = feed.querySelector(qs); if (!st) return null;
  1284. return st.getAttribute('title') || st.textContent || '未通过审核应用';
  1285. }).filter(function (x) { return x; });
  1286. };
  1287.  
  1288. // 来源过滤
  1289. var sourceFilterGroup = allInOneFilters({
  1290. 'name': 'source',
  1291. 'add': function (s) {
  1292. s = s.trim();
  1293. if (s === '微博 weibo.com') {
  1294. Alert('yawf-source-filter-warning', {
  1295. 'title': fillStr('{{sourceFilterWarningTitle}}'),
  1296. 'text': fillStr('{{sourceFilterWarning}}'),
  1297. 'icon': 'error'
  1298. });
  1299. s = null;
  1300. }
  1301. return s;
  1302. },
  1303. 'rule': function sourceMatch(action, feed) {
  1304. var sources = this.conf, _sources = getFeedSourceList(feed);
  1305. var match = _sources.some(function (s) { return sources.indexOf(s) !== -1; })
  1306. if (match) return action; else return null;
  1307. },
  1308. });
  1309.  
  1310. var getFeedHyperlinkList = function (feed) {
  1311. return Array.apply(Array, feed.querySelectorAll('a[title]')).map(function (a) {
  1312. return a.getAttribute('title');
  1313. });
  1314. };
  1315.  
  1316. // 超链接过滤
  1317. var hyperlinkFilterGroup = allInOneFilters({
  1318. 'name': 'hyperlink',
  1319. 'add': function (s) { return s.trim(); },
  1320. 'rule': function hyperlinkMatch(action, feed) {
  1321. var links = this.conf, _links = getFeedHyperlinkList(feed);
  1322. var match = _links.some(function (l) {
  1323. return links.some(function (link) {
  1324. return l.toUpperCase().indexOf(link.toUpperCase()) !== -1;
  1325. });
  1326. });
  1327. if (match) return action; else return null;
  1328. },
  1329. });
  1330.  
  1331. var otherFilterGroup = filterGroup('otherFilterGroup');
  1332.  
  1333. otherFilterGroup.add({
  1334. 'type': 'subtitle',
  1335. 'text': '{{otherWhitelistTitle}}'
  1336. });
  1337.  
  1338. // 总是显示自己的微博
  1339. otherFilterGroup.add({
  1340. 'type': 'boolean',
  1341. 'key': 'weibo.other.my_weibo',
  1342. 'text': '{{showMyWeiboDesc}}',
  1343. 'priority': 1e5 - 1e3, // 略低于白名单,但高于其他
  1344. 'rule': function showMyWeiboRule(feed) {
  1345. if (!this.conf) return;
  1346. if (getFeedAuthorId(feed) === config.uid) return 'showme'; else return null;
  1347. },
  1348. });
  1349.  
  1350. // 总是显示自己原创的微博
  1351. otherFilterGroup.add({
  1352. 'type': 'boolean',
  1353. 'key': 'weibo.other.my_original',
  1354. 'text': '{{showMyOriginalDesc}}',
  1355. 'priority': 1e5 - 1e3, // 略低于白名单,但高于其他
  1356. 'rule': function showMyOriginalRule(feed) {
  1357. if (!this.conf) return;
  1358. if (getFeedOriginalId(feed) === config.uid) return 'showme'; else return null;
  1359. },
  1360. });
  1361.  
  1362. // 总是显示自己原创的微博
  1363. otherFilterGroup.add({
  1364. 'type': 'boolean',
  1365. 'key': 'weibo.other.mention_me',
  1366. 'text': '{{showMentionMeDesc}}',
  1367. 'priority': 1e5 - 1e3, // 略低于白名单,但高于其他
  1368. 'rule': function showMentionMeRule(feed) {
  1369. if (!this.conf) return;
  1370. if (getFeedMentionList(feed).indexOf(config.uid) !== -1) return 'showme'; else return null;
  1371. },
  1372. });
  1373.  
  1374. otherFilterGroup.add({
  1375. 'type': 'subtitle',
  1376. 'text': '{{otherBlacklistTitle}}'
  1377. });
  1378.  
  1379. // 推广微博
  1380. otherFilterGroup.add({
  1381. 'type': 'boolean',
  1382. 'key': 'weibo.other.ad_feed',
  1383. 'text': '{{adfeedFilterDesc}}',
  1384. 'rule': function adFeedFilterRule(feed) {
  1385. if (!this.conf) return null;
  1386. return feed.getAttribute('feedtype') === 'ad' ? 'hidden' : null;
  1387. },
  1388. });
  1389.  
  1390. // 关注推荐微博
  1391. otherFilterGroup.add({
  1392. 'type': 'boolean',
  1393. 'key': 'weibo.other.fake_weibo',
  1394. 'text': '{{fakeWeiboFilterDesc}}',
  1395. 'rule': function fakeWeiboFilterRule(feed) {
  1396. if (!this.conf) return null;
  1397. if (!feed.getAttribute('mid')) return 'hidden';
  1398. return null;
  1399. },
  1400. });
  1401.  
  1402. // 已删除或没有权限查看的微博的转发
  1403. otherFilterGroup.add({
  1404. 'type': 'boolean',
  1405. 'key': 'weibo.other.deleted_forward',
  1406. 'text': '{{deletedForwardFilterDesc}}',
  1407. 'rule': function deletedForwardFilterRule(feed) {
  1408. if (!this.conf) return null;
  1409. if (feed.getAttribute('isforward') === '1' &&
  1410. !feed.querySelector('.WB_media_expand .WB_info .WB_name')) return 'hidden';
  1411. return null;
  1412. },
  1413. });
  1414.  
  1415. // 投票微博
  1416. otherFilterGroup.add({
  1417. 'type': 'boolean',
  1418. 'key': 'weibo.other.vote_weibo',
  1419. 'text': '{{voteWeiboFilterDesc}}',
  1420. 'rule': function voteWeiboFilterRule(feed) {
  1421. if (!this.conf) return null;
  1422. if (feed.querySelector('.WB_from a[href^="http://vote.weibo.com/"]'))
  1423. return 'hidden';
  1424. return null;
  1425. },
  1426. });
  1427.  
  1428. otherFilterGroup.add({
  1429. 'type': 'subtitle',
  1430. 'text': '{{otherSpammingTitle}}',
  1431. });
  1432.  
  1433. // 添加数量和折叠/隐藏的
  1434. var lotShown = function (dom) {
  1435. var nl = cewih('label', fillStr(text.sameNumberOptionDesc, { 'number': html.numberInput }));
  1436. var sl = cewih('label', fillStr(text.sameActionOptionDesc, {
  1437. 'select': html.select,
  1438. 'options': fillStr(html.option, { 'value': 'fold', 'text': '{{foldlistActionDesc}}' }) +
  1439. fillStr(html.option, { 'value': 'hidden', 'text': '{{blacklistActionDesc}}' }),
  1440. }));
  1441. var n = nl.querySelector('input'), s = sl.querySelector('select');
  1442. n.setAttribute('min', '1');
  1443. bindInputValue(n, this, 'number', function (val) {
  1444. if (isNaN(val)) val = 1; else val = parseInt(val);
  1445. return Math.max(val, 1);
  1446. });
  1447. bindInputValue(s, this, 'action');
  1448. dom.appendChild(nl); dom.appendChild(sl);
  1449. };
  1450.  
  1451. // 相同账号的过多微博
  1452. otherFilterGroup.add({
  1453. 'type': 'boolean',
  1454. 'priority': -1e6, // 低优先级
  1455. 'key': 'weibo.other.same_account',
  1456. 'keys': { 'number': 'number', 'action': 'string' },
  1457. 'defaultnumber': 5,
  1458. 'defaultaction': 'fold',
  1459. 'text': '{{sameAccountFilterDesc}}',
  1460. 'shown': lotShown,
  1461. 'rule': function sameAccountRule(feed) {
  1462. if (!this.conf) return null;
  1463. if (sameAccountByGroup.conf && onGroupPage()) return null;
  1464. var author = feed.querySelector('.WB_name[usercard]');
  1465. if (!author) return null;
  1466. var id = author.getAttribute('usercard').split('=')[1];
  1467. var number = document.querySelectorAll('[node-type="feed_list"] ' +
  1468. '.WB_feed_type[yawf-display]:not([yawf-display$="-fold"]):not([yawf-display$="-unfold"]):not([yawf-display$="-hidden"])' +
  1469. '>.WB_feed_datail>.WB_detail>.WB_info>a.WB_name[usercard="id=' + id + '"]').length;
  1470. if (number >= this.confnumber) return 'account-' + this.confaction; else return null;
  1471. },
  1472. });
  1473.  
  1474. // 相同微博的过多转发
  1475. otherFilterGroup.add({
  1476. 'type': 'boolean',
  1477. 'priority': -1e6, // 低优先级
  1478. 'key': 'weibo.other.same_forward',
  1479. 'keys': { 'number': 'number', 'action': 'string' },
  1480. 'defaultnumber': 3,
  1481. 'defaultaction': 'fold',
  1482. 'text': '{{sameForwardFilterDesc}}',
  1483. 'shown': lotShown,
  1484. 'rule': function sameForwardRule(feed) {
  1485. if (!this.conf) return null;
  1486. var omid = feed.getAttribute('omid');
  1487. if (!omid) return null;
  1488. var number = document.querySelectorAll('[node-type="feed_list"] ' +
  1489. '.WB_feed_type[omid="' + omid + '"][yawf-display]:not([yawf-display$="-fold"]):not([yawf-display$="-unfold"]):not([yawf-display$="-hidden"])').length;
  1490. if (number >= this.confnumber) return 'forward-' + this.confaction; else return null;
  1491. },
  1492. });
  1493.  
  1494. // 分组浏览
  1495. otherFilterGroup.add({
  1496. 'type': 'subtitle',
  1497. 'text': '{{otherGroupTitle}}',
  1498. });
  1499.  
  1500. // 分组浏览不做按帐号隐藏
  1501. var accountByGroup = otherFilterGroup.add({
  1502. 'type': 'boolean',
  1503. 'key': 'weibo.other.group_account',
  1504. 'text': '{{accountByGroup}}',
  1505. });
  1506.  
  1507. // 分组浏览不做刷屏检查
  1508. var sameAccountByGroup = otherFilterGroup.add({
  1509. 'type': 'boolean',
  1510. 'key': 'weibo.other.group_same_account',
  1511. 'text': '{{sameAccountByGroup}}',
  1512. });
  1513.  
  1514.  
  1515. var layoutFilterGroup = filterGroup('layoutFilterGroup');
  1516.  
  1517. layoutFilterGroup.add({
  1518. 'type': 'subtitle',
  1519. 'text': '{{layoutFilterGroupDesc}}',
  1520. });
  1521.  
  1522. // 大部分选择器参考了 眼不见心不烦 脚本
  1523. var layouts = (function () {
  1524. var current = null;
  1525. var subtitle = function (name) {
  1526. layoutFilterGroup.add({
  1527. 'type': 'subtitle',
  1528. 'text': '{{layoutHide' + name + '}}',
  1529. });
  1530. current = name;
  1531. };
  1532.  
  1533. var item = function (name, cssText, defaultValue) {
  1534. layoutFilterGroup.add({
  1535. 'type': 'boolean',
  1536. 'key': 'weibo.layoutHide' + current + name,
  1537. 'default': defaultValue || false,
  1538. 'text': '{{layoutHide' + current + name + '}}',
  1539. 'init': css(cssText),
  1540. });
  1541. };
  1542.  
  1543. subtitle('Icon');
  1544. item('Level', '.icon_bed[node-type="level"] { display: none !important; }');
  1545. item('Member', '.W_ico16[class*="ico_member"], .ico_member_dis { display: none !important; }');
  1546. item('Approve', '.approve { display: none !important; }');
  1547. item('ApproveCo', '.approve_co { display: none !important; }');
  1548. item('Club', '.ico_club { display: none !important; }');
  1549. item('VGirl', '.ico_vlady { display: none !important; }');
  1550. item('Taobao', '.ico_taobao { display: none !important; }');
  1551.  
  1552. subtitle('Nav');
  1553. item('Main', '.gn_nav>div:nth-child(1) { display: none !important; }');
  1554. item('Hot', '.gn_nav>div:nth-child(2) { display: none !important; }');
  1555. item('App', '.gn_nav>div:nth-child(3) { display: none !important; }');
  1556. item('Game', '.gn_nav>div:nth-child(4) { display: none !important; }');
  1557. item('Member', '.gn_setting[node-type="member"] { display: none !important; }');
  1558.  
  1559. subtitle('Left');
  1560. item('ToMe', '#pl_leftnav_common a[href^="/direct/tome"] { display: none !important; }');
  1561. item('Friends', '#pl_leftnav_group > div[node-type="groupList"] > .level_1_Box, #pl_leftnav_common .level_1_Box > form.left_nav_line { display: none !important; }');
  1562. item('App', '#pl_leftnav_app { display: none !important; }');
  1563.  
  1564. subtitle('Middle');
  1565. item('MemberTip', '[node-type="feed_list_shieldKeyword"] { display: none !important; }');
  1566. item('RecommendedTopic', '#pl_content_publisherTop div[node-type="recommendTopic"] { display: none !important; }');
  1567.  
  1568. subtitle('Right');
  1569. item('Whole', '.B_profile .W_main_c, .B_profile .WB_feed .repeat .input textarea { width: 100% } .B_profile .WB_feed .WB_screen { margin-left: 928px } .B_profile .W_main_2r { display: none !important; }');
  1570. item('Template', '.templete_enter { display: none !important; }');
  1571. item('Info', '.W_person_info { display: none !important; }');
  1572. item('Atten', '#pl_rightmod_myinfo .user_atten { display: none !important; }');
  1573. item('Trial', '#trustPagelet_checkin_lotteryv5 { display: none !important; }');
  1574. item('Interest', '[yawf-id="rightmod_recom_interest"] { display: none !important; }');
  1575. item('HotTopic', '[yawf-id="rightmod_zt_hottopic"] { display: none !important; }');
  1576. item('Member', '#trustPagelet_recom_memberv5 { display: none !important; }');
  1577. item('Weibo', '[yawf-id="rightmod_recom_weibo"] { display: none !important; }');
  1578. item('Location', '[yawf-id="rightmod_recom_location"] { display: none !important; }');
  1579. item('Music', '[yawf-id="rightmod_recom_music"] { display: none !important; }');
  1580. item('Movie', '[yawf-id="rightmod_recom_movie"] { display: none !important; }');
  1581. item('Book', '[yawf-id="rightmod_recom_book"] { display: none !important; }');
  1582. item('Notice', '#pl_rightmod_noticeboard { display: none !important; }');
  1583.  
  1584. subtitle('Weibo');
  1585. item('RecomFeed', '[node-type="feed_list_recommend"] { display: none !important; }');
  1586. item('TopicCard', '.WB_feed_spec[exp-data*="value=1022-topic"] { display: none !important; }');
  1587. item('LocationCard', '.WB_feed_spec[exp-data*="value=1022-place"] { display: none !important; }');
  1588. item('FeedTip', '[node-type="feed_privateset_tip"] { display: none !important; }');
  1589.  
  1590. subtitle('Person');
  1591. item('Cover', funcStr(function () { /* !CSS
  1592. .S_profile_pic { display: none; }
  1593. .profile_top { margin-top: 20px; }
  1594. .profile_top .pf_head { top: 5px; margin-top: 0 !important; }
  1595. .profile_top .pf_head_pic { height: 120px; width: 120px; float: right; }
  1596. .profile_top .pf_head_pic img { height: 120px; }
  1597. .profile_top .pf_head .user_atten { width: 60px; float: left; height: 120px; }
  1598. .profile_top .pf_head .user_atten li, .profile_top .pf_head .user_atten .follower { width: 54px; padding: 0 3px 3px; height: 37px; border-right: none; }
  1599. .profile_top .pf_head .user_atten li strong { margin: 3px 0 0; }
  1600. */ }));
  1601. item('BadgeIcon', '.pf_badge_icon { display: none !important; }');
  1602. item('Stats', '.profile_top .user_atten { display: none !important; } .profile_top .pf_head { margin-top: 51px; } ');
  1603. item('MyData', '.W_main_c [id^="Pl_Official_MyMicroworld__"] { display: none !important; }');
  1604. item('Group', '.W_main_2r [id^="Pl_Core_RightGroupsBtn__"] { display: none !important; }');
  1605. item('SuggestUser', '.W_main_2r [id^="Pl_Core_RightUserList__"] { display: none !important; }');
  1606. item('Relation', '.W_main_2r [id^="Pl_Core_RightUserGrid__"] { display: none !important; }');
  1607. item('Album', '.W_main_2r [id^="Pl_Core_RightPicMulti__"] { display: none !important; }'); // FIXME
  1608. item('HotTopic', '.W_main_2r [id^="Pl_Core_RightTextSingle__"] { display: none !important; }');
  1609. item('HotWeibo', '.W_main_2r [id^="Pl_Core_RightPicText__"] { display: none !important; }');
  1610.  
  1611. subtitle('Other');
  1612. item('Ads', '#plc_main [id^="pl_rightmod_ads"], #Box_right [id^="ads_"], #trustPagelet_zt_hottopicv5 [class*="hot_topicad"], div[ad-data], .WB_feed .popular_buss, [id^="sinaadToolkitBox"] { display: none !important; } #wrapAD, .news_logo { visibility: hidden !important; }');
  1613. item('FeedRecom', '.W_main_2r [id^="Pl_Third_Inline__"] { display: none !important; }');
  1614. item('Footer', '.global_footer { display: none !important; }');
  1615. item('WbIm', '.WBIM_news { display: none !important; }');
  1616. item('Tip', '.layer_tips { display: none !important; }');
  1617.  
  1618. var tagRightbarMods = function () {
  1619. var mods = document.querySelectorAll('#trustPagelet_indexright_recom .WB_right_module:not([yawf-id])');
  1620. if (!mods) return;
  1621. var identifiers = {
  1622. '.right_content.hot_topic': 'rightmod_zt_hottopic',
  1623. '.right_content.person_list': 'rightmod_recom_interest',
  1624. '[change-data*="key=index_weibo"]': 'rightmod_recom_weibo',
  1625. '[change-data*="key=index_LBS"]': 'rightmod_recom_location',
  1626. '[change-data*="key=index_song"]': 'rightmod_recom_music',
  1627. '[change-data*="key=index_mov"]': 'rightmod_recom_movie',
  1628. '[change-data*="key=index_book"]': 'rightmod_recom_book'
  1629. };
  1630. Array.apply(Array, mods).forEach(function (mod) {
  1631. Object.keys(identifiers).forEach(function (qs) {
  1632. if (mod.querySelector(qs)) mod.setAttribute('yawf-id', identifiers[qs]);
  1633. });
  1634. });
  1635. };
  1636.  
  1637. newNode.add(tagRightbarMods);
  1638. tagRightbarMods();
  1639. css.add('.W_miniblog { visibility: visible !important; }');
  1640.  
  1641. }());
  1642.  
  1643. // 改造设置
  1644. var toolFilterGroup = filterGroup('toolFilterGroup');
  1645.  
  1646. // 清除发布框中的默认话题 (wcf)
  1647. toolFilterGroup.add({
  1648. 'type': 'boolean',
  1649. 'key': 'weibo.tool.clear_def_topic',
  1650. 'text': '{{clearDefTopicDesc}}',
  1651. 'init': function () {
  1652. if (!this.conf) return;
  1653. var clearDefTopic = function () {
  1654. var inputBox = document.querySelector('#pl_content_publisherTop .send_weibo .input textarea');
  1655. if (inputBox && inputBox.hasAttribute('hottopic')) {
  1656. inputBox.removeAttribute('hottopic'); inputBox.removeAttribute('hottopicid');
  1657. inputBox.value = 'DUMMY'; inputBox.focus();
  1658. inputBox.value = ''; inputBox.blur();
  1659. }
  1660. };
  1661. newNode.add(clearDefTopic);
  1662. },
  1663. });
  1664.  
  1665. // 展开左栏分组
  1666. toolFilterGroup.add({
  1667. 'type': 'boolean',
  1668. 'key': 'weibo.tool.noFloatNav',
  1669. 'text': '{{noFloatNav}}',
  1670. 'init': css('.WB_global_nav { position: absolute !important; }'),
  1671. });
  1672.  
  1673. // 展开左栏分组
  1674. toolFilterGroup.add({
  1675. 'type': 'boolean',
  1676. 'key': 'weibo.tool.showAllGroup',
  1677. 'text': '{{showAllGroupDesc}}',
  1678. 'init': css('#pl_leftnav_group div[node-type="moreList"] { display: block !important } #pl_leftnav_group > div[node-type="groupList"] > .level_2_Box > .levmore { display: none }'),
  1679. });
  1680.  
  1681. // 展开左栏消息
  1682. toolFilterGroup.add({
  1683. 'type': 'boolean',
  1684. 'key': 'weibo.tool.showAllMsgNav',
  1685. 'text': '{{showAllMsgNavDesc}}',
  1686. 'init': css('#pl_leftnav_common > .level_1_Box > .lev2_new { display: block !important }'),
  1687. });
  1688.  
  1689. // 微博作者与正文同行
  1690. toolFilterGroup.add({
  1691. 'type': 'boolean',
  1692. 'key': 'weibo.tool.unwrapText',
  1693. 'text': '{{unwrapTextDesc}}',
  1694. 'init': css('.WB_info, .WB_text { display: inline } .WB_info+.WB_text::before { content: ": " } .WB_func { margin-top: 5px } .B_index .WB_feed .W_ico16 { vertical-align: -3px !important }'),
  1695. });
  1696.  
  1697. // 个人主页自动打开微博列表
  1698. toolFilterGroup.add({
  1699. 'type': 'boolean',
  1700. 'key': 'weibo.tool.redirectWeibo',
  1701. 'text': '{{personalRedirectWeibo}}',
  1702. 'init': function () {
  1703. if (!this.conf) return;
  1704. var locat = unsafeWindow.$CONFIG.location;
  1705. if (locat.slice(-5) !== '_home') return;
  1706. if (!document.body.classList.contains('B_profile')) return;
  1707. var from = (location.search.match(/from=([^&]*)/) || {})[1];
  1708. if (locat.indexOf(from) === 0) return;
  1709. var redirect = function () {
  1710. var link = document.querySelector('.PRF_tab_noicon li.pftb_itm a[href*="/weibo?"]'); if (!link) return;
  1711. if (!link) return false;
  1712. newNode.remove(redirect);
  1713. location.replace(link.href);
  1714. };
  1715. newNode.add(redirect);
  1716. redirect();
  1717. },
  1718. });
  1719.  
  1720. // 查看大图旁添加查看原图链接
  1721. toolFilterGroup.add({
  1722. 'type': 'boolean',
  1723. 'default': true,
  1724. 'key': 'weibo.tool.viewOriginal',
  1725. 'text': '{{viewOriginalDesc}}',
  1726. 'init': function () {
  1727. if (!this.conf) return;
  1728. var addOriLink = function () {
  1729. var a = document.querySelector('a.show_big[action-data]:not([yawf-viewori])');
  1730. if (!a) return; a.setAttribute('yawf-viewori', 'yawf-viewori');
  1731. var arg = a.getAttribute('action-data').match(/pid=(\w+)&mid=(\d+)&uid=(\d+)/);
  1732. if (!arg) return;
  1733. var vol = cewih('div', fillStr(html.viewOriginalLink)), l = vol.firstChild;
  1734. var img = fillStr(url.view_ori, { 'uid': arg[3], 'mid': arg[2], 'pid': arg[1] });
  1735. while (vol.firstChild) a.parentNode.insertBefore(vol.firstChild, a);
  1736. if (0) GM_xmlhttpRequest({
  1737. 'method': 'GET',
  1738. 'url': img,
  1739. 'onload': function (resp) {
  1740. var h = (new DOMParser()).parseFromString(resp.responseText, 'text/html');
  1741. l.href = h.querySelector('#pic').src;
  1742. },
  1743. }); l.href = img;
  1744. };
  1745. newNode.add(addOriLink);
  1746. },
  1747. });
  1748.  
  1749. // 屏蔽隐藏微博
  1750. toolFilterGroup.add({
  1751. 'type': 'boolean',
  1752. 'key': 'weibo.tool.block_hidden',
  1753. 'text': '{{blockHiddenWeiboDesc}}',
  1754. 'init': function () {
  1755. if (!this.conf) return;
  1756. addWeiboFilterListener(function (feed) {
  1757. [feed].concat(Array.apply(Array, feed.querySelectorAll('.WB_feed_type'))).forEach(function (feed) {
  1758. var display = feed.getAttribute('yawf-display');
  1759. if (display.slice(-7) !== '-hidden') return;
  1760. if (!feed.getAttribute('mid')) return;
  1761. blockWeibo(feed.getAttribute('mid'));
  1762. feed.setAttribute('yawf-block', 'block');
  1763. });
  1764. });
  1765. }
  1766. });
  1767.  
  1768. // 显示一个透明度设置框
  1769. var genTransparencyInput = function (binder) {
  1770. var l = cewih('label', fillStr(text.transparencyInput, { 'number': html.transparencyInput }));
  1771. var n = l.querySelector('input[type="number"]'), r = l.querySelector('input[type="range"]');
  1772. var onchange = binder(n, function (val) {
  1773. if (isNaN(parseInt(val))) return 0;
  1774. return Math.min(Math.max(parseInt(val), 0), 100);
  1775. });
  1776. r.value = n.value;
  1777. var updateN = function () { if (r.value !== n.value) n.value = r.value; onchange(); };
  1778. var updateR = function () { if (r.value !== n.value) r.value = n.value; onchange(); };
  1779. r.addEventListener('change', updateN); r.addEventListener('mousemove', updateN);
  1780. n.addEventListener('change', updateR); n.addEventListener('keypress', updateR);
  1781. return l;
  1782. };
  1783.  
  1784. // 显示一个颜色&透明度设置框
  1785. var genColorWithTransparencyInput = function (binder1, binder2) {
  1786. var color = cewih('label', html.colorInput);
  1787. var c = color.querySelector('input[type="color"]');
  1788. binder1(c);
  1789. var transparency = genTransparencyInput(binder2);
  1790. return [color, transparency];
  1791. };
  1792.  
  1793. // 将颜色和透明度转换为一个表示颜色的字符串
  1794. var colorStr = function (color, transparency) {
  1795. return 'rgba(' + color.slice(1)
  1796. .split(/(..)/).filter(function (x) { return x; })
  1797. .map(function (x) { return parseInt(x, 16); }).join(',') +
  1798. ',' + (100 - transparency) / 100 + ')';
  1799. };
  1800.  
  1801. // 一个带有颜色/透明度的选框项
  1802. var coloredConfigItem = function (details) {
  1803. var conf = {
  1804. 'type': 'boolean',
  1805. 'key': details.key,
  1806. 'keys': { 'color': 'string', 'transparency': 'number', 'blur': 'boolean' },
  1807. 'defaultcolor': details.defaultcolor,
  1808. 'defaulttransparency': details.defaulttransparency,
  1809. 'text': details.text,
  1810. 'shown': function (dom) {
  1811. var elements = genColorWithTransparencyInput(function (c, s) {
  1812. bindInputValue(c, this, 'color', s);
  1813. }.bind(this), function (t, s) {
  1814. return bindInputValue(t, this, 'transparency', s);
  1815. }.bind(this));
  1816. elements.forEach(dom.appendChild.bind(dom));
  1817. },
  1818. 'init': function () {
  1819. if (!this.conf) return;
  1820. details.init(colorStr(this.confcolor, this.conftransparency));
  1821. },
  1822. };
  1823. return conf;
  1824. };
  1825.  
  1826. // 高亮显示白名单微博
  1827. toolFilterGroup.add(coloredConfigItem({
  1828. 'key': 'weibo.tool.whitelist_highlight',
  1829. 'defaultcolor': '#fef3da',
  1830. 'text': '{{whitelistHighlightDesc}}',
  1831. 'init': function (color) {
  1832. css.add(fillStr(funcStr(function () { /*
  1833. [node-type="feed_list"] .WB_feed_type[yawf-display$="-show"] { background-color: {{color}} !important; box-shadow: -20px 0 0 {{color}}, 20px 0 0 {{color}}; }
  1834. [node-type="feed_list"] .WB_feed_together .WB_feed_type[yawf-display$="-show"] { background-color: {{color}} !important; box-shadow: -10px 0 0 {{color}}, 10px 0 0 {{color}}; }
  1835. */ }), { 'color': color }));
  1836. },
  1837. }));
  1838.  
  1839. // 首页背景
  1840. toolFilterGroup.add(coloredConfigItem({
  1841. 'key': 'weibo.tool.my_background_color',
  1842. 'defaultcolor': '#ffffff',
  1843. 'defaulttransparency': 30,
  1844. 'text': '{{mainBackgroundColorOverride}}',
  1845. 'init': function (color) {
  1846. css.add(fillStr(funcStr(function () { /*
  1847. body:not(.S_profile) .W_main { background-image: none !important; background-color: {{color}} !important }
  1848. body:not(.S_profile) .S_bg4, body:not(.S_profile) .W_main_a, body:not(.S_profile) .W_main_bg { background: transparent !important; }
  1849. */ }), { 'color': color }));
  1850. },
  1851. }));
  1852.  
  1853. // 个人主页背景
  1854. toolFilterGroup.add(coloredConfigItem({
  1855. 'key': 'weibo.tool.other_background_color',
  1856. 'defaultcolor': '#ffffff',
  1857. 'defaulttransparency': 30,
  1858. 'text': '{{profileBackgroundColorOverride}}',
  1859. 'init': function (color) {
  1860. css.add(fillStr(funcStr(function () { /*
  1861. .S_profile .W_profile_bg, .S_profile .S_bg5 { background-color: {{color}} !important; }
  1862. .S_profile .S_bg4:not(.W_profile_bg) { background: none transparent !important }
  1863. */ }), { 'color': color }));
  1864. },
  1865. }));
  1866.  
  1867.  
  1868. // 自定义样式
  1869. toolFilterGroup.add({
  1870. 'type': 'string',
  1871. 'text': '{{userstyleTitle}}',
  1872. 'key': 'weibo.tool.userstyle',
  1873. 'init': function () {
  1874. var conf = this.conf; GM_addStyle(conf);
  1875. var set = this.putconf.bind(this);
  1876. var putconf = function (css) {
  1877. conf = css;
  1878. setTimeout(function () { set(css); config.write(); location.reload(); }, 0);
  1879. };
  1880. GM_registerMenuCommand(fillStr('{{userstyleEditDesc}}'), function () {
  1881. var newcss = prompt(fillStr('{{userstyleEditDetails}}'), conf);
  1882. if (newcss !== null) putconf(newcss);
  1883. }, "S");
  1884. },
  1885. });
  1886.  
  1887.  
  1888. // 脚本设置
  1889. var scriptFilterGroup = filterGroup('scriptFilterGroup');
  1890.  
  1891. // 导入导出
  1892. scriptFilterGroup.add({
  1893. 'type': 'subtitle',
  1894. 'text': '{{configImportAndExport}}',
  1895. });
  1896.  
  1897. scriptFilterGroup.add({
  1898. 'show': function () {
  1899. var dom = cewih('div', html.configImportExport).firstChild;
  1900. var bii = dom.querySelector('input[type="file"]');
  1901. var be = dom.querySelector('[node-type="export"]');
  1902. var br = dom.querySelector('[node-type="reset"]');
  1903. // 导出按钮
  1904. var updateExportButton = function () {
  1905. be.href = 'data:application/octet-stream;base64,' +
  1906. btoa(unescape(encodeURIComponent(config.export())));
  1907. be.setAttribute('download', 'yawf-config.yawf');
  1908. };
  1909. // 导入按钮
  1910. var doImport = function (file) {
  1911. var reader = new FileReader();
  1912. var success = function () {
  1913. Alert('yawf-config-import-success', {
  1914. 'title': fillStr('{{configImportSuccessTitle}}'),
  1915. 'text': fillStr('{{configImportSuccess}}'),
  1916. 'icon': 'succ'
  1917. });
  1918. };
  1919. var error = function () {
  1920. Alert('yawf-config-import-fail', {
  1921. 'title': fillStr('{{configImportFailTitle}}'),
  1922. 'text': fillStr('{{configImportFail}}'),
  1923. 'icon': 'error'
  1924. });
  1925. };
  1926. if (file.size > (1 << 24)) error();
  1927. else reader.addEventListener('load', function () {
  1928. if (config.import(reader.result)) {
  1929. updateExportButton();
  1930. success();
  1931. } else error();
  1932. });
  1933. reader.readAsText(file);
  1934. bii.value = '';
  1935. };
  1936. bii.addEventListener('change', function () {
  1937. var file = bii.files[0];
  1938. Confirm('yawf-config-import-warning', {
  1939. 'title': fillStr('{{configImportWarningTitle}}'),
  1940. 'text': fillStr('{{configImportWarning}}'),
  1941. 'onOk': function () { doImport(file); },
  1942. });
  1943. });
  1944. updateExportButton();
  1945. // 重置按钮
  1946. var doReset = function () {
  1947. config.clear();
  1948. updateExportButton();
  1949. };
  1950. br.addEventListener('click', function () {
  1951. Confirm('yawf-config-reset-warning', {
  1952. 'title': fillStr('{{configResetWarningTitle}}'),
  1953. 'text': fillStr('{{configResetWarning}}'),
  1954. 'onOk': doReset,
  1955. });
  1956. });
  1957. return dom;
  1958. },
  1959. });
  1960.  
  1961. // 调试
  1962. scriptFilterGroup.add({
  1963. 'type': 'subtitle',
  1964. 'text': '{{scriptDebugTitle}}',
  1965. });
  1966.  
  1967. scriptFilterGroup.add({
  1968. 'show': function () {
  1969. var dom = cewih('div', fillStr(html.configBoolean, { 'key': 'debug', 'text': '{{scriptDebug}}' })).firstChild;
  1970. var input = dom.querySelector('input');
  1971. input.checked = !!GM_getValue('debug', false);
  1972. input.addEventListener('change', function () {
  1973. GM_setValue('debug', !GM_getValue('debug', false));
  1974. });
  1975. return dom;
  1976. }
  1977. });
  1978.  
  1979. // 关于
  1980. scriptFilterGroup.add({
  1981. 'type': 'subtitle',
  1982. 'text': '{{scriptAboutTitle}}',
  1983. });
  1984.  
  1985. scriptFilterGroup.add({
  1986. 'type': 'text',
  1987. 'text': '{{scriptAbout}}',
  1988. });
  1989.  
  1990. scriptFilterGroup.add({
  1991. 'init': function () {
  1992. var isEn = i18n.lang === 'en';
  1993. css.add(fillStr(funcStr(function () { /*!CSS
  1994. .profile_tab .pftb_lk { padding-left: {{headerWidth}}; padding-right: {{headerWidth}}; }
  1995. .profile_tab .current.pftb_lk { padding-left: {{headerWidth2}}; padding-right: {{headerWidth2}}; }
  1996. .layoutFilterGroupLayer .yawf-configBoolean { width: {{layoutOptionWidth}}; }
  1997. */ }), {
  1998. 'headerWidth': isEn ? '12px' : '15px',
  1999. 'headerWidth2': isEn ? '9px' : '12px',
  2000. 'layoutOptionWidth': isEn ? '320px' : '160px',
  2001. }));
  2002. },
  2003. });
  2004.  
  2005. // 检查是否要在本页上运行
  2006. var validPage = function () {
  2007. if (self !== top) return false;
  2008. if (!unsafeWindow.$CONFIG.uid) return false;
  2009. if (!unsafeWindow.$CONFIG.lang) return false;
  2010. return true;
  2011. };
  2012.  
  2013. // 完成加载时
  2014. var dcl = function () {
  2015. if (!validPage()) return;
  2016. // 初始化用户语言
  2017. i18n.setLang(unsafeWindow.$CONFIG.lang);
  2018. // 加载用户配置
  2019. config = config(unsafeWindow.$CONFIG.uid);
  2020. typedConfig();
  2021. // 初始化文本和网页数据(基于用户选择的语言)
  2022. Object.keys(text).map(function (key) { i18n(text[key]); text[key] = text[key].local; });
  2023. Object.keys(html).map(function (key) { html[key] = fillStr(html[key]); });
  2024. // 初始化所有过滤器
  2025. filters.init();
  2026. // 初始化折叠微博
  2027. fixFoldWeibo.init();
  2028. // 注册样式
  2029. css.init();
  2030. // 显示设置按钮
  2031. showIcon();
  2032. // 开始过滤
  2033. newNode.active();
  2034. };
  2035. if (document.body) call(dcl);
  2036. else document.addEventListener('DOMContentLoaded', dcl);
  2037.  
  2038. GM_addStyle(fillStr((funcStr(function () { /*!CSS
  2039. // 在顶部添加按钮
  2040. .gn_setting[node-type="member"]:last-child { margin-right: 44px; }
  2041. .WB_global_nav .gn_setting .gn_tab.gn_filter .ico { background-image: url("{{filter-img}}"); !important; background-position: 0 0 !important; }
  2042. .WB_global_nav .gn_search { width: 210px !important; left: 440px !important; position: absolute !important; }
  2043. .WB_global_nav .gn_search .gn_input { width: 168px !important; }
  2044. // 设置框相关样式
  2045. .yawf-Layer.yawf-drag { opacity: 0.67; -moz-user-select: none; user-select: none; }
  2046. #yawf-config [node-type="inner"] { padding: 20px; }
  2047. .yawf-config-body { margin: -20px; max-height: 360px; overflow-y: auto; padding: 20px; width: 760px; }
  2048. #yawf-config .profile_tab { font-size: 12px; margin: -20px -20px 20px; width: 800px; }
  2049. .yawf-groupSubtitle { margin: 5px 10px; padding: 10px 0 0 0; font-weight: bold; }
  2050. .yawf-configItem, .yawf-groupText { margin: 5px 20px; padding: 5px 0; }
  2051. .yawf-configString span { line-height: 16px; padding: 2px 10px; margin-bottom: -20px; display: block; width: calc(100% - 20px); position: relative; }
  2052. .yawf-configString textarea.W_input { width: calc(100% - 20px); padding-top: 20px; min-height: 80px; resize: vertical; }
  2053. .yawf-configStringsInput, .yawf-configUsersInput { margin: 5px; }
  2054. .yawf-configStringsItems, .yawf-configUsersItems { padding: 5px 10px; }
  2055. .yawf-configStringsItem, .yawf-configUsersItem { display: inline-block; margin: 2px; }
  2056. .yawf-configStringsItem a.icon_close, .yawf-configUsersItem a.icon_close { margin-left: 3px; vertical-align: -2px; }
  2057. .yawf-configUsersItem .shield_object_card { display: inline-block; }
  2058. .yawf-configUsersItem .shield_object_card .card_bg { border: 1px solid #e6e6e6; border-radius: 2px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.02); padding: 1px 5px 1px 1px; }
  2059. .yawf-configUsersItem .shield_object_card .card_pic { float: left; width: 50px; }
  2060. .yawf-configUsersItem .shield_object_card .card_pic .pic_box { display: block; }
  2061. .yawf-configUsersItem .shield_object_card .card_content { margin-left: 60px; }
  2062. .yawf-configUsersItem .shield_object_card .object_info { height: 22px; margin-top: 2px; }
  2063. .yawf-configUsersItem .shield_object_card .object_name { line-height: 22px; overflow: hidden; }
  2064. .yawf-configUsersItem .shield_object_card .other_info { line-height: 24px; }
  2065. .yawf-configImportExport [node-type] { margin-right: 20px; }
  2066. .yawf-configAdd { appearance: none; }
  2067. #yawf-config .btn { border-top: 1px solid #ccc; margin: 15px 0 0; padding: 10px 0 0; }
  2068. #yawf-config .btn .W_btn_b_disable:hover { border-color: #d9d9d9; }
  2069. #yawf-config .btn .W_btn_b_disable:hover span { border-color: #ffffff; }
  2070. .layoutFilterGroupLayer .yawf-configBoolean { display: inline-block; margin-right: 0; }
  2071. // 隐藏微博
  2072. [yawf-display$="-hidden"] { display: none !important; }
  2073. [node-type="feed_list"] .WB_feed_type:not([yawf-display]), [node-type="feed_list"] .WB_feed_type .WB_feed_type:not([yawf-display]) { visibility: hidden !important; }
  2074. // 折叠微博
  2075. [node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"]::before { display: block; width: 100%; height: 24px; line-height: 24px; padding: 0 2em 20px; border-bottom: #e6e6e6 1px solid; }
  2076. [node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"] { height: 45px; overflow: hidden; cursor: pointer; }
  2077. [node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"] .WB_screen { margin-top: -40px !important; }
  2078. [node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"] .WB_feed_datail { display: none !important; }
  2079. // 子微博
  2080. [node-type="feed_list"] .WB_feed_type[yawf-display$="-hidden"]+.WB_feed_type[yawf-display$="-son"],
  2081. [node-type="feed_list"] .WB_feed_type[yawf-display$="-fold"]+.WB_feed_type[yawf-display$="-son"] { display: none !important; }
  2082. [node-type="feed_list"] .WB_feed_type:not([yawf-display$="-son"]) .WB_feed_together { display: none !important; }
  2083. [node-type="feed_list"] .WB_feed_type[yawf-withson="son"] .WB_feed_datail,
  2084. [node-type="feed_list"] .WB_feed_type[yawf-withson="son"][yawf-display$="-fold"]::before { border: 0 none !important; }
  2085. [node-type="feed_list"] .WB_feed_type[yawf-display$="-son"] { padding-top: 0 !important; }
  2086. [node-type="feed_list"] .WB_feed_type[yawf-display$="-son"]>.WB_screen,
  2087. [node-type="feed_list"] .WB_feed_type[yawf-display$="-son"]>.WB_feed_datail>.WB_face,
  2088. [node-type="feed_list"] .WB_feed_type[yawf-display$="-son"]>.WB_feed_datail>.WB_detail>*:not(.WB_feed_together) { display: none !important; }
  2089. [node-type="feed_list"] .WB_feed_type[yawf-display$="-son"]>.WB_feed_datail>.WB_detail { margin-top: -20px; margin-bottom: -10px; }
  2090. // 其他
  2091. .WB_feed_together .wft_users { display: none; }
  2092. .WB_feed_together[yawf-sonfold="display"] [node-type="feed_list_wrapForward"] { display: block !important; }
  2093. .WB_feed_together[yawf-sonfold="display"] [action-type="feed_list_seeAll"],
  2094. .WB_feed_together[yawf-sonfold="display"] [action-type="feed_list_foldForward"] { display: none !important; }
  2095. .W_miniblog { visibility: hidden; }
  2096. input[type="number"]:not(:focus) ~ .yawf-transparency-range:not(:hover) > input[type="range"]:not(:focus) { display: none; }
  2097. */ }) + '\n').replace(/\/\/.*\n/g, '\n'), {
  2098. 'filter-img': images.filter,
  2099. }));
  2100.