Просмотр файла wu-static/js/bbeditor/jquery.wysibb.js

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