Tieba Utilities

百度贴吧依赖脚本(寂寞的原子的公共库)

  1. // ==UserScript==
  2. // @name Tieba Utilities
  3. // @namespace http://gera2ld.blog.163.com/
  4. // @author Gerald <gera2ld@163.com>
  5. // @icon http://cn.gravatar.com/avatar/a0ad718d86d21262ccd6ff271ece08a3?s=80
  6. // @version 0.9.1
  7. // @description 百度贴吧依赖脚本(寂寞的原子的公共库)
  8. // @homepageURL http://geraldl.net/userjs/TiebaUtils
  9. // @match *://*.baidu.com/*
  10. // @include *.baidu.com/*
  11. // @run-at document-start
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // ==/UserScript==
  15.  
  16. function initUtils(event_id){
  17. // communicate with content page
  18. var post=function(data){
  19. var e=document.createEvent("MutationEvent");
  20. e.initMutationEvent(event_id,false,false,null,null,null,JSON.stringify(data),e.ADDITION);
  21. document.dispatchEvent(e);
  22. };
  23. var addSButton=function(){
  24. function oldTheme(v){
  25. var b=$('<span class=poster_submit>').insertBefore('.poster_draft_status');
  26. b.label=$('<em>').html(v).appendTo(b).wrap('<a href="#" class="ui_btn ui_btn_m"><span>');
  27. return b;
  28. }
  29. function newTheme(v){
  30. var b=$('<span class=poster_submit>').insertBefore('.poster_draft_status');
  31. b.label=$('<a href="#" class="btn_default btn_middle">').html(v).appendTo(b);
  32. return b;
  33. }
  34. addSButton=$('.j_submit').hasClass('btn_default')?newTheme:oldTheme;
  35. return addSButton.apply(this, arguments);
  36. };
  37.  
  38. // popup menu for editor
  39. function Popup(b,funcs){
  40. this.funcs=funcs;
  41. this.container=null;
  42. this.onopen=this._onopen.bind(this);
  43. this.onclose=this._onclose.bind(this);
  44. this.ontoggle=this._ontoggle.bind(this);
  45. this.button=$(b).click(this.ontoggle);
  46. this.call('init').stopPropagation();
  47. }
  48. Popup.prototype={
  49. stopPropagation:function(){
  50. this.container.click(function(e){
  51. e.stopPropagation();
  52. });
  53. return this;
  54. },
  55. call:function(func){
  56. var f=this.funcs[func];
  57. if(f) f(this);
  58. return this;
  59. },
  60. getfunc:function(func){
  61. var t=this,f=t.funcs[func];
  62. if(f) return function(){f(t);};
  63. },
  64. _onopen:function(){
  65. this.container.show();
  66. $(document).click(this.onclose);
  67. this.call('open');
  68. this.call('locate');
  69. },
  70. _onclose:function(){
  71. this.container.hide();
  72. $(document).unbind('click',this.onclose);
  73. this.call('close');
  74. },
  75. _ontoggle:function(e){
  76. e.preventDefault();
  77. if(this.container.is(':visible')) this.onclose();
  78. else setTimeout(this.onopen,0);
  79. },
  80. };
  81.  
  82. var shortcuts={},links={
  83. hotkey:'http://gerald.top/code/TiebaUtils#hotkey',
  84. advanced:'http://gerald.top/code/TiebaAdvanced#advanced',
  85. },utils={
  86. index:function(objs,obj,key){
  87. for(var i=0;i<objs.length;i++)
  88. if(objs[i][key]===obj) return i;
  89. return -1;
  90. },
  91. wait: (function(){
  92. var objs=[];
  93. function init(obj,name,callbacks){
  94. var value=undefined;
  95. Object.defineProperty(obj,name,{
  96. get:function(){return value;},
  97. set:function(val){
  98. value=val;
  99. if(callbacks) {
  100. callbacks.forEach(function(f){f(val);});
  101. callbacks=null;
  102. }
  103. },
  104. configurable:true,
  105. });
  106. }
  107. return function(obj,name,callback) {
  108. if(obj[name]!==undefined) callback(obj[name]);
  109. else {
  110. var i=utils.index(objs,obj,'obj'),o=objs[i],c;
  111. if(!o) objs.push(o={obj:obj,callbacks:{}});
  112. c=o.callbacks[name];
  113. if(!c) c=o.callbacks[name]=[];
  114. c.push(callback);
  115. init(obj,name,c);
  116. }
  117. };
  118. })(),
  119. /* window cannot be observed, use utils.wait instead
  120. observe: (function(){
  121. var objs=[];
  122. function init(obj,o){
  123. // Opera Presto is not supported any more
  124. function observer(changes){
  125. changes.forEach(function(c){
  126. var d=o.data[c.name];
  127. if(d) {
  128. console.log('Observed: ',obj,c.name);
  129. d.forEach(function(f){f(obj[c.name]);});
  130. delete o.data[c.name];
  131. if(!--o.length) {
  132. o=objs.indexOf(o);
  133. if(o>=0) objs.splice(o,1);
  134. Object.unobserve(obj,observer,['add']);
  135. }
  136. }
  137. });
  138. }
  139. Object.observe(obj,observer,['add']);
  140. }
  141. return function(obj,name,callback) {
  142. if(name in obj) callback(obj[name]);
  143. else {
  144. var i=utils.index(objs,obj,'obj'),o=objs[i],d;
  145. if(!o) {
  146. objs.push(o={obj:obj,data:{},length:0});
  147. init(obj,o);
  148. }
  149. d=o.data[name];
  150. if(!d) {
  151. d=o.data[name]=[];
  152. o.length++;
  153. }
  154. d.push(callback);
  155. }
  156. };
  157. })(),*/
  158. find: function(selector,ancestor,callback){
  159. var o=$(selector,ancestor),mo;
  160. if(o.length) callback(o);
  161. else if(window.MutationObserver) {
  162. mo=new MutationObserver(function(changes){
  163. $.each(changes,function(i,e){
  164. $.each(e.addedNodes,function(i,o){
  165. o=$(o).find(selector);
  166. if(o.length) {
  167. mo.disconnect();
  168. callback(o);
  169. }
  170. });
  171. });
  172. });
  173. mo.observe(ancestor,{
  174. childList:true,
  175. subtree:true,
  176. });
  177. } else $(window).load(function(){
  178. callback($(selector,ancestor));
  179. });
  180. },
  181. hook: function(o,n,a) {
  182. var f;
  183. if(o&&(f=o[n])) {
  184. if(!f.hooked) {
  185. o[n]=function() {
  186. var t=this,a=arguments,f=a.callee,r=undefined,_r,i,stop=false;
  187. f.hookStop=function(){stop=true;};
  188. for(i=0;i<f.hook_before.length;i++){
  189. r=f.hook_before[i].apply(t,[f,a]);
  190. if(stop) return r;
  191. }
  192. r=f.hook_func.apply(t,a);
  193. for(i=0;i<f.hook_after.length;i++){
  194. _r=f.hook_after[i].apply(t,[f,r,a]);
  195. if(_r!==undefined) r=_r;
  196. if(stop) return r;
  197. }
  198. return r;
  199. };
  200. o[n].hook_func=f;
  201. f=o[n];
  202. f.hooked=true;
  203. f.hook_after=[];
  204. f.hook_before=[];
  205. }
  206. o=f.hook_after;
  207. if(n=a.after) {
  208. if(n.concat) f.hook_after=o.concat(n);
  209. else o.push(n);
  210. }
  211. o=f.hook_before;
  212. if(n=a.before) {
  213. if(n.concat) f.hook_before=o.concat(n);
  214. else o.push(n);
  215. }
  216. }
  217. },
  218. addStyle: function(css,id) {
  219. var s=document.getElementById(id)||document.createElement('style');
  220. if(id) s.id=id;if(css) s.innerHTML=css;
  221. document.head.appendChild(s);
  222. return $?$(s):s;
  223. },
  224. getObj: function(k,d) {
  225. var r=localStorage.getItem('ge_'+k),u=undefined,v=u;
  226. if(r) try{v=JSON.parse(r);}catch(e){}
  227. if(v==u&&d!=u) v=utils.setObj(k,d);
  228. return v;
  229. },
  230. setObj: function(k,v) {
  231. var j=JSON.stringify(v);
  232. localStorage.setItem('ge_'+k,j);
  233. post({cmd:'setvalue',data:{key:k,val:j}});
  234. return v;
  235. },
  236. // Base function
  237. insertButton: function (parent, $button, additional) {
  238. additional = additional || {};
  239. parent = $(parent);
  240. if (additional.after)
  241. $button.insertAfter(parent.children(additional.after));
  242. else if (additional.before)
  243. $button.insertBefore(parent.children(additional.before));
  244. else
  245. $button.appendTo(parent);
  246. return $button;
  247. },
  248. // Deprecated base function
  249. addButton: function(t,o,m,a) {
  250. if(m) {
  251. var i,k=a.keys;
  252. if(!k||!k.length) k=['mousedown','mouseup'];
  253. for(i=0;i<k.length;i++) if(o[k[i]]) {o[k[i]].call(o,m);break;}
  254. }
  255. return this.insertButton(t,o,a);
  256. },
  257. addTButton: function(o,m) { // Add Toolbar Button
  258. var tb=$('div.edui-btn-toolbar').first();
  259. if(m) o.click(m);
  260. return o.appendTo($('<div class="edui-btn edui-btn-bold" unselectable="on" onmousedown="return false">').prependTo(tb));
  261. },
  262. addSButton: addSButton, // Add Big Button
  263. addRPopup: function(b,o,c) { // Add popup for submit-like buttons
  264. return new Popup(b,{
  265. init:function(p){
  266. p.container=$('<div class=ge_panel_p title="">').prependTo(p.button).hide();
  267. p.caret=$('<i class=ge_caret>').appendTo(p.container).html('<i>');
  268. p.panel=$('<div class=ge_panel>').appendTo(p.container);
  269. },
  270. open:function(p){
  271. if(o) o(p);
  272. var l=Math.min(-50,$(document.body).innerWidth()-p.button.offset().left-p.panel.outerWidth());
  273. p.container.css({marginLeft:l});
  274. p.caret.css({left:p.button.width()/2-l-10});
  275. },
  276. close:c,
  277. });
  278. },
  279. addTPopup: function(b,o,c) { // Add popup for toolbar buttons
  280. return new Popup(b,{
  281. init:function(p){
  282. p.container=$('<div class="edui-dropdown-menu edui-popup" title="" style="display:block;top:44px;position:absolute;">').appendTo('.edui-dialog-container').hide();
  283. p.caret=$('<div class="edui-popup-caret up" style="top:-8px;position:absolute;">').appendTo(p.container);
  284. p.panel=$('<div class="edui-popup-body">').appendTo(p.container);
  285. },
  286. open:function(p){
  287. if(o) o(p);
  288. p.container.css({right:Math.max(-50,p.button.offset().left+p.button.width()-$(document.body).innerWidth())});
  289. p.caret.css({right:p.panel.outerWidth()+p.panel.offset().left-p.button.parent().offset().left-p.button.width()});
  290. },
  291. close:c,
  292. });
  293. },
  294. addLPopup: function(b,o,c) { // Add popup for Lzl buttons
  295. return new Popup(b,{
  296. init:function(p){
  297. p.container=$('<div class="lzl_edui_dialog_container">').hide();
  298. p.caret=$('<div class="inde_edui_popup_caret">').appendTo(p.container);
  299. p.panel=$('<div class="inde_edui_dropdown_menu">').appendTo(p.container);
  300. },
  301. reinit:function(p){
  302. p.stopPropagation().container.insertAfter(p.button);
  303. },
  304. open:function(p){
  305. if(o) o(p);
  306. p.container.css({left:'auto',right:0});
  307. p.caret.css({right:p.panel.outerWidth()+p.panel.offset().left-p.button.offset().left-p.button.width()});
  308. },
  309. close:c,
  310. });
  311. },
  312. bindProp: function(obj,prop,key,def,func,evt) {
  313. obj.prop(prop,utils.getObj(key,def));
  314. if(!evt) evt=['change'];
  315. evt.forEach(function(i){obj.bind(i,function(e){utils.setObj(key,this[prop]);if(func) obj.each(function(i,o){func.call(o,e);});});});
  316. return obj;
  317. },
  318. shortcut:function(key,func){
  319. key=key.toLowerCase();
  320. var d=[];
  321. if(key.slice(-2)=='--') {d.push('-');key=key.slice(0,-2).split('-');}
  322. else key=key.split('-');
  323. if(key.indexOf('m')>=0||key.indexOf('meta')>=0) d.unshift('m');
  324. if(key.indexOf('s')>=0||key.indexOf('shift')>=0) d.unshift('s');
  325. if(key.indexOf('a')>=0||key.indexOf('alt')>=0) d.unshift('a');
  326. if(key.indexOf('c')>=0||key.indexOf('ctrl')>=0) d.unshift('c');
  327. key=key.join('-');
  328. if(func) shortcuts[key]=func; else delete shortcuts[key];
  329. },
  330. list: function(lkey,ikey,dnew,def) { // def===true: not null
  331. var t={};t.last=0;
  332. t.load=function(i,nosave){
  333. if(i==undefined) i=ikey?utils.getObj(ikey,0):0;
  334. if(i<0||!t.length) i=0; else if(i>=t.length) i=t.length-1;
  335. if(ikey&&!nosave) utils.setObj(ikey,i);
  336. t.cur=t.list[t.last=i];
  337. return t;
  338. };
  339. t.push=function(d){if(!d) d=dnew();t.list.push(d);t.save();return t.length-1;};
  340. t.pop=function(i){var o=t.list.splice(i,1)[0];t.save();t.load(i);return o;}
  341. t.save=function(){if(lkey) utils.setObj(lkey,t.list);if(ikey) utils.setObj(ikey,t.last);};
  342. t.list=lkey?utils.getObj(lkey,[]):[];
  343. Object.defineProperty(t,'length',{get:function(){return t.list.length;}});
  344. if(!t.length&&def) {if(def.concat) {t.list=def.concat();t.save();} else t.push();}
  345. return t;
  346. },
  347. getLink:function(t,o){
  348. o=o||{};
  349. var l=links[t];
  350. if(l) o.href=l;
  351. if(!o['target']) o.target='_blank';
  352. t=o.html||'';delete t.html;l=['<a'];
  353. for(i in o) l.push(i+'="'+o[i]+'"');
  354. return l.join(' ')+'>'+t+'</a>';
  355. },
  356. dialog:{ // Popup Window
  357. dialog:null,
  358. className:'ge_popup',
  359. show:function(o){
  360. var t=this,d=t.dialog;
  361. t.hide();t.obj=o;
  362. d.className=o.className||'';
  363. d.classList.add(t.className);
  364. d.innerHTML=o.html;
  365. if(o.init) o.init(d);
  366. d.style.display='block';
  367. d.style.top=(innerHeight-d.offsetHeight)/2+'px';
  368. d.style.left=(innerWidth-d.offsetWidth)/2+'px';
  369. document.addEventListener('click',t._hide=t.hide.bind(this),false);
  370. },
  371. hide:function(){
  372. var t=this,o=t.obj,d=t.dialog;
  373. if(o) {
  374. if(o.dispose) o.dispose(d);
  375. d.innerHTML='';d.className=t.className;
  376. d.style.display='none';t.obj=null;
  377. document.removeEventListener('click',t._hide,false);
  378. }
  379. },
  380. },
  381. };
  382. utils.popup=utils.dialog;
  383. document.addEventListener('keydown',function(e){
  384. if(e.target==document.body){
  385. var k=[],f;
  386. if(e.ctrlKey) k.push('c');
  387. if(e.altKey) k.push('a');
  388. if(e.shiftKey) k.push('s');
  389. if(e.metaKey) k.push('m');
  390. k.push(String.fromCharCode(e.keyCode));
  391. k=k.join('-').toLowerCase();
  392. if(f=shortcuts[k]) {e.preventDefault();f();}
  393. }
  394. },false);
  395. window.addEventListener('DOMContentLoaded',function(){
  396. var d=document.createElement('div');document.body.appendChild(d);
  397. d.addEventListener('click',function(e){e.stopPropagation();},false);
  398. utils.dialog.dialog=d;
  399. utils.addStyle('\
  400. .ge_x{clear:both;}\
  401. .ge_popup{display:none;z-index:10006;font:normal normal 400 12px/18px 宋体;position:fixed;background:white;border:1px solid silver;box-shadow:5px 5px 7px #333;text-align:left;}\
  402. .ge_mask{background:rgba(0,0,0,0.6);position:fixed;top:0;bottom:0;left:0;right:0;z-index:1007;display:none;}\
  403. .ge_panel_p{position:relative;z-index:1006;}\
  404. .ge_panel{position:absolute;background:#eee;border:1px solid black;padding:10px;border-radius:5px;bottom:0;white-space:nowrap;}\
  405. .ge_caret,.ge_caret>i{position:absolute;border:solid;border-color:black transparent;border-width:8px 8px 0;z-index:889;}\
  406. .ge_caret>i{border-top-color:#eee;top:-9px;left:-8px;}\
  407. .ge_sbtn{background:#77f;color:white;border-radius:3px;border:1px solid;border:none;margin:2px;cursor:pointer;text-align:center;}\
  408. span.ge_sbtn{padding:2px 3px;}\
  409. .ge_disabled{background:gray;cursor:default;}\
  410. .ge_rsep{margin-right:10px;}\
  411. .ge_opt{padding:20px;border-radius:5px;}\
  412. .ge_opt fieldset{border:1px solid silver;border-radius:5px;padding:5px;}\
  413. .ge_opt textarea{min-height:100px;width:100%;}\
  414. ','ge_css');
  415. },false);
  416. var gkey='__ge_firefox',ff=window[gkey];
  417. if(!ff) ff=window[gkey]={};
  418. ff['utils']=utils;
  419. }
  420.  
  421. function injectScript(code){
  422. var s=document.createElement('script'),p=document.body||document.documentElement;
  423. s.innerHTML=code;
  424. p.appendChild(s);p.removeChild(s);
  425. }
  426. function setvalue(o){
  427. if(o) data[o.key]=o.val;
  428. GM_setValue('data',JSON.stringify(data));
  429. }
  430. var event_id='utils'+(Math.random()*65536).toString(36),data;
  431. try{
  432. data=JSON.parse(GM_getValue('data','{}'));
  433. }catch(e){
  434. data={};
  435. }
  436. if(!localStorage.ge_backup) {
  437. var i,k;
  438. if(data.backup) {
  439. for(i in data) localStorage.setItem('ge_'+i,data[i]);
  440. } else {
  441. data.backup=1;
  442. for(i=0;i<localStorage.length;i++) {
  443. k=localStorage.key(i);
  444. if(k.slice(0,3)=='ge_') data[k.slice(3)]=localStorage.getItem(k);
  445. }
  446. setvalue();
  447. }
  448. }
  449. document.addEventListener(event_id,function(e){
  450. var o=JSON.parse(e.attrName),
  451. mappings={
  452. setvalue:setvalue,
  453. },f=mappings[o.cmd];
  454. if(f) f(o.data);
  455. },false);
  456. injectScript('!'+initUtils.toString()+'('+JSON.stringify(event_id)+')');