wysibb 1.0.3

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