Tieba Imagizer

贴吧图化 - Gerald倾情打造

目前为 2014-10-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Tieba Imagizer
  3. // @namespace http://gera2ld.blog.163.com/
  4. // @author Gerald <gera2ld@163.com>
  5. // @icon http://s.gravatar.com/avatar/a0ad718d86d21262ccd6ff271ece08a3?s=80
  6. // @version 1.2.6.1
  7. // @description 贴吧图化 - Gerald倾情打造
  8. // @homepageURL http://geraldl.ml/userjs/TiebaImagizer
  9. // @include http://tieba.baidu.com/*
  10. // @exclude http://tieba.baidu.com/tb/*
  11. // @require https://greasyfork.org/scripts/144/code.user.js
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. // 初始化图片上传功能
  16. var loadingURL='http://tieba.baidu.com/tb/static-ihome/img/loading2.gif';
  17. function initImageLoader(callback) {
  18. var fil='http://static.tieba.baidu.com/tb/static-frs/component/sign_shai/flash_image_loader.js';
  19. if(!unsafeWindow.FlashImageLoader) $.getScript(fil,callback); else callback();
  20. }
  21. // 初始化颜色选择面板
  22. function initColorPanel() {
  23. if(utils.colorInput) return;
  24. // Check support for input[type=color]
  25. var i=document.createElement('input');
  26. i.setAttribute('type','color');
  27. if(i.type=='color')
  28. return utils.colorInput=function(id,key,def,func){
  29. return utils.bindProp($('<input type=color id='+id+' class="ge_rsep colorbox">'),'value',key,def,func,['change','keyup']);
  30. };
  31.  
  32. utils.addStyle('\
  33. #colors{display:none;position:absolute;background:white;border:2px ridge;padding:10px;cursor:default;}\
  34. #colors .colors{width:261px;cursor:pointer;margin:2px;border-collapse:separate;border-spacing:1px;background:black;}\
  35. #colors .colors td{display:table-cell !important;width:12px;height:12px;border:none;emptycells:show;}\
  36. .colorbox{width:12px;height:12px;border:1px solid;display:inline-block;position:relative;top:3px;}\
  37. ');
  38. var cp=$('<div id=colors>').click(function(e){e.stopPropagation();}),r,c,t;
  39. r=function(e){
  40. var d=$(e.target).attr('data');
  41. if(d) {
  42. if(e.type=='mouseover') {
  43. if(c) c.css('outline','none');
  44. c=$(e.target).css('outline','1px outset yellow');
  45. $('#ge_vcolor').val(d);
  46. } else cp.owner.setColor(d);
  47. }
  48. };
  49. t=$('<table class=colors>').appendTo(cp).mouseover(r).click(r);
  50. var k=['00','33','66','99','cc','ff'],p=['#ffffff','#ff0000','#00ff00','#0000ff','#ffff00','#00ffff','#ff00ff'];
  51. for(var i=0;i<12;i++) {
  52. r=$('<tr>').appendTo(t);
  53. if(i<6) c='#'+k[i]+k[i]+k[i]; else c=p[i-6];
  54. $('<td>').appendTo(r).css({background:c}).attr('data',c);
  55. if(!i) $('<td rowspan=12 style="background:white;">').appendTo(r);
  56. for(var j=0;j<18;j++) {
  57. c='#'+k[Math.floor(i/6)*3+Math.floor(j/6)]+k[j%6]+k[i%6];
  58. $('<td>').appendTo(r).css({background:c}).attr('data',c);
  59. }
  60. }
  61. t=$('<form>').appendTo(cp);
  62. $('<span id=ge_scolor class="ge_rsep colorbox">').appendTo(t);
  63. r=function(){$('#ge_scolor').css('background',this.value);};
  64. $('<input type=text id=ge_vcolor style="width:60px" class=ge_rsep>').appendTo(t).change(r).keyup(r);
  65. r=function(e){e.preventDefault();cp.owner.setColor($('#ge_scolor').css('background-color'));};
  66. $('<span class=ge_sbtn>OK</span>').appendTo(t).click(r);t.submit(r);
  67. c=null;
  68. utils.colorInput=function(id,key,def,func){
  69. var o=$('<span id='+id+' class=colorbox>'),c=utils.getObj(key,def);
  70. o.css({border:'1px outset white',cursor:'pointer',background:c}).attr('data',c).click(function(e){
  71. if(cp.owner!=o) {
  72. cp.owner=o;cp.appendTo(o).css({top:'auto',bottom:'auto'}).show();
  73. if(cp.offset().top+cp.height()>pageYOffset+innerHeight) cp.css('bottom','14px');
  74. else cp.css('top','14px');
  75. $('#ge_scolor').css('background',e=o.attr('data'));
  76. $('#ge_vcolor').val(e);
  77. } else {cp.owner=null;cp.hide();}
  78. });
  79. o.setColor=function(v){
  80. v=v.replace(/rgb\((\d+),\s?(\d+),\s?(\d+)\)/i,function(v,g1,g2,g3){
  81. v=[g1,g2,g3];for(g1 in v) {v[g1]=parseInt(v[g1]).toString(16);if(v[g1].length<2) v[g1]='0'+v[g1];}
  82. return '#'+v.join('');
  83. });
  84. o.attr('data',v).css('background',v);
  85. utils.setObj(key,v);
  86. cp.owner=null;cp.hide();func();
  87. };
  88. o[0].val=function(){return o.attr('data');};
  89. return o[0];
  90. };
  91. }
  92. function initImagizer(editor){
  93. var st=utils.addStyle(),content=null,ebody=editor.$body,
  94. op=utils.addRPopup(utils.addSButton('图 化')).panel;
  95. utils.uploadImage=null; // tell other scripts that imagizer is initiated
  96. function getStyle() {
  97. var s={},t=[];
  98. if($('#w2iitalic').prop('checked')) t.push('italic');
  99. if($('#w2ibold').prop('checked')) t.push('bold');
  100. t.push($('#w2isize').val()+'px');
  101. if(f.val()) t.push(f.val());
  102. s.font=t.join(' ');
  103. s.color=cf.val();
  104. s.background=$('#w2iabgclr').prop('checked')?cb.val():'inherit';
  105. return s;
  106. }
  107. function undo(){
  108. if(!content) return;
  109. ebody.html(content);content=null;
  110. bUndo.addClass('ge_disabled');
  111. }
  112. function init(){
  113. initImageLoader(function(){
  114. utils.uploadImage=function(data,node) {
  115. function error(a){
  116. alert('图片上传发生错误!');
  117. undo();
  118. unbindEvents();
  119. }
  120. function uploaded(a,d) {
  121. var c=JSON.parse(d);
  122. if(c.error_code) error(); else {
  123. var e='http://imgsrc.baidu.com/forum/pic/item/'+c.info.pic_id_encode+'.jpg';
  124. $(node).replaceWith('<img class="BDE_Image" src="'+e+'" pic_type="0" onload="EditorUI.resizeImage(this,560)">');
  125. unbindEvents();
  126. }
  127. }
  128. function bindEvents(){
  129. unsafeWindow.FlashImageLoader.bind('uploadComplete', uploaded);
  130. unsafeWindow.FlashImageLoader.bind('uploadError',error);
  131. }
  132. function unbindEvents(){
  133. unsafeWindow.FlashImageLoader.unbind('uploadComplete', uploaded);
  134. unsafeWindow.FlashImageLoader.unbind('uploadError',error);
  135. }
  136. $.get('/dc/common/imgtbs',function(r) {
  137. bindEvents();
  138. unsafeWindow.FlashImageLoader.uploadBase64('http://upload.tieba.baidu.com/upload/pic',data.replace(/^data:.*?;base64,/,''),{tbs:r.data.tbs});
  139. },'json');
  140. };
  141. u.removeClass('ge_disabled').text('开始图化').unbind('click').click(word2Image);
  142. });
  143. }
  144. var u=$('<div class="ge_sbtn ge_disabled" style="margin:0 0 2px;">图化组件初始化失败,点击重试</div>').appendTo(op).click(init);
  145. init();
  146. // Extracted from ueditor.js
  147. function extractContents(H) {
  148. function remove(i){i.parentNode.removeChild(i);}
  149. function findParents(i){
  150. var a=[i];
  151. while(i.parentNode!==editor.body&&(i=i.parentNode)) a.unshift(i);
  152. return a;
  153. }
  154. var F = H.startContainer, E = H.endContainer, N = H.startOffset, G = H.endOffset, T = H.document, B = T.createDocumentFragment(), I, K;
  155. if (F.nodeType == 1) {
  156. F = F.childNodes[N] || (I = F.appendChild(T.createTextNode("")))
  157. }
  158. if (E.nodeType == 1) {
  159. E = E.childNodes[G] || (K = E.appendChild(T.createTextNode("")))
  160. }
  161. if (F === E && F.nodeType == 3) {
  162. B.appendChild(T.createTextNode(F.substringData(N, G - N)));
  163. F.deleteData(N, G - N);
  164. H.collapse(true)
  165. return B
  166. }
  167. var J, P, R = B, Q = findParents(F), C = findParents(E);
  168. for (var O = 0; Q[O] == C[O]; ) {
  169. O++
  170. }
  171. for (var M = O, S; S = Q[M]; M++) {
  172. J = S.nextSibling;
  173. if (S == F) {
  174. if (!I) {
  175. if (H.startContainer.nodeType == 3) {
  176. R.appendChild(T.createTextNode(F.nodeValue.slice(N)));
  177. } else {
  178. R.appendChild(F)
  179. }
  180. }
  181. } else {
  182. P = S.cloneNode(false);
  183. R.appendChild(P)
  184. }
  185. while (J) {
  186. if (J === E || J === C[M]) {
  187. break
  188. }
  189. S = J.nextSibling;
  190. R.appendChild(J);
  191. J = S
  192. }
  193. R = P
  194. }
  195. R = B;
  196. if (!Q[O]) {
  197. R.appendChild(Q[O - 1].cloneNode(false));
  198. R = R.firstChild
  199. }
  200. for (var M = O, D; D = C[M]; M++) {
  201. J = D.previousSibling;
  202. if (D == E) {
  203. if (!K && H.endContainer.nodeType == 3) {
  204. R.appendChild(T.createTextNode(E.substringData(0, G)));
  205. E.deleteData(0, G)
  206. }
  207. } else {
  208. P = D.cloneNode(false);
  209. R.appendChild(P)
  210. }
  211. if (M != O || !Q[O]) {
  212. while (J) {
  213. if (J === F) {
  214. break
  215. }
  216. D = J.previousSibling;
  217. R.insertBefore(J, R.firstChild);
  218. J = D
  219. }
  220. }
  221. R = P
  222. }
  223. H.setStartBefore(!C[O] ? C[O - 1] : !Q[O] ? Q[O - 1] : C[O]).collapse(true);
  224. I && remove(I);
  225. K && remove(K);
  226. return B
  227. }
  228. function innerText(o) {
  229. return $('<div>').append(o.childNodes||o.html()).html(function(i,h){return h.replace(/<br>(<\/p>)?|<\/p>/gi,'\n');}).text().replace(/\s+$/,'');
  230. }
  231. function word2Image(){
  232. content=ebody.html();
  233. bUndo.removeClass('ge_disabled');
  234. var fz=parseInt($('#w2isize').val()),loading=$('<img title="双击撤销">').attr('src',loadingURL),
  235. r=editor.selection.getRange(),s=null;
  236. if(!r.collapsed) s=innerText(extractContents(r));
  237. if(s&&/\S/.test(s)) {
  238. r.insertNode(loading[0]);
  239. } else {
  240. s=innerText(ebody);
  241. if(!/\S/.test(s)) return;
  242. ebody.html(loading);
  243. }
  244. var lines=s.split('\n'),w=0,c=document.createElement('canvas'),d=c.getContext('2d'),lh=Math.round(1.5*fz),data=[];
  245. s=getStyle();
  246. d.font=s.font;
  247. lines.forEach(function(line){
  248. line=line.replace(/\s+$/,'');
  249. do {
  250. for(var l=0,j=0;j<line.length;j++) {
  251. l+=d.measureText(line[j]).width;
  252. if(l>560) break; else if(w<l) w=l;
  253. }
  254. data.push(line.substr(0,j));
  255. line=line.substr(j);
  256. } while(line);
  257. });
  258. c.height=lh*data.length;
  259. c.width=w;
  260. if($('#w2ishadow').prop('checked')) {
  261. d.shadowColor='gray';
  262. d.shadowBlur=d.shadowOffsetY=d.shadowOffsetX=Math.ceil(fz/25);
  263. }
  264. if($('#w2iabgclr').prop('checked')) {
  265. d.fillStyle=s.background;
  266. d.fillRect(0,0,w,c.height);
  267. }
  268. d.font=s.font;
  269. d.fillStyle=d.strokeStyle=s.color;
  270. e=$('#w2istroke').prop('checked')?d.strokeText:d.fillText;
  271. i=0;data.forEach(function(j){e.call(d,j,0,fz+lh*(i++));});
  272. utils.uploadImage(c.toDataURL(),loading);
  273. }
  274. function checkFont(e) {
  275. e=getStyle();var i,s='';
  276. for(i in e) e[i]+=' !important';
  277. if($('#w2ipreview').prop('checked')) st.html('#ueditor_replace{font:'+e.font+';color:'+e.color+';background:'+e.background+'}');
  278. else st.html('');
  279. for(i in e) s+=i+':'+e[i]+';';
  280. f.css('cssText',s);
  281. }
  282. utils.addStyle('#w2iface{max-width:800px;max-height:400px;}');
  283. var ff=utils.list('w2ifaces','w2ifaceid',null,['微软雅黑']).load();
  284. var f=$('<select id=w2iface>').appendTo($('<label>字体:</label>').appendTo(op)).change(function(e){ff.load(f.prop('selectedIndex'));checkFont();});
  285. ff.list.forEach(function(i){$('<option>'+i+'</option>').appendTo(f);});f.prop('selectedIndex',ff.last);
  286. $('<span class=ge_sbtn>+</span>').appendTo(op).click(function(e){
  287. if(e=prompt('请输入字体名称:')) {
  288. ff.load(ff.push(e));
  289. $('<option>').text(e).appendTo(f);
  290. f.val(e);checkFont();
  291. }
  292. });
  293. $('<span class=ge_sbtn>-</span>').appendTo(op).click(function(e){
  294. e=f.prop('selectedIndex');
  295. f.children(':eq('+e+')').remove();
  296. ff.pop(e);ff.load(f.prop('selectedIndex'));checkFont();
  297. });
  298. initColorPanel();
  299. var cf,cb;
  300. utils.bindProp($('<input type=checkbox id=w2ipreview>').appendTo(op),'checked','w2ipreview',false,checkFont);
  301. $('<label for=w2ipreview>预览</label><br><label for=w2icolor>颜色:</label>').appendTo(op);
  302. $(cf=utils.colorInput('w2icolor','w2icolor','#2222ff',checkFont)).appendTo(op).addClass('ge_rsep');
  303. $('<label for=w2isize>大小:</label>').appendTo(op);
  304. utils.bindProp($('<input type=number id=w2isize min=9 class=ge_rsep style="height:18px;width:40px;">').appendTo(op),'value','w2isize',22,checkFont);
  305. utils.bindProp($('<input type=checkbox id=w2iabgclr>').appendTo(op),'checked','w2iabgclr',false,checkFont);
  306. $('<label for=w2iabgclr>背景色:</label>').appendTo(op);
  307. $(cb=utils.colorInput('w2ibgclr','w2ibgclr','#efe4b0',checkFont)).appendTo(op);
  308. $('<br>').appendTo(op);
  309. utils.bindProp($('<input type=checkbox id=w2ibold>').appendTo(op),'checked','w2ibold',false,checkFont);
  310. $('<label for=w2ibold class=ge_rsep>加粗</label>').appendTo(op);
  311. utils.bindProp($('<input type=checkbox id=w2iitalic>').appendTo(op),'checked','w2iitalic',false,checkFont);
  312. $('<label for=w2iitalic class=ge_rsep>倾斜</label>').appendTo(op);
  313. utils.bindProp($('<input type=checkbox id=w2ishadow>').appendTo(op),'checked','w2ishadow',false,checkFont);
  314. $('<label for=w2ishadow class=ge_rsep>阴影</label>').appendTo(op);
  315. utils.bindProp($('<input type=checkbox id=w2istroke>').appendTo(op),'checked','w2istroke',false,checkFont);
  316. $('<label for=w2istroke class=ge_rsep>镂空</label>').appendTo(op);
  317. var bUndo=$('<span class="ge_sbtn ge_disabled" title="回到最后一次图化前的状态">撤销图化</span>').appendTo(op).click(undo);
  318. f.prop('selectedIndex',ff.last);checkFont();
  319. }
  320.  
  321. if(unsafeWindow.PosterContext&&unsafeWindow.PosterContext.isPostAllowed()) utils.wait(unsafeWindow,'test_editor',initImagizer);