1/*! WysiBB v1.5.1 2014-03-26 2 Author: Vadim Dobroskok 3 */ 4if (typeof (WBBLANG)=="undefined") {WBBLANG = {};} 5WBBLANG['en'] = CURLANG = { 6 bold: "Bold", 7 italic: "Italic", 8 underline: "Underline", 9 strike: "Strike", 10 link: "Link", 11 img: "Insert image", 12 sup: "Superscript", 13 sub: "Subscript", 14 justifyleft: "Align left", 15 justifycenter: "Align center", 16 justifyright: "Align right", 17 table: "Insert table", 18 bullist: "⢠Unordered list", 19 numlist: "1. Ordered list", 20 quote: "Quote", 21 offtop: "Offtop", 22 code: "Code", 23 spoiler: "Spoiler", 24 fontcolor: "Font color", 25 fontsize: "Font size", 26 fontfamily: "Font family", 27 fs_verysmall: "Very small", 28 fs_small: "Small", 29 fs_normal: "Normal", 30 fs_big: "Big", 31 fs_verybig: "Very big", 32 smilebox: "Insert emoticon", 33 video: "Insert YouTube", 34 removeFormat:"Remove Format", 35 36 modal_link_title: "Insert link", 37 modal_link_text: "Display text", 38 modal_link_url: "URL", 39 modal_email_text: "Display email", 40 modal_email_url: "Email", 41 modal_link_tab1: "Insert URL", 42 43 modal_img_title: "Insert image", 44 modal_img_tab1: "Insert URL", 45 modal_img_tab2: "Upload image", 46 modal_imgsrc_text: "Enter image URL", 47 modal_img_btn: "Choose file", 48 add_attach: "Add Attachment", 49 50 modal_video_text: "Enter the URL of the video", 51 52 close: "Close", 53 save: "Save", 54 cancel: "Cancel", 55 remove: "Delete", 56 57 validation_err: "The entered data is invalid", 58 error_onupload: "Error during file upload", 59 60 fileupload_text1: "Drop file here", 61 fileupload_text2: "or", 62 63 loading: "Loading", 64 auto: "Auto", 65 views: "Views", 66 downloads: "Downloads", 67 68 //smiles 69 sm1: "Smile", 70 sm2: "Laughter", 71 sm3: "Wink", 72 sm4: "Thank you", 73 sm5: "Scold", 74 sm6: "Shock", 75 sm7: "Angry", 76 sm8: "Pain", 77 sm9: "Sick" 78}; 79wbbdebug=true; 80(function($) { 81 'use strict'; 82 $.wysibb = function(txtArea,settings) { 83 $(txtArea).data("wbb",this); 84 85 if (settings && settings.deflang && typeof(WBBLANG[settings.deflang])!="undefined") {CURLANG = WBBLANG[settings.deflang];} 86 if (settings && settings.lang && typeof(WBBLANG[settings.lang])!="undefined") {CURLANG = WBBLANG[settings.lang];} 87 this.txtArea=txtArea; 88 this.$txtArea=$(txtArea); 89 var id = this.$txtArea.attr("id") || this.setUID(this.txtArea); 90 this.options = { 91 bbmode: false, 92 onlyBBmode: false, 93 themeName: "default", 94 bodyClass: "", 95 lang: "ru", 96 tabInsert: true, 97// toolbar: false, 98 //img upload config 99 imgupload: false, 100 img_uploadurl: "/iupload.php", 101 img_maxwidth: 800, 102 img_maxheight: 800, 103 hotkeys: true, 104 showHotkeys: true, 105 autoresize: true, 106 resize_maxheight: 800, 107 loadPageStyles: true, 108 traceTextarea: true, 109// direction: "ltr", 110 smileConversion: true, 111 112 //END img upload config 113 buttons: "bold,italic,underline,strike,sup,sub,|,img,video,link,|,bullist,numlist,|,fontcolor,fontsize,fontfamily,|,justifyleft,justifycenter,justifyright,|,quote,code,table,removeFormat", 114 allButtons: { 115 bold : { 116 title: CURLANG.bold, 117 buttonHTML: '<span class="fonticon ve-tlb-bold1">\uE018</span>', 118 excmd: 'bold', 119 hotkey: 'ctrl+b', 120 transform : { 121 '<b>{SELTEXT}</b>':"[b]{SELTEXT}[/b]", 122 '<strong>{SELTEXT}</strong>':"[b]{SELTEXT}[/b]" 123 } 124 }, 125 italic : { 126 title: CURLANG.italic, 127 buttonHTML: '<span class="fonticon ve-tlb-italic1">\uE001</span>', 128 excmd: 'italic', 129 hotkey: 'ctrl+i', 130 transform : { 131 '<i>{SELTEXT}</i>':"[i]{SELTEXT}[/i]", 132 '<em>{SELTEXT}</em>':"[i]{SELTEXT}[/i]" 133 } 134 }, 135 underline : { 136 title: CURLANG.underline, 137 buttonHTML: '<span class="fonticon ve-tlb-underline1">\uE002</span>', 138 excmd: 'underline', 139 hotkey: 'ctrl+u', 140 transform : { 141 '<u>{SELTEXT}</u>':"[u]{SELTEXT}[/u]" 142 } 143 }, 144 strike : { 145 title: CURLANG.strike, 146 buttonHTML: '<span class="fonticon fi-stroke1 ve-tlb-strike1">\uE003</span>', 147 excmd: 'strikeThrough', 148 transform : { 149 '<strike>{SELTEXT}</strike>':"[s]{SELTEXT}[/s]", 150 '<s>{SELTEXT}</s>':"[s]{SELTEXT}[/s]" 151 } 152 }, 153 sup : { 154 title: CURLANG.sup, 155 buttonHTML: '<span class="fonticon ve-tlb-sup1">\uE005</span>', 156 excmd: 'superscript', 157 transform : { 158 '<sup>{SELTEXT}</sup>':"[sup]{SELTEXT}[/sup]" 159 } 160 }, 161 sub : { 162 title: CURLANG.sub, 163 buttonHTML: '<span class="fonticon ve-tlb-sub1">\uE004</span>', 164 excmd: 'subscript', 165 transform : { 166 '<sub>{SELTEXT}</sub>':"[sub]{SELTEXT}[/sub]" 167 } 168 }, 169 link : { 170 title: CURLANG.link, 171 buttonHTML: '<span class="fonticon ve-tlb-link1">\uE007</span>', 172 hotkey: 'ctrl+shift+2', 173 modal: { 174 title: CURLANG.modal_link_title, 175 width: "500px", 176 tabs: [ 177 { 178 input: [ 179 {param: "SELTEXT",title:CURLANG.modal_link_text, type: "div"}, 180 {param: "URL",title:CURLANG.modal_link_url,validation: '^http(s)?://'} 181 ] 182 } 183 ] 184 }, 185 transform : { 186 '<a href="{URL}">{SELTEXT}</a>':"[url={URL}]{SELTEXT}[/url]", 187 '<a href="{URL}">
187{URL}</a>':"[url]{URL}[/url]" 188 } 189 }, 190 img : { 191 title: CURLANG.img, 192 buttonHTML: '<span class="fonticon ve-tlb-img1">\uE006</span>', 193 hotkey: 'ctrl+shift+1', 194 addWrap: true, 195 modal: { 196 title: CURLANG.modal_img_title, 197 width: "600px", 198 tabs: [ 199 { 200 title: CURLANG.modal_img_tab1, 201 input: [ 202 {param: "SRC",title:CURLANG.modal_imgsrc_text,validation: '^http(s)?://.*?\.(jpg|png|gif|jpeg)$'} 203 ] 204 } 205 ], 206 onLoad: this.imgLoadModal 207 }, 208 transform : { 209 '<img src="{SRC}" />':"[img]{SRC}[/img]", 210 '<img src="{SRC}" width="{WIDTH}" height="{HEIGHT}"/>':"[img width={WIDTH},height={HEIGHT}]{SRC}[/img]" 211 } 212 }, 213 bullist : { 214 title: CURLANG.bullist, 215 buttonHTML: '<span class="fonticon ve-tlb-list1">\uE009</span>', 216 excmd: 'insertUnorderedList', 217 transform : { 218 '<ul>{SELTEXT}</ul>':"[list]{SELTEXT}[/list]", 219 '<li>{SELTEXT}</li>':"[*]{SELTEXT}[/*]" 220 } 221 }, 222 numlist : { 223 title: CURLANG.numlist, 224 buttonHTML: '<span class="fonticon ve-tlb-numlist1">\uE00a</span>', 225 excmd: 'insertOrderedList', 226 transform : { 227 '<ol>{SELTEXT}</ol>':"[list=1]{SELTEXT}[/list]", 228 '<li>{SELTEXT}</li>':"[*]{SELTEXT}[/*]" 229 } 230 }, 231 quote : { 232 title: CURLANG.quote, 233 buttonHTML: '<span class="fonticon ve-tlb-quote1">\uE00c</span>', 234 hotkey: 'ctrl+shift+3', 235 //subInsert: true, 236 transform : { 237 '<blockquote>{SELTEXT}</blockquote>':"[quote]{SELTEXT}[/quote]" 238 } 239 }, 240 code : { 241 title: CURLANG.code, 242 buttonText: '[code]', 243 /* buttonHTML: '<span class="fonticon">\uE00d</span>', */ 244 hotkey: 'ctrl+shift+4', 245 onlyClearText: true, 246 transform : { 247 '<code>{SELTEXT}</code>':"[code]{SELTEXT}[/code]" 248 } 249 }, 250 offtop : { 251 title: CURLANG.offtop, 252 buttonText: 'offtop', 253 transform : { 254 '<span style="font-size:10px;color:#ccc">{SELTEXT}</span>':"[offtop]{SELTEXT}[/offtop]" 255 } 256 }, 257 fontcolor: { 258 type: "colorpicker", 259 title: CURLANG.fontcolor, 260 excmd: "foreColor", 261 valueBBname: "color", 262 subInsert: true, 263 colors: "#000000,#444444,#666666,#999999,#b6b6b6,#cccccc,#d8d8d8,#efefef,#f4f4f4,#ffffff,-, \ 264 #ff0000,#980000,#ff7700,#ffff00,#00ff00,#00ffff,#1e84cc,#0000ff,#9900ff,#ff00ff,-, \ 265 #f4cccc,#dbb0a7,#fce5cd,#fff2cc,#d9ead3,#d0e0e3,#c9daf8,#cfe2f3,#d9d2e9,#ead1dc, \ 266 #ea9999,#dd7e6b,#f9cb9c,#ffe599,#b6d7a8,#a2c4c9,#a4c2f4,#9fc5e8,#b4a7d6,#d5a6bd, \ 267 #e06666,#cc4125,#f6b26b,#ffd966,#93c47d,#76a5af,#6d9eeb,#6fa8dc,#8e7cc3,#c27ba0, \ 268 #cc0000,#a61c00,#e69138,#f1c232,#6aa84f,#45818e,#3c78d8,#3d85c6,#674ea7,#a64d79, \ 269 #900000,#85200C,#B45F06,#BF9000,#38761D,#134F5C,#1155Cc,#0B5394,#351C75,#741B47, \ 270 #660000,#5B0F00,#783F04,#7F6000,#274E13,#0C343D,#1C4587,#073763,#20124D,#4C1130", 271 transform: { 272 '<font color="{COLOR}">{SELTEXT}</font>':'[color={COLOR}]{SELTEXT}[/color]' 273 } 274 }, 275 table: { 276 type: "table", 277 title: CURLANG.table, 278 cols: 10, 279 rows: 10, 280 cellwidth: 20, 281 transform: { 282 '<td>{SELTEXT}</td>': '[td]{SELTEXT}[/td]', 283 '<tr>{SELTEXT}</tr>': '[tr]{SELTEXT}[/tr]', 284 '<table class="wbb-table">{SELTEXT}</table>': '[table]{SELTEXT}[/table]' 285 }, 286 skipRules: true 287 }, 288 fontsize: { 289 type: 'select', 290 title: CURLANG.fontsize, 291 options: "fs_verysmall,fs_small,fs_normal,fs_big,fs_verybig" 292 }, 293 fontfamily: { 294 type: 'select', 295 title: CURLANG.fontfamily, 296 excmd: 'fontName', 297 valueBBname: "font", 298 options: [ 299 {title: "Arial",exvalue: "Arial"}, 300 {title: "Comic Sans MS",exvalue: "Comic Sans MS"}, 301 {title: "Courier New",exvalue: "Courier New"}, 302 {title: "Georgia",exvalue: "Georgia"}, 303 {title: "Lucida Sans Unicode",exvalue: "Lucida Sans Unicode"}, 304 {title: "Tahoma",exvalue: "Tahoma"}, 305 {title: "Times New Roman",exvalue: "Times New Roman"}, 306 {title: "Trebuchet MS",exvalue: "Trebuchet MS"}, 307 {title: "Verdana",exvalue: "Verdana"} 308 ], 309 transform: { 310 '<font face="{FONT}">{SELTEXT}</font>':'[font={FONT}]{SELTEXT}[/font]' 311 } 312 }, 313 smilebox: { 314 type: 'smilebox', 315 title: CURLANG.smilebox, 316 buttonHTML: '<span class="fonticon ve-tlb-smilebox1">\uE00b</span>' 317 }, 318 justifyleft: { 319 title: CURLANG.justifyleft, 320 buttonHTML: '<span class="fonticon ve-tlb-textleft1">\uE015</span>', 321 groupkey: 'align', 322 transform: { 323 '<p style="text-align:left">{SELTEXT}</p>': '[left]{SELTEXT}[/left]' 324 } 325 }, 326 justifyright: { 327 title: CURLANG.justifyright, 328 buttonHTML: '<span class="fonticon ve-tlb-textright1">\uE016</span>', 329 groupkey: 'align', 330 transform: { 331 '<p style="text-align:right">{SELTEXT}</p>': '[right]{SELTEXT}[/right]' 332 } 333 }, 334 justifycenter: { 335 title: CURLANG.justifycenter, 336 buttonHTML: '<span class="fonticon ve-tlb-textcenter1">\uE014</span>', 337 groupkey: 'align', 338 transform: { 339 '<p style="text-align:center">{SELTEXT}</p>': '[center]{SELTEXT}[/center]' 340 } 341 }, 342 video: { 343 title: CURLANG.video, 344 buttonHTML: '<span class="fonticon ve-tlb-video1">\uE008</span>', 345 modal: { 346 title: CURLANG.video, 347 width: "600px", 348 tabs: [ 349 { 350 title: CURLANG.video, 351 input: [ 352 {param: "SRC",title:CURLANG.modal_video_text} 353 ] 354 } 355 ], 356 onSubmit: function(cmd,opt,queryState) { 357 var url = this.$modal.find('input[name="SRC"]').val(); 358 if (url) { 359 url = url.replace(/^\s+/,"").replace(/\s+$/,""); 360 } 361 var a; 362 if (url.indexOf("youtu.be")!=-1) { 363 a = url.match(/^http[s]*:\/\/youtu\.be\/([a-z0-9_-]+)/i); 364 }else{ 365 a = url.match(/^http[s]*:\/\/www\.youtube\.com\/watch\?.*?v=([a-z0-9_-]+)/i); 366 } 367 if (a && a.length==2) { 368 var code = a[1]; 369 this.insertAtCursor(this.getCodeByCommand(cmd,{src:code})); 370 } 371 this.closeModal(); 372 this.updateUI(); 373 return false;
374 } 375 }, 376 transform: { 377 '<iframe src="http://www.youtube.com/embed/{SRC}" width="640" height="480" frameborder="0"></iframe>':'[video]{SRC}[/video]' 378 } 379 }, 380 381 //select options 382 fs_verysmall: { 383 title: CURLANG.fs_verysmall, 384 buttonText: "fs1", 385 excmd: 'fontSize', 386 exvalue: "1", 387 transform: { 388 '<font size="1">{SELTEXT}</font>':'[size=50]{SELTEXT}[/size]' 389 } 390 }, 391 fs_small: { 392 title: CURLANG.fs_small, 393 buttonText: "fs2", 394 excmd: 'fontSize', 395 exvalue: "2", 396 transform: { 397 '<font size="2">{SELTEXT}</font>':'[size=85]{SELTEXT}[/size]' 398 } 399 }, 400 fs_normal: { 401 title: CURLANG.fs_normal, 402 buttonText: "fs3", 403 excmd: 'fontSize', 404 exvalue: "3", 405 transform: { 406 '<font size="3">{SELTEXT}</font>':'[size=100]{SELTEXT}[/size]' 407 } 408 }, 409 fs_big: { 410 title: CURLANG.fs_big, 411 buttonText: "fs4", 412 excmd: 'fontSize', 413 exvalue: "4", 414 transform: { 415 '<font size="4">{SELTEXT}</font>':'[size=150]{SELTEXT}[/size]' 416 } 417 }, 418 fs_verybig: { 419 title: CURLANG.fs_verybig, 420 buttonText: "fs5", 421 excmd: 'fontSize', 422 exvalue: "6", 423 transform: { 424 '<font size="6">{SELTEXT}</font>':'[size=200]{SELTEXT}[/size]' 425 } 426 }, 427 428 removeformat: { 429 title: CURLANG.removeFormat, 430 buttonHTML: '<span class="fonticon ve-tlb-removeformat1">\uE00f</span>', 431 excmd: "removeFormat" 432 } 433 }, 434 systr: { 435 '<br/>':"\n", 436 '<span class="wbbtab">{SELTEXT}</span>': ' {SELTEXT}' 437 }, 438 customRules: { 439 td: [["[td]{SELTEXT}[/td]",{seltext: {rgx:false,attr:false,sel:false}}]], 440 tr: [["[tr]{SELTEXT}[/tr]",{seltext: {rgx:false,attr:false,sel:false}}]], 441 table: [["[table]{SELTEXT}[/table]",{seltext: {rgx:false,attr:false,sel:false}}]] 442 //blockquote: [[" {SELTEXT}",{seltext: {rgx:false,attr:false,sel:false}}]] 443 }, 444 smileList: [ 445 //{title:CURLANG.sm1, img: '<img src="{themePrefix}{themeName}/img/smiles/sm1.png" class="sm">', bbcode:":)"}, 446 ], 447 attrWrap: ['src','color','href'] //use becouse FF and IE change values for this attr, modify [attr] to _[attr] 448 } 449 450 //FIX for Opera. Wait while iframe loaded 451 this.inited=this.options.onlyBBmode; 452 453 //init css prefix, if not set 454 if (!this.options.themePrefix) { 455 $('link').each($.proxy(function(idx, el) { 456 var sriptMatch = $(el).get(0).href.match(/(.*\/)(.*)\/wbbtheme\.css.*$/); 457 if (sriptMatch !== null) { 458 this.options.themeName = sriptMatch[2]; 459 this.options.themePrefix = sriptMatch[1]; 460 } 461 },this)); 462 } 463 464 //check for preset 465 if (typeof(WBBPRESET)!="undefined") { 466 if (WBBPRESET.allButtons) { 467 //clear transform 468 $.each(WBBPRESET.allButtons,$.proxy(function(k,v) { 469 if (v.transform && this.options.allButtons[k]) { 470 delete this.options.allButtons[k].transform; 471 } 472 },this)); 473 } 474 $.extend(true,this.options,WBBPRESET); 475 } 476 477 if (settings && settings.allButtons) { 478 $.each(settings.allButtons,$.proxy(function(k,v) { 479 if (v.transform && this.options.allButtons[k]) { 480 delete this.options.allButtons[k].transform; 481 } 482 },this)); 483 } 484 $.extend(true,this.options,settings); 485 this.init(); 486 } 487 488 $.wysibb.prototype = { 489 lastid : 1, 490 init: function() { 491 $.log("Init",this); 492 //check for mobile 493 this.isMobile = function(a) {(/android|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|meego.+mobile|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a))}(navigator.userAgent||navigator.vendor||window.opera); 494 495 //use bbmode on mobile devices 496 //this.isMobile = true; //TEMP 497 if (this.options.onlyBBmode===true) {this.options.bbmode=true;} 498 //create array of controls, for queryState 499 this.controllers = []; 500 501 //convert button string to array 502 this.options.buttons = this.options.buttons.toLowerCase(); 503 this.options.buttons = this.options.buttons.split(","); 504 505 //init system transforms 506 this.options.allButtons["_systr"] = {}; 507 this.options.allButtons["_systr"]["transform"]= this.options.systr; 508 509 this.smileFind(); 510 this.initTransforms(); 511 this.build(); 512 this.initModal(); 513 if (this.options.hotkeys===true && !this.isMobile) { 514 this.initHotkeys(); 515 } 516 517 //sort smiles 518 if (this.options.smileList && this.options.smileList.length>0) { 519 this.options.smileList.sort(function(a,b) { 520 return (b.bbcode.length-a.bbcode.length); 521 }) 522 } 523 524 this.$txtArea.parents("form").bind("submit",$.proxy(function() { 525 this.sync(); 526 return true; 527 },this)); 528 529 530 //phpbb2 531 this.$txtArea.parents("form").find("input[id*='preview'],input[id*='submit'],input[class*='preview'],input[class*='submit'],input[name*='preview'],input[name*='submit']").bind("mousedown",$.proxy(function() { 532 this.sync(); 533 setTimeout($.proxy(function() { 534 if (this.options.bbmode===false) { 535 this.$txtArea.removeAttr("wbbsync").val(""); 536 } 537 },this),1000); 538 },this)); 539 //end phpbb2 540 541 if (this.options.initCallback) { 542 this.options.initCallback.call(this); 543 } 544 545 $.log(this); 546 547 }, 548 initTransforms: function() { 549 $.log("Create rules for transform HTML=>BB"); 550 var o = this.options; 551 //need to check for active buttons 552 if (!o.rules) {o.rules={};} 553 if (!o.groups) {o.groups={};} //use for groupkey, For example: justifyleft,justifyright,justifycenter. It is must replace each other. 554 var btnlist = o.buttons.slice(); 555 556 //add system transform 557 btnlist.push("_systr"); 558 for (var bidx=0; bidx<btnlist.length; bidx++) { 559 var ob = o.allButtons[btnlist[bidx]]; 560 if (!ob ) {continue;} 561 ob.en=true; 562 563 //check for simplebbcode 564 if (ob.simplebbcode && $.isArray(ob.simplebbcode) && ob.simplebbcode.length==2) { 565 ob.bbcode = ob.html = ob.simplebbcode[0]+"{SELTEXT}"+ob.simplebbcode[1]; 566 if (ob.transform) delete ob.transform; 567 if (ob.modal) delete ob.modal; 568 } 569 570 //add transforms to option list 571 if (ob.type=="select" && typeof(ob.options)=="string") { 572 var olist = ob.options.split(","); 573 $.each(olist,function(i,op) { 574 if ($.inArray(op,btnlist)==-1) { 575 btnlist.push(op); 576 } 577 }); 578 } 579 if (ob.transform && ob.skipRules!==true) { 580 var obtr = $.extend({},ob.transform); 581 582 /* if (ob.addWrap) { 583 //addWrap 584 $.log("needWrap"); 585 for (var bhtml in obtr) { 586 var bbcode = ob.transform[bhtml]; 587 var newhtml = '<span wbb="'+btnlist[bidx]+'">'+bhtml+'</span>'; 588 obtr[newhtml] = bbcode; 589 } 590 } */ 591 592 for (var bhtml in obtr) { 593 var orightml = bhtml; 594 var bbcode = obtr[bhtml]; 595 596 //create root selector for isContain bbmode 597 if (!ob.bbSelector) {ob.bbSelector=[];} 598 if ($.inArray(bbcode,ob.bbSelector)==-1) { 599 ob.bbSelector.push(bbcode); 600 } 601 if (this.options.onlyBBmode===false) { 602 603 //wrap attributes 604 bhtml = this.wrapAttrs(bhtml); 605 606 607 var $bel = $(document.createElement('DIV')).append($(this.elFromString(bhtml,document))); 608 var rootSelector = this.filterByNode($bel.children()); 609 610 611 //check if current rootSelector is exist, create unique selector for each transform (1.2.2) 612 if (rootSelector=="div" || typeof(o.rules[rootSelector])!="undefined") { 613 //create unique selector 614 $.log("create unique selector: "+rootSelector); 615 this.setUID($bel.children()); 616 rootSelector = this.filterByNode($bel.children()); 617 $.log("New rootSelector: "+rootSelector); 618 //replace transform with unique selector 619 var nhtml2 = $bel.html(); 620 nhtml2 = this.unwrapAttrs(nhtml2); 621 var obhtml = this.unwrapAttrs(bhtml); 622 623 624 ob.transform[nhtml2]=bbcode; 625 delete ob.transform[obhtml]; 626 627 bhtml=nhtml2; 628 orightml = nhtml2; 629 } 630 631 //create root selector for isContain 632 if (!ob.excmd) { 633 if (!ob.rootSelector) {ob.rootSelector=[];} 634 ob.rootSelector.push(rootSelector); 635 } 636 637 //check for rules on this rootSeletor 638 if (typeof(o.rules[rootSelector])=="undefined") { 639 o.rules[rootSelector]=[]; 640 } 641 var crules={}; 642 643 if (bhtml.match(/\{\S+?\}/)) { 644 $bel.find('*').each($.proxy(function(idx,el) { 645 //check attributes 646 647 var attributes = this.getAttributeList(el); 648 $.each(attributes,$.proxy(function(i, item) { 649 var attr = $(el).attr(item); 650 if (item.substr(0,1)=='_') { 651 item = item.substr(1); 652 } 653 654 var r = attr.match(/\{\S+?\}/g); 655 if (r) { 656 for (var a=0; a<r.length; a++) { 657 var rname = r[a].substr(1,r[a].length-2); 658 rname = rname.replace(this.getValidationRGX(rname),""); 659 var p = this.relFilterByNode(el,rootSelector); 660 var regRepl = (attr!=r[a]) ? this.getRegexpReplace(attr,r[a]):false; 661 crules[rname.toLowerCase()]={sel:(p) ? $.trim(p):false,attr:item,rgx:regRepl} 662 } 663 } 664 },this)); 665 666 //check for text 667 var sl=[]; 668 if (!$(el).is("iframe")) { 669 $(el).contents().filter(function() {return this.nodeType===3}).each($.proxy(function(i,rel) { 670 var txt = rel.textContent || rel.data; 671 if (typeof(txt)=="undefined") {return true;} 672 var r = txt.match(/\{\S+?\}/g) 673 if (r) { 674 for (var a=0; a<r.length; a++) { 675 var rname = r[a].substr(1,r[a].length-2); 676 rname = rname.replace(this.getValidationRGX(rname),""); 677 var p = this.relFilterByNode(el,rootSelector); 678 var regRepl = (txt!=r[a]) ? this.getRegexpReplace(txt,r[a]):false; 679 var sel = (p) ? $.trim(p):false; 680 if ($.inArray(sel,sl)>-1 || $(rel).parent().contents().size()>1) { 681 //has dublicate and not one children, need wrap 682 var nel = $("<span>").html("{"+rname+"}"); 683 this.setUID(nel,"wbb"); 684 var start = (txt.indexOf(rname)+rname.length)+1; 685 var after_txt = txt.substr(start,txt.length-start); 686 //create wrap element 687 rel.data = txt.substr(0,txt.indexOf(rname)-1); 688 $(rel).after(this.elFromString(after_txt,document)).after(nel); 689 690 sel=((sel) ? sel+" ":"")+this.filterByNode(nel); 691 regRepl=false; 692 } 693 crules[rname.toLowerCase()]={sel:sel,attr:false,rgx:regRepl} 694 sl[sl.length]=sel; 695 } 696 } 697 },this)); 698 } 699 sl=null; 700 701 702 },this)); 703 704 var nbhtml = $bel.html(); 705 //UnWrap attributes 706 nbhtml = this.unwrapAttrs(nbhtml); 707 if (orightml!=nbhtml) { 708 //if we modify html, replace it 709 delete ob.transform[orightml]; 710 ob.transform[nbhtml]=bbcode; 711 bhtml=nbhtml; 712 } 713 714 } 715 o.rules[rootSelector].push([bbcode,crules]); 716 717 //check for onlyClearText 718 if (ob.onlyClearText===true) { 719 if (!this.cleartext) {this.cleartext={};} 720 this.cleartext[rootSelector]=btnlist[bidx]; 721 } 722 723 //check for groupkey 724 if (ob.groupkey) { 725 if (!o.groups[ob.groupkey]) {o.groups[ob.groupkey]=[]} 726 o.groups[ob.groupkey].push(rootSelector); 727 } 728 } 729 } 730 731 //sort rootSelector 732 if (ob.rootSelector) { 733 this.sortArray(ob.rootSelector,-1); 734 } 735 736 var htmll = $.map(ob.transform,function(bb,html) {return html}).sort(function(a,b) { 737 return ((b[0] || "").length-(a[0] || "").length) 738 }); 739 ob.bbcode = ob.transform[htmll[0]]; 740 ob.html = htmll[0]; 741 } 742 }; 743 744 this.options.btnlist=btnlist; //use for transforms, becouse select elements not present in buttons 745 746 //add custom rules, for table,tr,td and other 747 $.extend(o.rules,this.options.customRules); 748 749 //smile rules 750 o.srules={}; 751 if (this.options.smileList) { 752 $.each(o.smileList,$.proxy(function(i,sm) { 753 var $sm = $(this.strf(sm.img,o)); 754 var f = this.filterByNode($sm); 755 o.srules[f]=[sm.bbcode,sm.img]; 756 },this)); 757 } 758 759 //sort transforms by bbcode length desc 760 for (var rootsel in o.rules) { 761 this.options.rules[rootsel].sort(function(a,b) { 762 return (b[0].length-a[0].length) 763 }); 764 } 765 766 //create rootsel list 767 this.rsellist = []; 768 for (var rootsel in this.options.rules) { 769 this.rsellist.push(rootsel); 770 } 771 this.sortArray(this.rsellist,-1); 772 }, 773 774 //BUILD 775 build: function() { 776 $.log("Build editor"); 777 778 //this.$editor = $('<div class="wysibb">'); 779 this.$editor = $('<div>').addClass("wysibb"); 780 781 if (this.isMobile) { 782 this.$editor.addClass("wysibb-mobile"); 783 } 784 785 //set direction if defined 786 if (this.options.direction) {this.$editor.css("direction",this.options.direction)} 787 788 this.$editor.insertAfter(this.txtArea).append(this.txtArea); 789 790 this.startHeight = this.$txtArea.outerHeight(); 791 this.$txtArea.addClass("wysibb-texarea"); 792 this.buildToolbar(); 793 //Build iframe if needed 794 this.$txtArea.wrap('<div class="wysibb-text">'); 795 796 if (this.options.onlyBBmode===false) { 797 var height = this.options.minheight || this.$txtArea.outerHeight(); 798 var maxheight = this.options.resize_maxheight; 799 var mheight = (this.options.autoresize===true) ? this.options.resize_maxheight:height; 800 this.$body = $(this.strf('<div class="wysibb-text-editor" style="max-height:{maxheight}px;min-height:{height}px"></div>',{maxheight:mheight,height:height})).insertAfter(this.$txtArea); 801 this.body = this.$body[0]; 802 this.$txtArea.hide(); 803 804 if (height>32) {
805 this.$toolbar.css("max-height",height); 806 } 807 808 $.log("WysiBB loaded"); 809 810 this.$body.addClass("wysibb-body").addClass(this.options.bodyClass); 811 812 //set direction if defined 813 if (this.options.direction) {this.$body.css("direction",this.options.direction)} 814 815 816 if ('contentEditable' in this.body) { 817 this.body.contentEditable=true; 818 try{ 819 //fix for mfirefox 820 //document.execCommand('enableObjectResizing', false, 'false'); //disable image resizing 821 document.execCommand('StyleWithCSS', false, false); 822 //document.designMode = "on"; 823 this.$body.append("<span></span>"); 824 }catch(e) {} 825 }else{ 826 //use onlybbmode 827 this.options.onlyBBmode=this.options.bbmode=true; 828 } 829 830 //check for exist content in textarea 831 if (this.txtArea.value.length>0) { 832 this.txtAreaInitContent(); 833 } 834 835 836 //clear html on paste from external editors 837 this.$body.bind('keydown', $.proxy(function(e) { 838 if ((e.which == 86 && (e.ctrlKey==true || e.metaKey==true)) || (e.which == 45 && (e.shiftKey==true || e.metaKey==true))) { 839 if (!this.$pasteBlock) { 840 this.saveRange(); 841 this.$pasteBlock = $(this.elFromString('<div style="opacity:0;" contenteditable="true">\uFEFF</div>')); 842 843 this.$pasteBlock.appendTo(this.body); 844 //if (!$.support.search?type=2) {this.$pasteBlock.focus();} //IE 7,8 FIX 845 setTimeout($.proxy(function() { 846 this.clearPaste(this.$pasteBlock); 847 var rdata = '<span>'+this.$pasteBlock.html()+'</span>'; 848 this.$body.attr("contentEditable","true"); 849 this.$pasteBlock.blur().remove(); 850 this.body.focus(); 851 852 if (this.cleartext) { 853 $.log("Check if paste to clearText Block"); 854 if (this.isInClearTextBlock()) { 855 rdata = this.toBB(rdata).replace(/\n/g,"<br/>").replace(/\s{3}/g,'<span class="wbbtab"></span>'); 856 } 857 } 858 rdata = rdata.replace(/\t/g,'<span class="wbbtab"></span>'); 859 this.selectRange(this.lastRange); 860 this.insertAtCursor(rdata,false); 861 this.lastRange=false; 862 this.$pasteBlock=false; 863 } 864 ,this), 1); 865 this.selectNode(this.$pasteBlock[0]); 866 } 867 return true; 868 } 869 },this)); 870 871 //insert BR on press enter 872 this.$body.bind('keydown',$.proxy(function(e) { 873 if (e.which == 13) { 874 var isLi = this.isContain(this.getSelectNode(),'li'); 875 if (!isLi) { 876 if (e.preventDefault) {e.preventDefault();} 877 this.checkForLastBR(this.getSelectNode()); 878 this.insertAtCursor('<br/>',false); 879 } 880 } 881 },this)); 882 883 //tabInsert 884 if (this.options.tabInsert===true) { 885 this.$body.bind('keydown', $.proxy(this.pressTab,this)); 886 } 887 888 //add event listeners 889 this.$body.bind('mouseup keyup',$.proxy(this.updateUI,this)); 890 this.$body.bind('mousedown',$.proxy(function(e) {this.clearLastRange();this.checkForLastBR(e.target)},this)); 891 892 //trace Textarea 893 if (this.options.traceTextarea===true) { 894 $(document).bind("mousedown",$.proxy(this.traceTextareaEvent,this)); 895 this.$txtArea.val(""); 896 } 897 898 //attach hotkeys 899 if (this.options.hotkeys===true) { 900 this.$body.bind('keydown',$.proxy(this.presskey,this)); 901 } 902 903 //smileConversion 904 if (this.options.smileConversion===true) { 905 this.$body.bind('keyup',$.proxy(this.smileConversion,this)); 906 } 907 908 this.inited=true; 909 910 //create resize lines 911 if (this.options.autoresize===true) { 912 this.$bresize = $(this.elFromString('<div class="bottom-resize-line"></div>')).appendTo(this.$editor) 913 .wdrag({ 914 scope:this, 915 axisY: true, 916 height: height 917 }); 918 } 919 920 this.imgListeners(); 921 } 922 923 924 //this.$editor.append('<span class="powered">Powered by <a href="http://www.wysibb.com" target="_blank">WysiBB<a/></span>'); 925 926 //add event listeners to textarea 927 this.$txtArea.bind('mouseup keyup',$.proxy(function() { 928 clearTimeout(this.uitimer); 929 this.uitimer = setTimeout($.proxy(this.updateUI,this),100); 930 },this)); 931 932 //attach hotkeys 933 if (this.options.hotkeys===true) { 934 $(document).bind('keydown',$.proxy(this.presskey,this)); 935 } 936 }, 937 buildToolbar: function() { 938 if (this.options.toolbar === false) {return false;} 939 940 //this.$toolbar = $('<div class="wysibb-toolbar">').prependTo(this.$editor); 941 this.$toolbar = $('<div>').addClass("wysibb-toolbar").prependTo(this.$editor); 942 943 var $btnContainer; 944 $.each(this.options.buttons,$.proxy(function(i,bn) { 945 var opt = this.options.allButtons[bn]; 946 if (i==0 || bn=="|" || bn=="-") { 947 if (bn=="-") { 948 this.$toolbar.append("<div>"); 949 }
950 $btnContainer = $('<div class="wysibb-toolbar-container">').appendTo(this.$toolbar); 951 } 952 if (opt) { 953 if (opt.type=="colorpicker") { 954 this.buildColorpicker($btnContainer,bn,opt); 955 }else if (opt.type=="table") { 956 this.buildTablepicker($btnContainer,bn,opt); 957 }else if (opt.type=="select") { 958 this.buildSelect($btnContainer,bn,opt); 959 }else if (opt.type=="smilebox") { 960 this.buildSmilebox($btnContainer,bn,opt); 961 }else{ 962 this.buildButton($btnContainer,bn,opt); 963 } 964 } 965 },this)); 966 967 //fix for hide tooltip on quick mouse over 968 this.$toolbar.find(".btn-tooltip").hover(function () {$(this).parent().css("overflow","hidden")},function() {$(this).parent().css("overflow","visible")}); 969 970 //build bbcode switch button 971 //var $bbsw = $('<div class="wysibb-toolbar-container modeSwitch"><div class="wysibb-toolbar-btn" unselectable="on"><span class="btn-inner ve-tlb-bbcode" unselectable="on"></span></div></div>').appendTo(this.$toolbar); 972 var $bbsw = $(document.createElement('div')).addClass("wysibb-toolbar-container modeSwitch").html('<div class="wysibb-toolbar-btn mswitch" unselectable="on"><span class="btn-inner modesw" unselectable="on">[bbcode]</span></div>').appendTo(this.$toolbar); 973 if (this.options.bbmode==true) {$bbsw.children(".wysibb-toolbar-btn").addClass("on");} 974 if (this.options.onlyBBmode===false) { 975 $bbsw.children(".wysibb-toolbar-btn").click($.proxy(function(e) { 976 $(e.currentTarget).toggleClass("on"); 977 this.modeSwitch(); 978 },this)); 979 } 980 }, 981 buildButton: function(container,bn,opt) { 982 if (typeof(container)!="object") { 983 container = this.$toolbar; 984 } 985 var btnHTML = (opt.buttonHTML) ? $(this.strf(opt.buttonHTML,this.options)).addClass("btn-inner") : this.strf('<span class="btn-inner btn-text">{text}</span>',{text:opt.buttonText.replace(/</g,"<")}); 986 var hotkey = (this.options.hotkeys===true && this.options.showHotkeys===true && opt.hotkey) ? (' <span class="tthotkey">['+opt.hotkey+']</span>'):"" 987 var $btn = $('<div class="wysibb-toolbar-btn wbb-'+bn+'">').appendTo(container).append(btnHTML).append(this.strf('<span class="btn-tooltip">{title}<ins/>{hotkey}</span>',{title:opt.title,hotkey:hotkey})); 988 989 //attach events 990 this.controllers.push($btn); 991 $btn.bind('queryState',$.proxy(function(e) { 992 (this.queryState(bn)) ? $(e.currentTarget).addClass("on"):$(e.currentTarget).removeClass("on"); 993 },this)); 994 $btn.mousedown($.proxy(function(e) { 995 e.preventDefault(); 996 this.execCommand(bn,opt.exvalue || false); 997 $(e.currentTarget).trigger('queryState'); 998 },this)); 999 }, 1000 buildColorpicker: function(container,bn,opt) { 1001 var $btn = $('<div class="wysibb-toolbar-btn wbb-dropdown wbb-cp">').appendTo(container).append('<div class="ve-tlb-colorpick"><span class="fonticon">\uE010</span><span class="cp-line"></span></div><ins class="fonticon ar">\uE011</ins>').append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title})); 1002 var $cpline = $btn.find(".cp-line"); 1003 1004 var $dropblock = $('<div class="wbb-list">').appendTo($btn); 1005 $dropblock.append('<div class="nc">'+CURLANG.auto+'</div>'); 1006 var colorlist = (opt.colors) ? opt.colors.split(","):[]; 1007 for (var j=0; j<colorlist.length; j++) { 1008 colorlist[j] = $.trim(colorlist[j]); 1009 if (colorlist[j]=="-") { 1010 //insert padding 1011 $dropblock.append('<span class="pl"></span>'); 1012 }else{ 1013 $dropblock.append(this.strf('<div class="sc" style="background:{color}" title="{color}"></div>',{color:colorlist[j]})); 1014 } 1015 } 1016 var basecolor = $(document.body).css("color"); 1017 //attach events 1018 this.controllers.push($btn); 1019 $btn.bind('queryState',$.proxy(function(e) { 1020 //queryState 1021 $cpline.css("background-color",basecolor); 1022 var r = this.queryState(bn,true); 1023 if (r) { 1024 $cpline.css("background-color",(this.options.bbmode) ? r.color:r); 1025 $btn.find(".ve-tlb-colorpick span.fonticon").css("color",(this.options.bbmode) ? r.color:r); 1026 } 1027 },this)); 1028 $btn.mousedown($.proxy(function(e) { 1029 e.preventDefault(); 1030 this.dropdownclick(".wbb-cp",".wbb-list",e); 1031 },this)); 1032 $btn.find(".sc").mousedown($.proxy(function(e) { 1033 e.preventDefault(); 1034 this.selectLastRange(); 1035 var c = $(e.currentTarget).attr("title"); 1036 this.execCommand(bn,c); 1037 $btn.trigger('queryState'); 1038 },this)); 1039 $btn.find(".nc").mousedown($.proxy(function(e) { 1040 e.preventDefault(); 1041 this.selectLastRange(); 1042 this.execCommand(bn,basecolor); 1043 $btn.trigger('queryState'); 1044 },this)); 1045 $btn.mousedown(function(e) { 1046 if (e.preventDefault) e.preventDefault(); 1047 }); 1048 }, 1049 buildTablepicker: function(container,bn,opt) { 1050 var $btn = $('<div class="wysibb-toolbar-btn wbb-dropdown wbb-tbl">').appendTo(container).append('<span class="btn-inner fonticon ve-tlb-table1">\uE00e</span><ins class="fonticon ar">\uE011</ins>').append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title})); 1051 1052 var $listblock = $('<div class="wbb-list">').appendTo($btn); 1053 var $dropblock = $('<div>').css({"position":"relative","box-sizing":"border-box"}).appendTo($listblock); 1054 var rows = opt.rows || 10; 1055 var cols = opt.cols || 10; 1056 var allcount = rows*cols; 1057 $dropblock.css("height",(rows*opt.cellwidth+2)+"px"); 1058 for (var j=1; j<=cols; j++) { 1059 for (var h=1; h<=rows; h++) { 1060 //var html = this.strf('<div class="tbl-sel" style="width:{width}px;height:{height}px;z-index:{zindex}" title="{row},{col}"></div>',{width: (j*opt.cellwidth),height: (h*opt.cellwidth),zindex: --allcount,row:h,col:j}); 1061 var html = '<div class="tbl-sel" style="width:'+(j*100/cols)+'%;height:'+(h*100/rows)+'%;z-index:'+(--allcount)+'" title="'+h+','+j+'"></div>'; 1062 $dropblock.append(html); 1063 } 1064 } 1065 //this.debug("Attach event on: tbl-sel");
1066 $btn.find(".tbl-sel").mousedown($.proxy(function(e) { 1067 e.preventDefault(); 1068 var t = $(e.currentTarget).attr("title"); 1069 var rc = t.split(","); 1070 var code = (this.options.bbmode) ? '[table]':'<table class="wbb-table" cellspacing="5" cellpadding="0">'; 1071 for (var i=1; i<=rc[0]; i++) { 1072 code += (this.options.bbmode) ? ' [tr]\n':'<tr>'; 1073 for (var j=1; j<=rc[1]; j++) { 1074 code += (this.options.bbmode) ? ' [td][/td]\n':'<td>\uFEFF</td>'; 1075 } 1076 code += (this.options.bbmode) ? '[/tr]\n':'</tr>'; 1077 } 1078 code += (this.options.bbmode) ? '[/table]':'</table>'; 1079 this.insertAtCursor(code); 1080 },this)); 1081 //this.debug("END Attach event on: tbl-sel"); 1082 $btn.mousedown($.proxy(function(e) { 1083 e.preventDefault(); 1084 this.dropdownclick(".wbb-tbl",".wbb-list",e); 1085 },this)); 1086 1087 }, 1088 buildSelect: function(container,bn,opt) { 1089 var $btn = $('<div class="wysibb-toolbar-btn wbb-select wbb-'+bn+'">').appendTo(container).append(this.strf('<span class="val">{title}</span><ins class="fonticon sar">\uE012</ins>',opt)).append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title})); 1090 var $sblock = $('<div class="wbb-list">').appendTo($btn); 1091 var $sval = $btn.find("span.val"); 1092 1093 var olist = ($.isArray(opt.options)) ? opt.options:opt.options.split(","); 1094 var $selectbox = (this.isMobile) ? $("<select>").addClass("wbb-selectbox"):""; 1095 for (var i=0; i<olist.length; i++) { 1096 var oname = olist[i]; 1097 if (typeof(oname)=="string") { 1098 var option = this.options.allButtons[oname]; 1099 if (option) { 1100 //$.log("create: "+oname); 1101 if (option.html) { 1102 $('<span>').addClass("option").attr("oid",oname).attr("cmdvalue",option.exvalue).appendTo($sblock).append(this.strf(option.html,{seltext:option.title})); 1103 }else{ 1104 $sblock.append(this.strf('<span class="option" oid="'+oname+'" cmdvalue="'+option.exvalue+'">{title}</span>',option)); 1105 } 1106 1107 //SelectBox for mobile devices 1108 if (this.isMobile) { 1109 $selectbox.append($('<option>').attr("oid",oname).attr("cmdvalue",option.exvalue).append(option.title)); 1110 } 1111 } 1112 }else{ 1113 //build option list from array 1114 var params = { 1115 seltext: oname.title 1116 } 1117 params[opt.valueBBname]=oname.exvalue; 1118 $('<span>').addClass("option").attr("oid",bn).attr("cmdvalue",oname.exvalue).appendTo($sblock).append(this.strf(opt.html,params)); 1119 1120 if (this.isMobile) {$selectbox.append($('<option>').attr("oid",bn).attr("cmdvalue",oname.exvalue).append(oname.exvalue))} 1121 } 1122 } 1123 //$sblock.append($selectbox); 1124 if (this.isMobile) { 1125 $selectbox.appendTo(container); 1126 this.controllers.push($selectbox); 1127 1128 $selectbox.bind('queryState',$.proxy(function(e) { 1129 //queryState 1130 $selectbox.find("option").each($.proxy(function(i,el){ 1131 var $el = $(el); 1132 var r = this.queryState($el.attr("oid"),true); 1133 var cmdvalue = $el.attr("cmdvalue"); 1134 if ((cmdvalue && r==$el.attr("cmdvalue")) || (!cmdvalue && r)) { 1135 $el.prop("selected",true); 1136 return false; 1137 } 1138 },this)); 1139 },this)); 1140 1141 $selectbox.change($.proxy(function(e) { 1142 e.preventDefault(); 1143 var $o = $(e.currentTarget).find(":selected"); 1144 var oid = $o.attr("oid"); 1145 var cmdvalue = $o.attr("cmdvalue"); 1146 var opt = this.options.allButtons[oid]; 1147 this.execCommand(oid,opt.exvalue || cmdvalue || false); 1148 $(e.currentTarget).trigger('queryState'); 1149 },this)); 1150 1151 } 1152 this.controllers.push($btn); 1153 $btn.bind('queryState',$.proxy(function(e) { 1154 //queryState 1155 $sval.text(opt.title); 1156 $btn.find(".option.selected").removeClass("selected"); 1157 $btn.find(".option").each($.proxy(function(i,el){ 1158 var $el = $(el); 1159 var r = this.queryState($el.attr("oid"),true); 1160 var cmdvalue = $el.attr("cmdvalue"); 1161 if ((cmdvalue && r==$el.attr("cmdvalue")) || (!cmdvalue && r)) { 1162 $sval.text($el.text()); 1163 $el.addClass("selected"); 1164 return false; 1165 } 1166 },this)); 1167 },this)); 1168 $btn.mousedown($.proxy(function(e) { 1169 e.preventDefault(); 1170 this.dropdownclick(".wbb-select",".wbb-list",e); 1171 },this)); 1172 $btn.find(".option").mousedown($.proxy(function(e) { 1173 e.preventDefault(); 1174 var oid = $(e.currentTarget).attr("oid"); 1175 var cmdvalue = $(e.currentTarget).attr("cmdvalue"); 1176 var opt = this.options.allButtons[oid]; 1177 this.execCommand(oid,opt.exvalue || cmdvalue || false); 1178 $(e.currentTarget).trigger('queryState'); 1179 },this)); 1180 }, 1181 buildSmilebox: function(container,bn,opt) { 1182 if (this.options.smileList && this.options.smileList.length>0) { 1183 var $btnHTML = $(this.strf(opt.buttonHTML,opt)).addClass("btn-inner"); 1184 var $btn = $('<div class="wysibb-toolbar-btn wbb-smilebox wbb-'+bn+'">').appendTo(container).append($btnHTML).append(this.strf('<span class="btn-tooltip">{title}<ins/></span>',{title:opt.title})); 1185 var $sblock = $('<div class="wbb-list">').appendTo($btn); 1186 if ($.isArray(this.options.smileList)) { 1187 $.each(this.options.smileList,$.proxy(function(i,sm){ 1188 $('<span>').addClass("smile").appendTo($sblock).append($(this.strf(sm.img,this.options)).attr("title",sm.title)); 1189 },this)); 1190 } 1191 $btn.mousedown($.proxy(function(e) { 1192 e.preventDefault(); 1193 this.dropdownclick(".wbb-smilebox",".wbb-list",e); 1194 },this)); 1195 $btn.find('.smile').mousedown($.proxy(function(e) { 1196 e.preventDefault(); 1197 //this.selectLastRange(); 1198 this.insertAtCursor((this.options.bbmode) ? this.toBB($(e.currentTarget).html()):$($(e.currentTarget).html())); 1199 },this)) 1200 } 1201 }, 1202 updateUI: function(e) { 1203 if (!e || ((e.which>=8 && e.which<=46) || e.which>90 || e.type=="mouseup")) { 1204 $.each(this.controllers,$.proxy(function(i,$btn) { 1205 $btn.trigger('queryState'); 1206 },this)); 1207 } 1208 1209 //check for onlyClearText 1210 this.disNonActiveButtons(); 1211 1212 }, 1213 initModal: function() { 1214 this.$modal=$("#wbbmodal"); 1215 if (this.$modal.size()==0) { 1216 $.log("Init modal");
1217 this.$modal = $('<div>').attr("id","wbbmodal").prependTo(document.body) 1218 .html('<div class="wbbm"><div class="wbbm-title"><span class="wbbm-title-text"></span><span class="wbbclose" title="'+CURLANG.close+'">Ã</span></div><div class="wbbm-content"></div><div class="wbbm-bottom"><button id="wbbm-submit" class="wbb-button">'+CURLANG.save+'</button><button id="wbbm-cancel" class="wbb-cancel-button">'+CURLANG.cancel+'</button><button id="wbbm-remove" class="wbb-remove-button">'+CURLANG.remove+'</button></div></div>').hide(); 1219 1220 this.$modal.find('#wbbm-cancel,.wbbclose').click($.proxy(this.closeModal,this)); 1221 this.$modal.bind('click',$.proxy(function(e) { 1222 if ($(e.target).parents(".wbbm").size()==0) { 1223 this.closeModal(); 1224 } 1225 },this)); 1226 1227 $(document).bind("keydown",$.proxy(this.escModal,this)); //ESC key close modal 1228 } 1229 }, 1230 initHotkeys: function() { 1231 $.log("initHotkeys"); 1232 this.hotkeys=[]; 1233 var klist = "0123456789 abcdefghijklmnopqrstuvwxyz"; 1234 $.each(this.options.allButtons,$.proxy(function(cmd,opt) { 1235 if (opt.hotkey) { 1236 var keys = opt.hotkey.split("+"); 1237 if (keys && keys.length>=2) { 1238 var metasum=0; 1239 var key = keys.pop(); 1240 $.each(keys,function(i,k) { 1241 switch($.trim(k.toLowerCase())) { 1242 case "ctrl": {metasum+=1;break;} 1243 case "shift": {metasum+=4;break;} 1244 case "alt": {metasum+=7;break;} 1245 } 1246 }) 1247 //$.log("metasum: "+metasum+" key: "+key+" code: "+(klist.indexOf(key)+48)); 1248 if (metasum>0) { 1249 if (!this.hotkeys["m"+metasum]) {this.hotkeys["m"+metasum]=[];} 1250 this.hotkeys["m"+metasum]["k"+(klist.indexOf(key)+48)]=cmd; 1251 } 1252 } 1253 } 1254 },this)) 1255 }, 1256 presskey: function(e) { 1257 if (e.ctrlKey==true || e.shiftKey==true || e.altKey==true) { 1258 var metasum = ((e.ctrlKey==true) ? 1:0)+((e.shiftKey==true) ? 4:0)+((e.altKey==true) ? 7:0); 1259 if (this.hotkeys["m"+metasum] && this.hotkeys["m"+metasum]["k"+e.which]) { 1260 this.execCommand(this.hotkeys["m"+metasum]["k"+e.which],false); 1261 e.preventDefault(); 1262 return false; 1263 } 1264 } 1265 }, 1266 1267 //COgdfMMAND FUNCTIONS 1268 execCommand: function(command,value) { 1269 $.log("execCommand: "+command); 1270 var opt = this.options.allButtons[command]; 1271 if (opt.en!==true) {return false;} 1272 var queryState = this.queryState(command,value); 1273 1274 //check for onlyClearText 1275 var skipcmd = this.isInClearTextBlock(); 1276 if (skipcmd && skipcmd!=command) {return;} 1277 1278 1279 if (opt.excmd) { 1280 //use NativeCommand 1281 if (this.options.bbmode) { 1282 $.log("Native command in bbmode: "+command); 1283 if (queryState && opt.subInsert!=true) { 1284 //remove bbcode 1285 this.wbbRemoveCallback(command,value); 1286 }else{ 1287 //insert bbcode 1288 var v = {}; 1289 if (opt.valueBBname && value) { 1290 v[opt.valueBBname]=value; 1291 } 1292 this.insertAtCursor(this.getBBCodeByCommand(command,v)); 1293 } 1294 }else{ 1295 this.execNativeCommand(opt.excmd,value || false); 1296 } 1297 }else if (!opt.cmd) { 1298 //wbbCommand 1299 //this.wbbExecCommand(command,value,queryState,$.proxy(this.wbbInsertCallback,this),$.proxy(this.wbbRemoveCallback,this)); 1300 this.wbbExecCommand.call(this,command,value,queryState); 1301 }else{ 1302 //user custom command 1303 opt.cmd.call(this,command,value,queryState); 1304 } 1305 this.updateUI(); 1306 }, 1307 queryState: function(command,withvalue) { 1308 var opt = this.options.allButtons[command]; 1309 if (opt.en!==true) {return false;} 1310 //if (opt.subInsert===true && opt.type!="colorpicker") {return false;} 1311 if (this.options.bbmode) { 1312 //bbmode 1313 if (opt.bbSelector) { 1314 for (var i=0; i<opt.bbSelector.length; i++) { 1315 var b = this.isBBContain(opt.bbSelector[i]); 1316 if (b) { 1317 return this.getParams(b,opt.bbSelector[i],b[1]); 1318 } 1319 } 1320 } 1321 return false; 1322 }else{ 1323 if (opt.excmd) { 1324 //native command 1325 if (withvalue) { 1326 try { 1327 //Firefox fix 1328 var v = (document.queryCommandValue(opt.excmd)+"").replace(/\'/g,""); 1329 if (opt.excmd=="foreColor") { 1330 v = this.rgbToHex(v); 1331 } 1332 //return (v==value); 1333 return v; 1334 }catch(e) {return false;} 1335 }else{ 1336 try { //Firefox fix, exception while get queryState for UnorderedList 1337 if ((opt.excmd=="bold" || opt.excmd=="italic" || opt.excmd=="underline" || opt.excmd=="strikeThrough") && $(this.getSelectNode()).is("img")) { //Fix, when img selected 1338 return false;
1339 }else if (opt.excmd=="underline" && $(this.getSelectNode()).closest("a").size()>0) { //fix, when link select 1340 return false; 1341 } 1342 return document.queryCommandState(opt.excmd); 1343 }catch(e) {return false;} 1344 } 1345 }else{ 1346 //custom command 1347 if ($.isArray(opt.rootSelector)) { 1348 for (var i=0; i<opt.rootSelector.length; i++) { 1349 var n = this.isContain(this.getSelectNode(),opt.rootSelector[i]); 1350 if (n) { 1351 return this.getParams(n,opt.rootSelector[i]); 1352 } 1353 } 1354 } 1355 return false; 1356 } 1357 } 1358 }, 1359 wbbExecCommand: function(command,value,queryState) { //default command for custom bbcodes 1360 $.log("wbbExecCommand"); 1361 var opt = this.options.allButtons[command]; 1362 if (opt) { 1363 if (opt.modal) { 1364 if ($.isFunction(opt.modal)) { 1365 //custom modal function 1366 //opt.modal(command,opt.modal,queryState,new clbk(this)); 1367 opt.modal.call(this,command,opt.modal,queryState); 1368 }else{ 1369 this.showModal.call(this,command,opt.modal,queryState); 1370 } 1371 }else{ 1372 if (queryState && opt.subInsert!=true) { 1373 //remove formatting 1374 //removeCallback(command,value); 1375 this.wbbRemoveCallback(command); 1376 }else{ 1377 //insert format 1378 if (opt.groupkey) { 1379 var groupsel = this.options.groups[opt.groupkey]; 1380 if (groupsel) { 1381 var snode = this.getSelectNode(); 1382 $.each(groupsel,$.proxy(function(i,sel) { 1383 var is = this.isContain(snode,sel); 1384 if (is) { 1385 var $sp = $('<span>').html(is.innerHTML) 1386 var id = this.setUID($sp); 1387 $(is).replaceWith($sp); 1388 this.selectNode(this.$editor.find("#"+id)[0]); 1389 return false; 1390 } 1391 },this)); 1392 } 1393 } 1394 this.wbbInsertCallback(command,value) 1395 } 1396 } 1397 } 1398 }, 1399 wbbInsertCallback: function(command,paramobj) { 1400 if (typeof(paramobj)!="object") {paramobj={}}; 1401 $.log("wbbInsertCallback: "+command); 1402 var data = this.getCodeByCommand(command,paramobj); 1403 this.insertAtCursor(data); 1404 1405 if (this.seltextID && data.indexOf(this.seltextID)!=-1) { 1406 var snode = this.$body.find("#"+this.seltextID)[0]; 1407 this.selectNode(snode); 1408 $(snode).removeAttr("id"); 1409 this.seltextID=false; 1410 } 1411 }, 1412 wbbRemoveCallback: function(command,clear) { 1413 $.log("wbbRemoveCallback: "+command); 1414 var opt = this.options.allButtons[command]; 1415 if (this.options.bbmode) { 1416 //bbmode 1417 //REMOVE BBCODE 1418 var pos = this.getCursorPosBB(); 1419 var stextnum=0; 1420 $.each(opt.bbSelector,$.proxy(function(i,bbcode) { 1421 var stext = bbcode.match(/\{[\s\S]+?\}/g); 1422 $.each(stext,function(n,s) { 1423 if (s.toLowerCase()=="{seltext}") {stextnum=n;return false} 1424 }); 1425 var a = this.isBBContain(bbcode); 1426 if (a) { 1427 this.txtArea.value = this.txtArea.value.substr(0,a[1])+this.txtArea.value.substr(a[1],this.txtArea.value.length-a[1]).replace(a[0][0],(clear===true) ? '':a[0][stextnum+1]); 1428 this.setCursorPosBB(a[1]); 1429 return false; 1430 } 1431 },this)); 1432 }else{ 1433 var node = this.getSelectNode(); 1434 $.each(opt.rootSelector,$.proxy(function(i,s) { 1435 //$.log("RS: "+s); 1436 var root = this.isContain(node,s); 1437 if (!root) {return true;} 1438 var $root = $(root); 1439 var cs = this.options.rules[s][0][1]; 1440 if ($root.is("span[wbb]") || !$root.is("span,font")) { //remove only blocks 1441 if (clear===true || (!cs || !cs["seltext"])) { 1442 this.setCursorByEl($root); 1443 $root.remove(); 1444 }else{ 1445 if (cs && cs["seltext"] && cs["seltext"]["sel"]) { 1446 var htmldata = $root.find(cs["seltext"]["sel"]).html(); 1447 if (opt.onlyClearText===true) { 1448 htmldata = this.getHTML(htmldata,true,true); 1449 htmldata = htmldata.replace(/\{/g,"{").replace(/\}/g,"}"); 1450 } 1451 $root.replaceWith(htmldata); 1452 }else{ 1453 var htmldata = $root.html(); 1454 if (opt.onlyClearText===true) { 1455 htmldata = this.getHTML(htmldata,true); 1456 htmldata = htmldata.replace(/\</g,"<").replace(/\>/g,">").replace(/\{/g,"{").replace(/\}/g,"}"); 1457 } 1458 $root.replaceWith(htmldata); 1459 } 1460 } 1461 return false;
1462 }else{ 1463 //span,font - extract select content from this span,font 1464 var rng = this.getRange(); 1465 var shtml = this.getSelectText(); 1466 var rnode = this.getSelectNode(); 1467 if (shtml=="") { 1468 shtml="\uFEFF"; 1469 }else{ 1470 shtml = this.clearFromSubInsert(shtml,command); 1471 } 1472 var ins = this.elFromString(shtml); 1473 1474 var before_rng = (window.getSelection) ? rng.cloneRange():this.body.createTextRange(); 1475 var after_rng = (window.getSelection) ? rng.cloneRange():this.body.createTextRange(); 1476 1477 if (window.getSelection) { 1478 this.insertAtCursor('<span id="wbbdivide"></span>'); 1479 var div = $root.find('span#wbbdivide').get(0); 1480 before_rng.setStart(root.firstChild,0); 1481 before_rng.setEndBefore(div); 1482 after_rng.setStartAfter(div); 1483 after_rng.setEndAfter(root.lastChild); 1484 }else{ 1485 before_rng.moveToElementText(root); 1486 after_rng.moveToElementText(root); 1487 before_rng.setEndPoint('EndToStart',rng); 1488 after_rng.setEndPoint('StartToEnd',rng); 1489 } 1490 var bf = this.getSelectText(false,before_rng); 1491 var af = this.getSelectText(false,after_rng); 1492 if (af!="") { 1493 var $af = $root.clone().html(af); 1494 $root.after($af); 1495 } 1496 if (clear!==true) $root.after(ins); //insert select html 1497 if (window.getSelection) { 1498 $root.html(bf); 1499 if (clear!==true) this.selectNode(ins); 1500 }else{ 1501 $root.replaceWith(bf); 1502 } 1503 return false; 1504 } 1505 },this)); 1506 } 1507 }, 1508 execNativeCommand: function(cmd,param) { 1509 //$.log("execNativeCommand: '"+cmd+"' : "+param); 1510 this.body.focus(); //set focus to frame body 1511 if (cmd=="insertHTML" && !window.getSelection) { //IE does't support insertHTML 1512 var r = (this.lastRange) ? this.lastRange:document.selection.createRange(); //IE 7,8 range lost fix 1513 r.pasteHTML(param); 1514 var txt = $('<div>').html(param).text(); //for ie selection inside block 1515 var brsp = txt.indexOf("\uFEFF"); 1516 if (brsp>-1) { 1517 r.moveStart('character',(-1)*(txt.length-brsp)); 1518 r.select(); 1519 } 1520 this.lastRange=false; 1521 }else if (cmd=="insertHTML") { //fix webkit bug with insertHTML 1522 var sel = this.getSelection(); 1523 var e = this.elFromString(param); 1524 var rng = (this.lastRange) ? this.lastRange:this.getRange(); 1525 rng.deleteContents(); 1526 rng.insertNode(e); 1527 rng.collapse(false); 1528 sel.removeAllRanges(); 1529 sel.addRange(rng); 1530 }else{ 1531 if (typeof param == "undefined") {param=false;} 1532 if (this.lastRange) { 1533 $.log("Last range select"); 1534 this.selectLastRange() 1535 } 1536 document.execCommand(cmd, false, param); 1537 } 1538 1539 }, 1540 getCodeByCommand: function(command,paramobj) { 1541 return (this.options.bbmode) ? this.getBBCodeByCommand(command,paramobj):this.getHTMLByCommand(command,paramobj); 1542 }, 1543 getBBCodeByCommand: function(command,params) { 1544 if (!this.options.allButtons[command]) {return "";} 1545 if (typeof(params)=="undefined") {params={};} 1546 params = this.keysToLower(params); 1547 if (!params["seltext"]) { 1548 //get selected text 1549 params["seltext"] = this.getSelectText(true); 1550 } 1551 1552 var bbcode = this.options.allButtons[command].bbcode; 1553 //bbcode = this.strf(bbcode,params); 1554 bbcode = bbcode.replace(/\{(.*?)(\[.*?\])*\}/g,function(str,p,vrgx) { 1555 if (vrgx) { 1556 var vrgxp; 1557 if (vrgx) { 1558 vrgxp = new RegExp(vrgx+"+","i"); 1559 } 1560 if (typeof(params[p.toLowerCase()])!="undefined" && params[p.toLowerCase()].toString().match(vrgxp)===null) { 1561 //not valid value 1562 return ""; 1563 } 1564 } 1565 return (typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()]; 1566 }); 1567 1568 //insert first with max params 1569 var rbbcode=null,maxpcount=0; 1570 if (this.options.allButtons[command].transform) { 1571 var tr=[]; 1572 $.each(this.options.allButtons[command].transform,function(html,bb) { 1573 tr.push(bb); 1574 }); 1575 tr=this.sortArray(tr,-1); 1576 $.each(tr,function(i,v) { 1577 var valid=true,pcount=0,pname={};; 1578 v = v.replace(/\{(.*?)(\[.*?\])*\}/g,function(str,p,vrgx) { 1579 var vrgxp; 1580 p = p.toLowerCase(); 1581 if (vrgx) { 1582 vrgxp = new RegExp(vrgx+"+","i"); 1583 } 1584 if (typeof(params[p.toLowerCase()])=="undefined" || (vrgx && params[p.toLowerCase()].toString().match(vrgxp)===null)) {val
1584id=false;}; 1585 if (typeof(params[p])!="undefined" && !pname[p]) {pname[p]=1;pcount++;} 1586 return (typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()]; 1587 }); 1588 if (valid && (pcount>maxpcount)) {rbbcode = v;maxpcount=pcount;} 1589 }); 1590 } 1591 return rbbcode || bbcode; 1592 }, 1593 getHTMLByCommand: function(command,params) { 1594 if (!this.options.allButtons[command]) {return "";} 1595 params = this.keysToLower(params); 1596 if (typeof(params)=="undefined") {params={};} 1597 if (!params["seltext"]) { 1598 //get selected text 1599 params["seltext"] = this.getSelectText(false); 1600 //$.log("seltext: '"+params["seltext"]+"'"); 1601 if (params["seltext"]=="") {params["seltext"]="\uFEFF";} 1602 else{ 1603 //clear selection from current command tags 1604 params["seltext"] = this.clearFromSubInsert(params["seltext"],command); 1605 1606 //toBB if params onlyClearText=true 1607 if (this.options.allButtons[command].onlyClearText===true) { 1608 params["seltext"] = this.toBB(params["seltext"]).replace(/\</g,"<").replace(/\n/g,"<br/>").replace(/\s{3}/g,'<span class="wbbtab"></span>'); 1609 } 1610 1611 } 1612 } 1613 1614 var postsel=""; 1615 this.seltextID = "wbbid_"+(++this.lastid); 1616 if (command!="link" && command!="img") { 1617 params["seltext"] = '<span id="'+this.seltextID+'">'+params["seltext"]+'</span>'; //use for select seltext 1618 }else{ 1619 postsel = '<span id="'+this.seltextID+'">\uFEFF</span>' 1620 } 1621 var html = this.options.allButtons[command].html; 1622 html = html.replace(/\{(.*?)(\[.*?\])*\}/g,function(str,p,vrgx) { 1623 if (vrgx) { 1624 var vrgxp = new RegExp(vrgx+"+","i"); 1625 if (typeof(params[p.toLowerCase()])!="undefined" && params[p.toLowerCase()].toString().match(vrgxp)===null) { 1626 //not valid value 1627 return ""; 1628 } 1629 } 1630 return (typeof(params[p.toLowerCase()])=="undefined") ? "":params[p.toLowerCase()]; 1631 }); 1632 1633 //insert first with max params 1634 var rhtml=null,maxpcount=0; 1635 if (this.options.allButtons[command].transform) { 1636 var tr=[]; 1637 $.each(this.options.allButtons[command].transform,function(html,bb) { 1638 tr.push(html); 1639 }); 1640 tr=this.sortArray(tr,-1); 1641 $.each(tr,function(i,v) { 1642 var valid=true, pcount=0,pname={}; 1643 v = v.replace(/\{(.*?)(\[.*?\])*\}/g,function(str,p,vrgx) { 1644 var vrgxp; 1645 p = p.toLowerCase(); 1646 if (vrgx) { 1647 vrgxp = new RegExp(vrgx+"+","i"); 1648 } 1649 if (typeof(params[p])=="undefined" || (vrgx && params[p].toString().match(vrgxp)===null)) {valid=false;}; 1650 if (typeof(params[p])!="undefined" && !pname[p]) {pname[p]=1;pcount++;} 1651 return (typeof(params[p])=="undefined") ? "":params[p]; 1652 }); 1653 if (valid && (pcount>maxpcount)) {rhtml = v;maxpcount=pcount;} 1654 }); 1655 } 1656 return (rhtml || html)+postsel; 1657 }, 1658 1659 //SELECTION FUNCTIONS 1660 getSelection: function() { 1661 if (window.getSelection) { 1662 return window.getSelection(); 1663 }else if (document.selection) { 1664 return (this.options.bbmode) ? document.selection.createRange():document.selection.createRange(); 1665 } 1666 }, 1667 getSelectText: function(fromTxtArea,range) { 1668 if (fromTxtArea) { 1669 //return select text from textarea 1670 this.txtArea.focus(); 1671 if('selectionStart' in this.txtArea) { 1672 var l = this.txtArea.selectionEnd - this.txtArea.selectionStart; 1673 return this.txtArea.value.substr(this.txtArea.selectionStart, l); 1674 }else{ 1675 //IE 1676 var r = document.selection.createRange(); 1677 return r.text; 1678 } 1679 }else{ 1680 //return select html from body 1681 this.body.focus(); 1682 if (!range) {range=this.getRange()}; 1683 if (window.getSelection) { 1684 //w3c 1685 if (range) { 1686 return $('<div>').append(range.cloneContents()).html(); 1687 } 1688 }else{ 1689 //ie 1690 return range.htmlText; 1691 } 1692 } 1693 return ""; 1694 }, 1695 getRange: function() { 1696 if (window.getSelection) { 1697 var sel = this.getSelection(); 1698 if (sel.getRangeAt && sel.rangeCount>0) { 1699 return sel.getRangeAt(0); 1700 }else if (sel.anchorNode) { 1701 var range = (this.options.bbmode) ? document.createRange() : document.createRange(); 1702 range.setStart (sel.anchorNode, sel.anchorOffset); 1703 range.setEnd (sel.focusNode, sel.focusOffset); 1704 return range; 1705 } 1706 }else{ 1707 return (this.options.bbmode===true) ? document.selection.createRange():document.selection.createRange(); 1708 } 1709 }, 1710 insertAtCursor: function(code,forceBBMode) { 1711 if (typeof(code)!="string") {code = $("<div>").append(code).html();} 1712 if ((this.options.bbmode && typeof(forceBBMode)=="undefined") || forceBBMode===true) { 1713 var clbb = code.replace(/.*(\[\/\S+?\])$/,"$1"); 1714 var p = this.getCursorPosBB()+((code.indexOf(clbb)!=-1 && code.match(/\[.*\]/)) ? code.indexOf(clbb):code.length); 1715 if (document.selection) { 1716 //IE 1717 this.txtArea.focus();
1718 this.getSelection().text=code; 1719 }else if (this.txtArea.selectionStart || this.txtArea.selectionStart == '0') { 1720 this.txtArea.value = this.txtArea.value.substring(0, this.txtArea.selectionStart) + code + this.txtArea.value.substring(this.txtArea.selectionEnd, this.txtArea.value.length); 1721 } 1722 if (p<0) {p=0;} 1723 this.setCursorPosBB(p); 1724 }else{ 1725 this.execNativeCommand("insertHTML",code); 1726 var node = this.getSelectNode(); 1727 if (!$(node).closest("table,tr,td")) { 1728 this.splitPrevNext(node); 1729 } 1730 } 1731 }, 1732 getSelectNode: function(rng) { 1733 this.body.focus(); 1734 if (!rng) {rng=this.getRange();} 1735 if (!rng) {return this.$body;} 1736 //return (window.getSelection) ? rng.commonAncestorContainer:rng.parentElement(); 1737 var sn = (window.getSelection) ? rng.commonAncestorContainer:rng.parentElement(); 1738 if ($(sn).is(".imgWrap")) {sn = $(sn).children("img")[0];} 1739 return sn; 1740 }, 1741 getCursorPosBB: function() { 1742 var pos=0; 1743 if ('selectionStart' in this.txtArea) { 1744 pos = this.txtArea.selectionStart; 1745 }else{ 1746 this.txtArea.focus(); 1747 var r = this.getRange(); 1748 var rt = document.body.createTextRange(); 1749 rt.moveToElementText(this.txtArea); 1750 rt.setEndPoint('EndToStart',r); 1751 pos = rt.text.length; 1752 } 1753 return pos; 1754 }, 1755 setCursorPosBB: function(pos) { 1756 if (this.options.bbmode) { 1757 if (window.getSelection) { 1758 this.txtArea.selectionStart=pos; 1759 this.txtArea.selectionEnd=pos; 1760 }else{ 1761 var range = this.txtArea.createTextRange(); 1762 range.collapse(true); 1763 range.move('character', pos); 1764 range.select(); 1765 } 1766 } 1767 }, 1768 selectNode: function(node,rng) { 1769 if (!rng) {rng = this.getRange();} 1770 if (!rng) {return;} 1771 if (window.getSelection) { 1772 var sel = this.getSelection(); 1773 rng.selectNodeContents(node) 1774 sel.removeAllRanges(); 1775 sel.addRange(rng); 1776 }else{ 1777 rng.moveToElementText(node); 1778 rng.select(); 1779 } 1780 }, 1781 selectRange: function(rng) { 1782 if (rng) { 1783 if (!window.getSelection) { 1784 rng.select(); 1785 }else{ 1786 var sel = this.getSelection(); 1787 sel.removeAllRanges(); 1788 sel.addRange(rng); 1789 } 1790 } 1791 }, 1792 cloneRange: function(rng) { 1793 if (rng) { 1794 if (!window.getSelection) { 1795 return rng.duplicate(); 1796 }else{ 1797 return rng.cloneRange(); 1798 } 1799 } 1800 }, 1801 getRangeClone: function() { 1802 return this.cloneRange(this.getRange()); 1803 }, 1804 saveRange: function() { 1805 this.setBodyFocus(); 1806 //this.lastRange=(this.options.bbmode) ? this.getCursorPosBB():this.getRangeClone(); 1807 this.lastRange=this.getRangeClone(); 1808 }, 1809 selectLastRange: function() { 1810 if (this.lastRange) { 1811 this.body.focus(); 1812 this.selectRange(this.lastRange); 1813 this.lastRange=false; 1814 } 1815 }, 1816 setBodyFocus: function() { 1817 $.log("Set focus to WysiBB editor"); 1818 if (this.options.bbmode) { 1819 if (!this.$txtArea.is(":focus")) { 1820 this.$txtArea.focus(); 1821 } 1822 }else{ 1823 if (!this.$body.is(":focus")) { 1824 this.$body.focus(); 1825 } 1826 } 1827 }, 1828 clearLastRange: function() { 1829 this.lastRange=false; 1830 }, 1831 1832 //TRANSFORM FUNCTIONS 1833 filterByNode: function(node) { 1834 var $n = $(node); 1835 var tagName = $n.get(0).tagName.toLowerCase(); 1836 var filter=tagName; 1837 var attributes = this.getAttributeList($n.get(0)); 1838 $.each(attributes, $.proxy(function(i, item) { 1839 var v = $n.attr(item); 1840 /* $.log("v: "+v); 1841 if ($.inArray(item,this.options.attrWrap)!=-1) { 1842 item = '_'+item; 1843 } */ 1844 //$.log(item); 1845 if (item.substr(0,1)=="_") {item=item.substr(1,item.length)} 1846 if (v && !v.match(/\{.*?\}/)) { 1847 //$.log("I1: "+item); 1848 if (item=="style") { 1849 var v = $n.attr(item); 1850 var va = v.split(";"); 1851 $.each(va,function(i,f) { 1852 if (f && f.length>0) { 1853 filter+='['+item+'*="'+$.trim(f)+'"]'; 1854 } 1855 }); 1856 }else{ 1857 filter+='['+item+'="'+v+'"]'; 1858 } 1859 }else if (v && item=="style") { 1860 //$.log("I2: "+item); 1861 var vf = v.substr(0,v.indexOf("{")); 1862 if (vf && vf!="") { 1863 var v = v.substr(0,v.indexOf("{")); 1864 var va = v.split(";"); 1865 $.each(va,function(i,f) { 1866 filter+='['+item+'*="'+f+'"]'; 1867 }); 1868 //filter+='['+item+'*="'+v.substr(0,v.indexOf("{"))+'"]'; 1869 } 1870 }else{ //1.2.2 1871 //$.log("I3: "+item); 1872 filter+='['+item+']'; 1873 } 1874 },this)); 1875 1876 //index 1877 var idx = $n.parent().children(filter).index($n); 1878 if (idx>0) { 1879 filter+=":eq("+$n.index()+")"; 1880 } 1881 return filter; 1882 }, 1883 relFilterByNode: function(node,stop) { 1884 var p=""; 1885 $.each(this.options.attrWrap,function(i,a) { 1886 stop = stop.replace('['+a,'[_'+a); 1887 }); 1888 while (node && node.tagName!="BODY" && !$(node).is(stop)) { 1889 p=this.filterByNode(node)+" "+p; 1890 if (node) {node = node.parentNode;} 1891 } 1892 return p; 1893 }, 1894 getRegexpReplace: function(str,validname) { 1895 str = str.replace(/(\(|\)|\[|\]|\.|\*|\?|\:|\\)/g,"\\$1") 1896 .replace(/\s+/g,"\\s+") 1897 .replace(validname.replace(/(\(|\)|\[|\]|\.|\*|\?|\:|\\)/g,"\\$1"),"(.+)") 1898 .replace(/\{\S+?\}/g,".*"); 1899 return (str); 1900 }, 1901 getBBCode: function() { 1902 if (!this.options.rules) {return this.$txtArea.val();} 1903 if (this.options.bbmode) {return this.$txtArea.val();} 1904 this.clearEmpty(); 1905 this.removeLastBodyBR(); 1906 return this.toBB(this.$body.html()); 1907 }, 1908 toBB: function(data) { 1909 if (!data) {return "";}; 1910 var $e = (typeof(data)=="string") ? $('<span>').html(data):$(data); 1911 //remove last BR 1912 $e.find("div,blockquote,p").each(function() { 1913 if (this.nodeType!=3 && this.lastChild && this.lastChild.tagName=="BR") { 1914 $(this.lastChild).remove(); 1915 } 1916 }) 1917 if ($e.is("div,blockquote,p") && $e[0].nodeType!=3 && $e[0].lastChild && $e[0].lastChild.tagName=="BR") { 1918 $($e[0].lastChild).remove(); 1919 } 1920 //END remove last BR 1921 1922 //Remove BR 1923 $e.find("ul > br, table > br, tr > br").remove(); 1924 //IE 1925 1926 var outbb=""; 1927 1928 //transform smiles 1929 $.each(this.options.srules,$.proxy(function(s,bb) { 1930 $e.find(s).replaceWith(bb[0]); 1931 },this)); 1932 1933 $e.contents().each($.proxy(function(i,el) { 1934 var $el = $(el);
1935 if (el.nodeType===3) { 1936 outbb+=el.data.replace(/\n+/,"").replace(/\t/g," "); 1937 }else{ 1938 //process html tag 1939 var rpl,processed=false; 1940 1941 //for (var rootsel in this.options.rules) { 1942 for (var j=0; j<this.rsellist.length; j++) { 1943 var rootsel = this.rsellist[j]; 1944 if ($el && $el.is(rootsel)) { 1945 //it is root sel 1946 var rlist = this.options.rules[rootsel]; 1947 for (var i=0; i<rlist.length; i++) { 1948 var bbcode = rlist[i][0]; 1949 var crules = rlist[i][1]; 1950 var skip=false,keepElement=false,keepAttr=false; 1951 if (!$el.is("br")) { 1952 bbcode = bbcode.replace(/\n/g,"<br>"); 1953 } 1954 bbcode = bbcode.replace(/\{(.*?)(\[.*?\])*\}/g,$.proxy(function(str,s,vrgx) { 1955 var c = crules[s.toLowerCase()]; 1956 //if (typeof(c)=="undefined") {$.log("Param: {"+s+"} not found in HTML representation.");skip=true;return s;} 1957 if (typeof(c)=="undefined") {$.log("Param: {"+s+"} not found in HTML representation.");skip=true;} 1958 var $cel = (c.sel) ? $(el).find(c.sel):$(el); 1959 if (c.attr && !$cel.attr(c.attr)) {skip=true;return s;} //skip if needed attribute not present, maybe other bbcode 1960 var cont = (c.attr) ? $cel.attr(c.attr):$cel.html(); 1961 if (typeof(cont)=="undefined" || cont==null) {skip=true;return s;} 1962 var regexp = c.rgx; 1963 1964 //style fix 1965 if (regexp && c.attr=="style" && regexp.substr(regexp.length-1,1)!=";") { 1966 regexp+=";"; 1967 } 1968 if (c.attr=="style" && cont && cont.substr(cont.length-1,1)!=";") {cont+=";"} 1969 //prepare regexp 1970 var rgx = (regexp) ? new RegExp(regexp,""):false; 1971 if (rgx) { 1972 if (cont.match(rgx)) { 1973 var m = cont.match(rgx); 1974 if (m && m.length==2) { 1975 cont=m[1]; 1976 } 1977 }else{ 1978 cont=""; 1979 } 1980 } 1981 1982 //if it is style attr, then keep tag alive, remove this style 1983 if (c.attr && skip===false) { 1984 if (c.attr=="style") { 1985 keepElement=true; 1986 var nstyle=""; 1987 var r = c.rgx.replace(/^\.\*\?/,"").replace(/\.\*$/,"").replace(/;$/,""); 1988 $($cel.attr("style").split(";")).each(function(idx,style) { 1989 if (style && style!="") { 1990 if (!style.match(r)) { 1991 nstyle+=style+";"; 1992 } 1993 } 1994 }); 1995 if (nstyle=="") { 1996 $cel.removeAttr("style"); 1997 }else{ 1998 $cel.attr("style",nstyle); 1999 } 2000 }else if (c.rgx===false){ 2001 keepElement=true; 2002 keepAttr=true; 2003 $cel.removeAttr(c.attr); 2004 } 2005 } 2006 if ($el.is('table,tr,td,font')) {keepElement=true;} 2007 2008 return cont || ""; 2009 },this)); 2010 if (skip) {continue;} 2011 if ($el.is("img,br,hr")) { 2012 //replace element 2013 outbb+=bbcode; 2014 $el=null; 2015 break; 2016 }else{ 2017 if (keepElement && !$el.attr("notkeep")) { 2018 if ($el.is("table,tr,td")) { 2019 bbcode = this.fixTableTransform(bbcode); 2020 outbb+=this.toBB($('<span>').html(bbcode)); 2021 $el=null; 2022 }else{ 2023 $el.empty().html('<span>'+bbcode+'</span>'); 2024 } 2025 2026 }else{ 2027 if ($el.is("iframe")) { 2028 outbb+=bbcode; 2029 }else{ 2030 $el.empty().html(bbcode); 2031 outbb+=this.toBB($el); 2032 $el=null; 2033 2034 } 2035 break; 2036 } 2037 } 2038 } 2039 } 2040 } 2041 if (!$el || $el.is("iframe,img")) {return true;} 2042 outbb+=this.toBB($el); 2043 } 2044 },this)); 2045 2046 outbb.replace(/\uFEFF/g,""); 2047 return outbb; 2048 }, 2049 getHTML: function(bbdata,init,skiplt) { 2050 if (!this.options.bbmode && !init) {return this.$body.html()} 2051 2052 if (!skiplt) {bbdata = bbdata.replace(/</g,"<").replace(/\{/g,"{").replace(/\}/g,"}");} 2053 bbdata = bbdata.replace(/\[code\]([\s\S]*?)\[\/code\]/g,function(s) { 2054 s = s.substr("[code]".length,s.length-"[code]".length-"[/code]".length).replace(/\[/g,"[").replace(/\]/g,"]"); 2055 return "[code]"+s+"[/code]"; 2056 }); 2057 2058 2059 $.each(this.options.btnlist,$.proxy(function(i,b){ 2060 if (b!="|" && b!="-") { 2061 var find=true; 2062 if (!this.options.allButtons[b] || !this.options.allButtons[b].transform) { 2063 return true; 2064 } 2065 2066 $.each(this.options.allButtons[b].transform,$.proxy(function(html,bb) { 2067 html = html.replace(/\n/g,""); //IE 7,8 FIX 2068 var a=[]; 2069 bb = bb.replace(/(\(|\)|\[|\]|\.|\*|\?|\:|\\|\\)/g,"\\$1"); 2070 //.replace(/\s/g,"\\s"); 2071 bb = bb.replace(/\{(.*?)(\\\[.*?\\\])*\}/gi,$.proxy(function(str,s,vrgx) { 2072 a.push(s); 2073 if (vrgx) { 2074 //has validation regexp 2075 vrgx = vrgx.replace(/\\/g,""); 2076 return "("+vrgx+"*?)"; 2077 } 2078 return "([\\s\\S]*?)"; 2079 },this)); 2080 var n=0,am; 2081 while ((am = (new RegExp(bb,"mgi")).exec(bbdata)) != null) { 2082 if (am) { 2083 var r={}; 2084 $.each(a,$.proxy(function(i,k) { 2085 r[k]=am[i+1]; 2086 },this)); 2087 var nhtml = html; 2088 nhtml = nhtml.replace(/\{(.*?)(\[.*?\])\}/g,"{$1}"); 2089 nhtml = this.strf(nhtml,r); 2090 bbdata = bbdata.replace(am[0],nhtml); 2091 } 2092 } 2093 },this)); 2094 } 2095 },this)); 2096 2097 //transform system codes 2098 $.each(this.options.systr,function(html,bb) { 2099 bb = bb.replace(/(\(|\)|\[|\]|\.|\*|\?|\:|\\|\\)/g,"\\$1") 2100 .replace(" ","\\s"); 2101 bbdata = bbdata.replace(new RegExp(bb,"g"),html); 2102 }); 2103 2104 2105 var $wrap = $(this.elFromString("<div>"+bbdata+"</div>")); 2106 //transform smiles 2107 /* $wrap.contents().filter(function() {return this.nodeType==3}).each($.proxy(smilerpl,this)).end().find("*").contents().filter(function() {return this.nodeType==3}).each($.proxy(smilerpl,this)); 2108 2109 function smilerpl(i,el) { 2110 var ndata = el.data; 2111 $.each(this.options.smileList,$.proxy(function(i,row) { 2112 var fidx = ndata.indexOf(row.bbcode); 2113 if (fidx!=-1) { 2114 var afternode_txt = ndata.substring(fidx+row.bbcode.length,ndata.length); 2115 var afternode = document.createTextNode(afternode_txt); 2116 el.data = ndata = el.data.substr(0,fidx); 2117 $(el).after(afternode).after(this.strf(row.img,this.options)); 2118 } 2119 },this)); 2120 } */ 2121 this.getHTMLSmiles($wrap); 2122 //$wrap.contents().filter(function() {return this.nodeType==3}).each($.proxy(this,smileRPL,this)); 2123 2124 return $wrap.html(); 2125 }, 2126 getHTMLSmiles: function(rel) { 2127 $(rel).contents().filter(function() {return this.nodeType==3}).each($.proxy(this.smileRPL,this)); 2128 }, 2129 smileRPL: function(i,el) { 2130 var ndata = el.data; 2131 $.each(this.options.smileList,$.proxy(function(i,row) { 2132 var fidx = ndata.indexOf(row.bbcode); 2133 if (fidx!=-1) { 2134 var afternode_txt = ndata.substring(fidx+row.bbcode.length,ndata.length); 2135 var afternode = document.createTextNode(afternode_txt); 2136 el.data = ndata = el.data.substr(0,fidx); 2137 $(el).after(afternode).after(this.strf(row.img,this.options)); 2138 this.getHTMLSmiles(el.parentNode); 2139 return false;
2140 } 2141 this.getHTMLSmiles(el); 2142 },this)); 2143 }, 2144 //UTILS 2145 setUID: function(el,attr) { 2146 var id = "wbbid_"+(++this.lastid); 2147 if (el) { 2148 $(el).attr(attr || "id",id); 2149 } 2150 return id; 2151 }, 2152 keysToLower: function(o) { 2153 $.each(o,function(k,v) { 2154 if (k!=k.toLowerCase()) { 2155 delete o[k]; 2156 o[k.toLowerCase()]=v; 2157 } 2158 }); 2159 return o; 2160 }, 2161 strf: function(str,data) { 2162 data = this.keysToLower($.extend({},data)); 2163 return str.replace(/\{([\w\.]*)\}/g, function (str, key) {key = key.toLowerCase();var keys = key.split("."), value = data[keys.shift().toLowerCase()];$.each(keys, function () { value = value[this]; }); return (value === null || value === undefined) ? "" : value;}); 2164 }, 2165 elFromString: function(str) { 2166 if (str.indexOf("<")!=-1 && str.indexOf(">")!=-1) { 2167 //create tag 2168 var wr = document.createElement("SPAN"); 2169 $(wr).html(str); 2170 this.setUID(wr,"wbb"); 2171 return ($(wr).contents().size()>1) ? wr:wr.firstChild; 2172 }else{ 2173 //create text node 2174 return document.createTextNode(str); 2175 } 2176 }, 2177 isContain: function(node,sel) { 2178 while (node && !$(node).hasClass("wysibb")) { 2179 if ($(node).is(sel)) {return node}; 2180 if (node) {node = node.parentNode;} 2181 else{return null;} 2182 } 2183 }, 2184 isBBContain: function(bbcode) { 2185 var pos=this.getCursorPosBB(); 2186 var b = this.prepareRGX(bbcode); 2187 var bbrgx = new RegExp(b,"g"); 2188 var a; 2189 var lastindex=0; 2190 while ((a=bbrgx.exec(this.txtArea.value))!=null) { 2191 var p = this.txtArea.value.indexOf(a[0],lastindex); 2192 if (pos>p && pos<(p+a[0].length)) { 2193 return [a,p]; 2194 }
2195 lastindex=p+1; 2196 } 2197 }, 2198 prepareRGX: function(r) { 2199 return r.replace(/(\[|\]|\)|\(|\.|\*|\?|\:|\||\\)/g,"\\$1").replace(/\{.*?\}/g,"([\\s\\S]*?)"); 2200 //return r.replace(/([^a-z0-9)/ig,"\\$1").replace(/\{.*?\}/g,"([\\s\\S]*?)"); 2201 }, 2202 checkForLastBR: function(node) { 2203 if (!node) {$node = this.body;} 2204 if (node.nodeType==3) {node=node.parentNode;} 2205 var $node = $(node); 2206 if ($node.is("span[id*='wbbid']")) {$node = $node.parent();} 2207 if (this.options.bbmode===false && $node.is('div,blockquote,code') && $node.contents().size()>0) { 2208 var l = $node[0].lastChild; 2209 if (!l || (l && l.tagName!="BR")) {$node.append("<br/>");} 2210 } 2211 if (this.$body.contents().size()>0 && this.body.lastChild.tagName!="BR") { 2212 this.$body.append('<br/>'); 2213 } 2214 }, 2215 getAttributeList: function(el) { 2216 var a=[]; 2217 $.each(el.attributes,function(i,attr) { 2218 if (attr.specified) { 2219 a.push(attr.name); 2220 } 2221 }); 2222 return a; 2223 }, 2224 clearFromSubInsert: function(html,cmd) { 2225 if (this.options.allButtons[cmd] && this.options.allButtons[cmd].rootSelector) { 2226 var $wr = $('<div>').html(html); 2227 $.each(this.options.allButtons[cmd].rootSelector,$.proxy(function(i,s) { 2228 var seltext=false; 2229 if (typeof(this.options.rules[s][0][1]["seltext"])!="undefined") { 2230 seltext = this.options.rules[s][0][1]["seltext"]["sel"]; 2231 } 2232 var res=true; 2233 $wr.find("*").each(function() { //work with find("*") and "is", becouse in ie7-8 find is case sensitive 2234 if ($(this).is(s)) { 2235 if (seltext && seltext["sel"]) { 2236 $(this).replaceWith($(this).find(seltext["sel"].toLowerCase()).html()); 2237 }else{ 2238 $(this).replaceWith($(this).html()); 2239 } 2240 res=false; 2241 } 2242 }); 2243 return res; 2244 },this)); 2245 return $wr.html(); 2246 } 2247 return html; 2248 }, 2249 splitPrevNext: function(node) { 2250 if (node.nodeType==3) {node = node.parentNode}; 2251 var f = this.filterByNode(node).replace(/\:eq.*$/g,""); 2252 if ($(node.nextSibling).is(f)) { 2253 $(node).append($(node.nextSibling).html()); 2254 $(node.nextSibling).remove(); 2255 } 2256 if ($(node.previousSibling).is(f)) { 2257 $(node).prepend($(node.previousSibling).html()); 2258 $(node.previousSibling).remove(); 2259 } 2260 }, 2261 modeSwitch: function() { 2262 if (this.options.bbmode) { 2263 //to HTML 2264 this.$body.html(this.getHTML(this.$txtArea.val())); 2265 this.$txtArea.hide().removeAttr("wbbsync").val(""); 2266 this.$body.css("min-height",this.$txtArea.height()).show().focus(); 2267 }else{ 2268 //to bbcode 2269 this.$txtArea.val(this.getBBCode()).css("min-height",this.$body.height()); 2270 this.$body.hide(); 2271 this.$txtArea.show().focus(); 2272 } 2273 this.options.bbmode=!this.options.bbmode; 2274 }, 2275 clearEmpty: function () { 2276 this.$body.children().filter(emptyFilter).remove(); 2277 function emptyFilter() { 2278 if (!$(this).is("span,font,a,b,i,u,s")) { 2279 //clear empty only for span,font 2280 return false; 2281 } 2282 if (!$(this).hasClass("wbbtab") && $.trim($(this).html()).length==0) { 2283 return true; 2284 }else if ($(this).children().size()>0) { 2285 $(this).children().filter(emptyFilter).remove(); 2286 if ($(this).html().length==0 && this.tagName!="BODY") { 2287 return true; 2288 } 2289 } 2290 } 2291 }, 2292 dropdownclick: function(bsel,tsel,e) { 2293 //this.body.focus(); 2294 var $btn = $(e.currentTarget).closest(bsel); 2295 if ($btn.hasClass("dis")) {return;} 2296 if ($btn.attr("wbbshow")) { 2297 //hide dropdown 2298 $btn.removeAttr("wbbshow"); 2299 $(document).unbind("mousedown",this.dropdownhandler); 2300 if (document) { 2301 $(document).unbind("mousedown",this.dropdownhandler); 2302 } 2303 this.lastRange=false; 2304 2305 }else{ 2306 this.saveRange(); 2307 this.$editor.find("*[wbbshow]").each(function(i,el) { 2308 $(el).removeClass("on").find($(el).attr("wbbshow")).hide().end().removeAttr("wbbshow"); 2309 }) 2310 $btn.attr("wbbshow",tsel); 2311 $(document.body).bind("mousedown",$.proxy(function(evt) {this.dropdownhandler($btn,bsel,tsel,evt)},this)); 2312 if (this.$body) { 2313 this.$body.bind("mousedown",$.proxy(function(evt) {this.dropdownhandler($btn,bsel,tsel,evt)},this)); 2314 } 2315 } 2316 $btn.find(tsel).toggle(); 2317 $btn.toggleClass("on"); 2318 }, 2319 dropdownhandler: function($btn,bsel,tsel,e) { 2320 if ($(e.target).parents(bsel).size()==0) { 2321 $btn.removeClass("on").find(tsel).hide(); 2322 $(document).unbind('mousedown',this.dropdownhandler); 2323 if (this.$body) { 2324 this.$body.unbind('mousedown',this.dropdownhandler); 2325 } 2326 } 2327 }, 2328 rgbToHex: function(rgb) { 2329 if (rgb.substr(0, 1)=='#') {return rgb;} 2330 //if (rgb.indexOf("rgb")==-1) {return rgb;} 2331 if (rgb.indexOf("rgb")==-1) { 2332 //IE 2333 var color=parseInt(rgb); 2334 color = ((color & 0x0000ff) << 16) | (color & 0x00ff00) | ((color & 0xff0000) >>> 16); 2335 return '#'+color.toString(16); 2336 } 2337 var digits = /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/.exec(rgb); 2338 return "#"+this.dec2hex(parseInt(digits[2]))+this.dec2hex(parseInt(digits[3]))+this.dec2hex(parseInt(digits[4])); 2339 }, 2340 dec2hex: function(d) { 2341 if(d>15) { 2342 return d.toString(16); 2343 }else{ 2344 return "0"+d.toString(16); 2345 } 2346 }, 2347 sync: function() { 2348 if (this.options.bbmode) { 2349 this.$body.html(this.getHTML(this.txtArea.value,true)); 2350 }else{ 2351 this.$txtArea.attr("wbbsync",1).val(this.getBBCode()); 2352 } 2353 }, 2354 clearPaste: function(el) { 2355 var $block = $(el); 2356 //NEW 2357 $.each(this.options.rules,$.proxy(function(s,ar) { 2358 var $sf = $block.find(s).attr("wbbkeep",1); 2359 if ($sf.size()>0) { 2360 var s2 = ar[0][1]; 2361 $.each(s2,function(i,v) { 2362 if (v.sel) { 2363 $sf.find(v.sel).attr("wbbkeep",1); 2364 } 2365 }); 2366 } 2367 },this)); 2368 $block.find("*[wbbkeep!='1']").each($.proxy(function(i,el) { 2369 var $this = $(el); 2370 if ($this.is('div,p') && ($this.children().size()==0 || el.lastChild.tagName!="BR")) { 2371 $this.after("<br/>"); 2372 } 2373 },this)); 2374 $block.find("*[wbbkeep]").removeAttr("wbbkeep").removeAttr("style"); 2375 $.log($block.html()); 2376 //$.log("BBCODE: "+this.toBB($block.clone(true))); 2377 $block.html(this.getHTML(this.toBB($block),true)); 2378 $.log($block.html()); 2379 2380 //OLD 2381 /* $.each(this.options.rules,$.proxy(function(s,bb) { 2382 $block.find(s).attr("wbbkeep",1); 2383 },this)); 2384 2385 //replace div and p without last br to html()+br 2386 $block.find("*[wbbkeep!='1']").each($.proxy(function(i,el) { 2387 var $this = $(el); 2388 if ($this.is('div,p') && ($this.children().size()==0 || el.lastChild.tagName!="BR")) { 2389 $this.after("<br/>").after($this.contents()).remove(); 2390 }else{ 2391 $this.after($this.contents()).remove(); 2392 } 2393 },this)); 2394 $block.find("*[wbbkeep]").removeAttr("wbbkeep").removeAttr("style"); */ 2395 }, 2396 sortArray: function(ar,asc) { 2397 ar.sort(function(a,b) { 2398 return (a.length-b.length)*(asc || 1); 2399 }); 2400 return ar; 2401 }, 2402 smileFind: function() { 2403 if (this.options.smilefind) { 2404 var $smlist = $(this.options.smilefind).find('img[alt]'); 2405 if ($smlist.size()>0) { 2406 this.options.smileList=[]; 2407 $smlist.each($.proxy(function(i,el) { 2408 var $el=$(el); 2409 this.options.smileList.push({title:$el.attr("title"),bbcode:$el.attr("alt"),img:$el.removeAttr("alt").removeAttr("title")[0].outerHTML}); 2410 },this)); 2411 } 2412 } 2413 }, 2414 destroy: function() { 2415 this.$editor.replaceWith(this.$txtArea); 2416 this.$txtArea.removeClass("wysibb-texarea").show(); 2417 this.$modal.remove(); 2418 this.$txtArea.data("wbb",null); 2419 }, 2420 pressTab: function(e) { 2421 if (e && e.which == 9) { 2422 //insert tab 2423 if (e.preventDefault) {e.preventDefault();} 2424 if (this.options.bbmode) { 2425 this.insertAtCursor(' ',false); 2426 }else{ 2427 this.insertAtCursor('<span class="wbbtab">\uFEFF</span>',false); 2428 //this.execNativeCommand("indent",false); 2429 } 2430 } 2431 }, 2432 removeLastBodyBR: function() { 2433 if (this.body.lastChild && this.body.lastChild.nodeType!=3 && this.body.lastChild.tagName=="BR") { 2434 this.body.removeChild(this.body.lastChild); 2435 this.removeLastBodyBR(); 2436 } 2437 }, 2438 traceTextareaEvent: function(e) { 2439 if ($(e.target).closest("div.wysibb").size()==0) { 2440 if ($(document.activeElement).is("div.wysibb-body")) { 2441 this.saveRange(); 2442 } 2443 setTimeout($.proxy(function() { 2444 var data = this.$txtArea.val(); 2445 if (this.options.bbmode===false && data!="" && $(e.target).closest("div.wysibb").size()==0 && !this.$txtArea.attr("wbbsync")) { 2446 this.selectLastRange(); 2447 this.insertAtCursor(this.getHTML(data,true)); 2448 this.$txtArea.val(""); 2449 } 2450 if ($(document.activeElement).is("div.wysibb-body")) { 2451 this.lastRange=false; 2452 } 2453 },this),100); 2454 } 2455 }, 2456 txtAreaInitContent: function() { 2457 //$.log(this.txtArea.value); 2458 this.$body.html(this.getHTML(this.txtArea.value,true)); 2459 }, 2460 getValidationRGX: function(s) { 2461 if (s.match(/\[\S+\]/)) { 2462 return s.replace(/.*(\\*\[\S+\]).*/,"$1"); 2463 } 2464 return ""; 2465 }, 2466 smileConversion: function() { 2467 if (this.options.smileList && this.options.smileList.length>0) {
2468 var snode = this.getSelectNode(); 2469 if (snode.nodeType==3) { 2470 var ndata = snode.data; 2471 if (ndata.length>=2 && !this.isInClearTextBlock(snode) && $(snode).parents("a").size()==0) { 2472 $.each(this.options.srules,$.proxy(function(i,sar) { 2473 var smbb = sar[0]; 2474 var fidx = ndata.indexOf(smbb); 2475 if (fidx!=-1) { 2476 var afternode_txt = ndata.substring(fidx+smbb.length,ndata.length); 2477 var afternode = document.createTextNode(afternode_txt); 2478 var afternode_cursor = document.createElement("SPAN"); 2479 snode.data = snode.data.substr(0,fidx); 2480 $(snode).after(afternode).after(afternode_cursor).after(this.strf(sar[1],this.options)); 2481 this.selectNode(afternode_cursor); 2482 return false; 2483 } 2484 },this)); 2485 } 2486 } 2487 } 2488 }, 2489 isInClearTextBlock: function() { 2490 if (this.cleartext) { 2491 var find=false; 2492 $.each(this.cleartext,$.proxy(function(sel,command) { 2493 if (this.queryState(command)) { 2494 find=command; 2495 return false; 2496 } 2497 },this)) 2498 return find; 2499 } 2500 return false; 2501 }, 2502 wrapAttrs: function(html) { 2503 $.each(this.options.attrWrap,function(i,a) { 2504 html = html.replace(a+'="','_'+a+'="'); 2505 }); 2506 return html; 2507 }, 2508 unwrapAttrs: function(html) { 2509 $.each(this.options.attrWrap,function(i,a) { 2510 html = html.replace('_'+a+'="',a+'="'); 2511 }); 2512 return html; 2513 }, 2514 disNonActiveButtons: function() { 2515 if (this.isInClearTextBlock()) { 2516 this.$toolbar.find(".wysibb-toolbar-btn:not(.on,.mswitch)").addClass("dis"); 2517 }else{ 2518 this.$toolbar.find(".wysibb-toolbar-btn.dis").removeClass("dis"); 2519 } 2520 }, 2521 setCursorByEl: function(el) { 2522 var sl = document.createTextNode("\uFEFF"); 2523 $(el).after(sl); 2524 this.selectNode(sl); 2525 }, 2526 2527 //img listeners 2528 imgListeners: function() { 2529 $(document).on("mousedown",$.proxy(this.imgEventHandler,this)); 2530 }, 2531 imgEventHandler: function(e) { 2532 var $e = $(e.target); 2533 if (this.hasWrapedImage && ($e.closest(".wbb-img,#wbbmodal").size()==0 || $e.hasClass("wbb-cancel-button"))) { 2534 this.$body.find(".imgWrap ").each(function() { 2535 $.log("Removed imgWrap block"); 2536 $(this).replaceWith($(this).find("img")); 2537 }) 2538 this.hasWrapedImage = false; 2539 this.updateUI(); 2540 } 2541 2542 if ($e.is("img") && $e.closest(".wysibb-body").size()>0) { 2543 $e.wrap("<span class='imgWrap'></span>"); 2544 this.hasWrapedImage = $e; 2545 this.$body.focus(); 2546 this.selectNode($e.parent()[0]); 2547 } 2548 }, 2549 2550 //MODAL WINDOW 2551 showModal: function(cmd,opt,queryState) { 2552 $.log("showModal: "+cmd); 2553 this.saveRange(); 2554 var $cont = this.$modal.find(".wbbm-content").html(""); 2555 var $wbbm = this.$modal.find(".wbbm").removeClass("hastabs"); 2556 this.$modal.find("span.wbbm-title-text").html(opt.title); 2557 if (opt.tabs && opt.tabs.length>1) { 2558 //has tabs, create 2559 $wbbm.addClass("hastabs"); 2560 var $ul = $('<div class="wbbm-tablist">').appendTo($cont).append("<ul>").children("ul"); 2561 $.each(opt.tabs,$.proxy(function(i,row) { 2562 if (i==0) {row['on']="on"} 2563 $ul.append(this.strf('<li class="{on}" onClick="$(this).parent().find(\'.on\').removeClass(\'on\');$(this).addClass(\'on\');$(this).parents(\'.wbbm-content\').find(\'.tab-cont\').hide();$(this).parents(\'.wbbm-content\').find(\'.tab'+i+'\').show()">{title}</li>',row)); 2564 2565 },this)) 2566 } 2567 if (opt.width) { 2568 $wbbm.css("width",opt.width); 2569 } 2570 var $cnt = $('<div class="wbbm-cont">').appendTo($cont); 2571 if (queryState) { 2572 $wbbm.find('#wbbm-remove').show(); 2573 }else{ 2574 $wbbm.find('#wbbm-remove').hide(); 2575 } 2576 $.each(opt.tabs,$.proxy(function(i,r) { 2577 var $c = $('<div>').addClass("tab-cont tab"+i).attr("tid",i).appendTo($cnt); 2578 if (i>0) {$c.hide();} 2579 if (r.html) { 2580 $c.html(this.strf(r.html,this.options)); 2581 }else{ 2582 $.each(r.input,$.proxy(function(j,inp) { 2583 inp["value"]=queryState[inp.param.toLowerCase()]; 2584 if (inp.param.toLowerCase()=="seltext" && (!inp["value"] || inp["value"]=="")) { 2585 inp["value"] = this.getSelectText(this.options.bbmode); 2586 } 2587 if (inp["value"] && inp["value"].indexOf("<span id='wbbid")==0 && $(inp["value"]).is("span[id*='wbbid']")) { 2588 inp["value"] = $(inp["value"]).html(); 2589 } 2590 if (inp.type && inp.type=="div") { 2591 //div input, support wysiwyg input 2592 $c.append(this.strf('<div class="wbbm-inp-row"><label>{title}</label><div class="inp-text div-modal-text" contenteditable="true" name="{param}">{value}</div></div>',inp)); 2593 }else{ 2594 //default input 2595 $c.append(this.strf('<div class="wbbm-inp-row"><label>{title}</label><input class="inp-text modal-text" type="text" name="{param}" value="{value}"/></div>',inp)); 2596 } 2597 2598 2599 },this)); 2600 } 2601 },this)); 2602 2603 //this.lastRange=this.getRange(); 2604 2605 if ($.isFunction(opt.onLoad)) { 2606 opt.onLoad.call(this,cmd,opt,queryState); 2607 } 2608 2609 $wbbm.find('#wbbm-submit').click($.proxy(function() { 2610 2611 if ($.isFunction(opt.onSubmit)) { //custom submit function, if return false, then don't process our function 2612 var r = opt.onSubmit.call(this,cmd,opt,queryState); 2613 if (r===false) {return;} 2614 } 2615 var params={};
2616 var valid=true; 2617 this.$modal.find(".wbbm-inperr").remove(); 2618 this.$modal.find(".wbbm-brdred").removeClass("wbbm-brdred"); 2619 //$.each(this.$modal.find(".tab-cont:visible input"),$.proxy(function(i,el) { 2620 $.each(this.$modal.find(".tab-cont:visible .inp-text"),$.proxy(function(i,el) { 2621 var tid = $(el).parents(".tab-cont").attr("tid"); 2622 var pname = $(el).attr("name").toLowerCase(); 2623 var pval=""; 2624 if ($(el).is("input,textrea,select")) { 2625 pval = $(el).val(); 2626 }else{ 2627 pval = $(el).html(); 2628 } 2629 var validation = opt.tabs[tid]["input"][i]["validation"]; 2630 if (typeof(validation)!="undefined") { 2631 if (!pval.match(new RegExp(validation,"i"))) { 2632 valid=false; 2633 $(el).after('<span class="wbbm-inperr">'+CURLANG.validation_err+'</span>').addClass("wbbm-brdred"); 2634 } 2635 } 2636 params[pname]=pval; 2637 },this)); 2638 if (valid) { 2639 $.log("Last range: "+this.lastRange); 2640 this.selectLastRange(); 2641 //insert callback 2642 if (queryState) { 2643 this.wbbRemoveCallback(cmd,true); 2644 } 2645 this.wbbInsertCallback(cmd,params); 2646 //END insert callback 2647 2648 this.closeModal(); 2649 this.updateUI(); 2650 } 2651 },this)); 2652 $wbbm.find('#wbbm-remove').click($.proxy(function() { 2653 //clbk.remove(); 2654 this.selectLastRange(); 2655 this.wbbRemoveCallback(cmd); //remove callback 2656 this.closeModal(); 2657 this.updateUI(); 2658 },this)); 2659 2660 $(document.body).css("overflow","hidden"); //lock the screen, remove scroll on body 2661 if ($("body").height() > $(window).height()) { //if body has scroll, add padding-right 18px 2662 $(document.body).css("padding-right","18px"); 2663 } 2664 this.$modal.show(); 2665 //if (window.getSelection) 2666 if (this.isMobile) { 2667 $wbbm.css("margin-top","10px"); 2668 }else{ 2669 $wbbm.css("margin-top",($(window).height()-$wbbm.outerHeight())/3+"px"); 2670 } 2671 //setTimeout($.proxy(function() {this.$modal.find("input:visible")[0].focus()},this),10); 2672 setTimeout($.proxy(function() {this.$modal.find(".inp-text:visible")[0].focus()},this),10); 2673 }, 2674 escModal: function(e) { 2675 if (e.which==27) {this.closeModal();} 2676 }, 2677 closeModal: function() { 2678 $(document.body).css("overflow","auto").css("padding-right","0").unbind("keyup",this.escModal); //ESC key close modal; 2679 this.$modal.find('#wbbm-submit,#wbbm-remove').unbind('click'); 2680 this.$modal.hide(); 2681 this.lastRange=false; 2682 return this; 2683 }, 2684 getParams: function(src,s,offset) { 2685 var params={}; 2686 if (this.options.bbmode) { 2687 //bbmode 2688 var stext = s.match(/\{[\s\S]+?\}/g); 2689 s = this.prepareRGX(s); 2690 var rgx = new RegExp(s,"g"); 2691 var val = this.txtArea.value; 2692 if (offset>0) { 2693 val = val.substr(offset,val.length-offset); 2694 } 2695 var a = rgx.exec(val); 2696 if (a) { 2697 $.each(stext,function(i,n) { 2698 params[n.replace(/\{|\}/g,"").replace(/"/g,"'").toLowerCase()] = a[i+1]; 2699 }); 2700 } 2701 }else{ 2702 var rules = this.options.rules[s][0][1]; 2703 $.each(rules,$.proxy(function(k,v) { 2704 var value=""; 2705 var $v = (v.sel!==false) ? value=$(src).find(v.sel):$(src); 2706 if (v.attr!==false) { 2707 value=$v.attr(v.attr); 2708 }else{ 2709 value=$v.html(); 2710 } 2711 if (value) { 2712 if (v.rgx!==false) { 2713 var m = value.match(new RegExp(v.rgx)); 2714 if (m && m.length==2) { 2715 value = m[1]; 2716 } 2717 } 2718 params[k]=value.replace(/"/g,"'"); 2719 } 2720 },this)) 2721 } 2722 return params; 2723 }, 2724 2725 2726 //imgUploader 2727 imgLoadModal: function() { 2728 $.log("imgLoadModal"); 2729 if (this.options.imgupload===true) { 2730 this.$modal.find("#imguploader").dragfileupload({ 2731 url: this.strf(this.options.img_uploadurl,this.options), 2732 extraParams: { 2733 maxwidth: this.options.img_maxwidth, 2734 maxheight: this.options.img_maxheight 2735 }, 2736 themePrefix: this.options.themePrefix, 2737 themeName: this.options.themeName, 2738 success: $.proxy(function(data) { 2739 this.$txtArea.insertImage(data.image_link,data.thumb_link); 2740 2741 this.closeModal(); 2742 this.updateUI(); 2743 },this) 2744 }); 2745 2746 this.$modal.find("#fileupl").bind("change",function() { 2747 $("#fupform").submit(); 2748 }); 2749 this.$modal.find("#fupform").bind("submit",$.proxy(function(e) { 2750 $(e.target).parents("#imguploader").hide().after('<div class="loader"><img src="'+this.options.themePrefix+'/'+this.options.themeName+'/img/loader.gif" /><br/><span>'+CURLANG.loading+'</span></div>').parent().css("text-align","center"); 2751 },this)) 2752 2753 }else{ 2754 this.$modal.find(".hastabs").removeClass("hastabs"); 2755 this.$modal.find("#imguploader").parents(".tab-cont").remove(); 2756 this.$modal.find(".wbbm-tablist").remove(); 2757 } 2758 }, 2759 imgSubmitModal: function() { 2760 $.log("imgSubmitModal"); 2761 }, 2762 //DEBUG 2763 printObjectInIE: function(obj) { 2764 try{ 2765 $.log(JSON.stringify(obj)); 2766 }catch(e) {} 2767 }, 2768 checkFilter: function(node,filter) { 2769 $.log("node: "+$(node).get(0).outerHTML+" filter: "+filter+" res: "+$(node).is(filter.toLowerCase())); 2770 }, 2771 debug: function(msg) { 2772 if (this.options.debug===true) { 2773 var time = (new Date()).getTime(); 2774 if (typeof(console)!="undefined") { 2775 console.log((time-this.startTime)+" ms: "+msg); 2776 }else{ 2777 $("#exlog").append('<p>'+(time-this.startTime)+" ms: "+msg+'</p>'); 2778 } 2779 this.startTime=time; 2780 } 2781 }, 2782 2783 //Browser fixes 2784 isChrome: function() { 2785 return (window.chrome) ? true:false; 2786 }, 2787 fixTableTransform: function(html) { 2788 if (!html) {return "";} 2789 if ($.inArray("table",this.options.buttons)==-1) { 2790 return html.replace(/\<(\/*?(table|tr|td|tbody))[^>]*\>/ig,""); 2791 }else{ 2792 return html.replace(/\<(\/*?(table|tr|td))[^>]*\>/ig,"[$1]".toLowerCase()).replace(/\<\/*tbody[^>]*\>/ig,""); 2793 } 2794 } 2795 } 2796 2797 $.log = function(msg) { 2798 if (typeof(wbbdebug)!="undefined" && wbbdebug===true) { 2799 if (typeof(console)!="undefined") { 2800 console.log(msg); 2801 }else{ 2802 $("#exlog").append('<p>'+msg+'</p>'); 2803 } 2804 } 2805 } 2806 $.fn.wysibb = function(settings) { 2807 return this.each(function() { 2808 var data = $(this).data("wbb"); 2809 if (!data) { 2810 new $.wysibb(this, settings); 2811 } 2812 }); 2813 } 2814 $.fn.wdrag = function(opt) { 2815 if (!opt.scope) {opt.scope=this;} 2816 var start={x:0,y:0, height: 0}; 2817 var drag; 2818 opt.scope.drag_mousedown = function(e) { 2819 e.preventDefault(); 2820 start = { 2821 x: e.pageX, 2822 y: e.pageY, 2823 height: opt.height, 2824 sheight: opt.scope.$body.height() 2825 } 2826 drag=true; 2827 $(document).bind("mousemove",$.proxy(opt.scope.drag_mousemove,this)); 2828 $(this).addClass("drag"); 2829 }; 2830 opt.scope.drag_mouseup = function(e) { 2831 if (drag===true) { 2832 e.preventDefault(); 2833 $(document).unbind("mousemove",opt.scope.drag_mousemove); 2834 $(this).removeClass("drag"); 2835 drag=false; 2836 } 2837 }; 2838 opt.scope.drag_mousemove = function(e) { 2839 e.preventDefault(); 2840 var axisX=0,axisY=0; 2841 if (opt.axisX) { 2842 axisX = e.pageX-start.x; 2843 } 2844 if (opt.axisY) { 2845 axisY = e.pageY-start.y; 2846 }
2847 if (axisY!=0) { 2848 var nheight = start.sheight+axisY; 2849 if (nheight>start.height && nheight<=opt.scope.options.resize_maxheight) { 2850 if (opt.scope.options.bbmode==true) { 2851 opt.scope.$txtArea.css((opt.scope.options.autoresize===true) ? "min-height":"height",nheight+"px"); 2852 }else{ 2853 opt.scope.$body.css((opt.scope.options.autoresize===true) ? "min-height":"height",nheight+"px"); 2854 } 2855 } 2856 } 2857 }; 2858 2859 2860 $(this).bind("mousedown",opt.scope.drag_mousedown); 2861 $(document).bind("mouseup",$.proxy(opt.scope.drag_mouseup,this)); 2862 }, 2863 2864 //API 2865 $.fn.getDoc = function() { 2866 return this.data('wbb').doc; 2867 } 2868 $.fn.getSelectText = function(fromTextArea) { 2869 return this.data('wbb').getSelectText(fromTextArea); 2870 } 2871 $.fn.bbcode = function(data) { 2872 if (typeof(data)!="undefined") { 2873 if (this.data('wbb').options.bbmode) { 2874 this.data('wbb').$txtArea.val(data); 2875 }else{ 2876 this.data('wbb').$body.html(this.data("wbb").getHTML(data)); 2877 } 2878 return this; 2879 }else{ 2880 return this.data('wbb').getBBCode(); 2881 } 2882 } 2883 $.fn.htmlcode = function(data) { 2884 if (!this.data('wbb').options.onlyBBMode && this.data('wbb').inited===true) { 2885 if (typeof(data)!="undefined") { 2886 this.data('wbb').$body.html(data); 2887 return this; 2888 }else{ 2889 return this.data('wbb').getHTML(this.data('wbb').$txtArea.val()); 2890 } 2891 } 2892 } 2893 $.fn.getBBCode = function() { 2894 return this.data('wbb').getBBCode(); 2895 } 2896 $.fn.getHTML = function() { 2897 var wbb = this.data('wbb'); 2898 return wbb.getHTML(wbb.$txtArea.val()); 2899 } 2900 $.fn.getHTMLByCommand = function(command,params) { 2901 return this.data("wbb").getHTMLByCommand(command,params); 2902 } 2903 $.fn.getBBCodeByCommand = function(command,params) { 2904 return this.data("wbb").getBBCodeByCommand(command,params); 2905 } 2906 $.fn.insertAtCursor = function(data,forceBBMode) { 2907 this.data("wbb").insertAtCursor(data,forceBBMode); 2908 return this.data("wbb"); 2909 } 2910 $.fn.execCommand = function(command,value) { 2911 this.data("wbb").execCommand(command,value); 2912 return this.data("wbb"); 2913 } 2914 $.fn.insertImage = function(imgurl,thumburl) { 2915 var editor = this.data("wbb"); 2916 var code = (thumburl) ? editor.getCodeByCommand('link',{url:imgurl,seltext: editor.getCodeByCommand('img',{src:thumburl})}): editor.getCodeByCommand('img',{src:imgurl}); 2917 this.insertAtCursor(code); 2918 return editor; 2919 } 2920 $.fn.sync = function() { 2921 this.data("wbb").sync(); 2922 return this.data("wbb"); 2923 } 2924 $.fn.destroy = function() { 2925 this.data("wbb").destroy(); 2926 } 2927 2928 2929 $.fn.queryState = function(command) { 2930 return this.data("wbb").queryState(command); 2931 } 2932})(jQuery); 2933 2934 2935//Drag&Drop file uploader 2936(function($) { 2937 'use strict'; 2938 2939 $.fn.dragfileupload = function(options) { 2940 return this.each(function() { 2941 var upl = new FileUpload(this, options); 2942 upl.init(); 2943 }); 2944 }; 2945 2946 function FileUpload(e, options) { 2947 this.$block=$(e); 2948 2949 this.opt = $.extend({ 2950 url: false, 2951 success: false, 2952 extraParams: false, 2953 fileParam: 'img', 2954 validation: '\.(jpg|png|gif|jpeg)$', 2955 2956 t1: CURLANG.fileupload_text1, 2957 t2: CURLANG.fileupload_text2 2958 },options); 2959 } 2960 2961 FileUpload.prototype = { 2962 init: function() { 2963 if (window.FormData != null) { 2964 this.$block.addClass("drag"); 2965 this.$block.prepend('<div class="p2">'+this.opt.t2+'</div>'); 2966 this.$block.prepend('<div class="p">'+this.opt.t1+'</div>'); 2967 2968 this.$block.bind('dragover', function() {$(this).addClass('dragover');return false;}); 2969 this.$block.bind('dragleave', function() {$(this).removeClass('dragover');return false;}); 2970 2971 //upload progress 2972 var uploadProgress = $.proxy(function(e) { 2973 var p = parseInt(e.loaded/e.total*100, 10); 2974 this.$loader.children("span").text(CURLANG.loading+': '+ p+'%'); 2975 2976 }, this); 2977 var xhr = jQuery.ajaxSettings.xhr(); 2978 if (xhr.upload) { 2979 xhr.upload.addEventListener('progress', uploadProgress, false); 2980 } 2981 this.$block[0].ondrop = $.proxy(function(e) { 2982 e.preventDefault(); 2983 this.$block.removeClass('dragover'); 2984 var ufile = e.dataTransfer.files[0]; 2985 if (this.opt.validation && !ufile.name.match(new RegExp(this.opt.validation))) { 2986 this.error(CURLANG.validation_err); 2987 return false;
2988 } 2989 var fData = new FormData(); 2990 fData.append(this.opt.fileParam, ufile); 2991 2992 if (this.opt.extraParams) { //check for extraParams to upload 2993 $.each(this.opt.extraParams,function(k,v) { 2994 fData.append(k, v); 2995 }); 2996 } 2997 2998 this.$loader = $('<div class="loader"><img src="'+this.opt.themePrefix+'/'+this.opt.themeName+'/img/loader.gif" /><br/><span>'+CURLANG.loading+'</span></div>'); 2999 this.$block.html(this.$loader); 3000 3001 $.ajax({ 3002 type: 'POST', 3003 url: this.opt.url, 3004 data: fData, 3005 processData: false, 3006 contentType: false, 3007 xhr: function() {return xhr}, 3008 dataType: 'json', 3009 success: $.proxy(function(data) { 3010 if (data && data.status==1) { 3011 this.opt.success(data); 3012 }else{ 3013 this.error(data.msg || CURLANG.error_onupload); 3014 } 3015 },this), 3016 error: $.proxy(function (xhr, txt, thr) {this.error(CURLANG.error_onupload)},this) 3017 }); 3018 },this); 3019 3020 } 3021 }, 3022 error: function(msg) { 3023 this.$block.find(".upl-error").remove().end().append('<span class="upl-error">'+msg+'</span>').addClass("wbbm-brdred"); 3024 } 3025 } 3026})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.