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