editor.js 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753
  1. // *** smc_Editor class.
  2. function smc_Editor(oOptions)
  3. {
  4. this.opt = oOptions;
  5. // Create some links to the editor object.
  6. this.oTextHandle = null;
  7. this.sCurrentText = 'sText' in this.opt ? this.opt.sText : '';
  8. // How big?
  9. this.sEditWidth = 'sEditWidth' in this.opt ? this.opt.sEditWidth : '70%';
  10. this.sEditHeight = 'sEditHeight' in this.opt ? this.opt.sEditHeight : '150px';
  11. this.showDebug = false;
  12. this.bRichTextEnabled = 'bWysiwyg' in this.opt && this.opt.bWysiwyg;
  13. // This doesn't work on Opera as they cannot restore focus after clicking a BBC button.
  14. this.bRichTextPossible = !this.opt.bRichEditOff && ((is_ie5up && !is_ie50) || is_ff || is_opera95up || is_safari || is_chrome) && !(is_iphone || is_android);
  15. this.oFrameHandle = null;
  16. this.oFrameDocument = null;
  17. this.oFrameWindow = null;
  18. // These hold the breadcrumb.
  19. this.oBreadHandle = null;
  20. this.oResizerElement = null;
  21. // Kinda holds all the useful stuff.
  22. this.aKeyboardShortcuts = new Array();
  23. // This tracks the cursor position on IE to avoid refocus problems.
  24. this.cursorX = 0;
  25. this.cursorY = 0;
  26. // This is all the elements that can have a simple execCommand.
  27. this.oSimpleExec = {
  28. b: 'bold',
  29. u: 'underline',
  30. i: 'italic',
  31. s: 'strikethrough',
  32. left: 'justifyleft',
  33. center: 'justifycenter',
  34. right: 'justifyright',
  35. hr: 'inserthorizontalrule',
  36. list: 'insertunorderedlist',
  37. orderlist: 'insertorderedlist',
  38. sub: 'subscript',
  39. sup: 'superscript',
  40. indent: 'indent',
  41. outdent: 'outdent'
  42. }
  43. // Codes to call a private function
  44. this.oSmfExec = {
  45. unformat: 'removeFormatting',
  46. toggle: 'toggleView'
  47. }
  48. // Any special breadcrumb mappings to ensure we show a consistant tag name.
  49. this.breadCrumbNameTags = {
  50. strike: 's',
  51. strong: 'b',
  52. em: 'i'
  53. }
  54. this.aBreadCrumbNameStyles = [
  55. {
  56. sStyleType: 'text-decoration',
  57. sStyleValue: 'underline',
  58. sBbcTag: 'u'
  59. },
  60. {
  61. sStyleType: 'text-decoration',
  62. sStyleValue: 'line-through',
  63. sBbcTag: 's'
  64. },
  65. {
  66. sStyleType: 'text-align',
  67. sStyleValue: 'left',
  68. sBbcTag: 'left'
  69. },
  70. {
  71. sStyleType: 'text-align',
  72. sStyleValue: 'center',
  73. sBbcTag: 'center'
  74. },
  75. {
  76. sStyleType: 'text-align',
  77. sStyleValue: 'right',
  78. sBbcTag: 'right'
  79. },
  80. {
  81. sStyleType: 'font-weight',
  82. sStyleValue: 'bold',
  83. sBbcTag: 'b'
  84. },
  85. {
  86. sStyleType: 'font-style',
  87. sStyleValue: 'italic',
  88. sBbcTag: 'i'
  89. }
  90. ];
  91. // All the fonts in the world.
  92. this.aFontFaces = [
  93. 'Arial',
  94. 'Arial Black',
  95. 'Impact',
  96. 'Verdana',
  97. 'Times New Roman',
  98. 'Georgia',
  99. 'Andale Mono',
  100. 'Trebuchet MS',
  101. 'Comic Sans MS'
  102. ];
  103. // Font maps (HTML => CSS size)
  104. this.aFontSizes = [
  105. 0,
  106. 8,
  107. 10,
  108. 12,
  109. 14,
  110. 18,
  111. 24,
  112. 36
  113. ];
  114. // Color maps! (hex => name)
  115. this.oFontColors = {
  116. black: '#000000',
  117. red: '#ff0000',
  118. yellow: '#ffff00',
  119. pink: '#ffc0cb',
  120. green: '#008000',
  121. orange: '#ffa500',
  122. purple: '#800080',
  123. blue: '#0000ff',
  124. beige: '#f5f5dc',
  125. brown: '#a52a2a',
  126. teal: '#008080',
  127. navy: '#000080',
  128. maroon: '#800000',
  129. limegreen: '#32cd32'
  130. }
  131. this.sFormId = 'sFormId' in this.opt ? this.opt.sFormId : 'postmodify';
  132. this.iArrayPosition = smf_editorArray.length;
  133. // Current resize state.
  134. this.osmc_EditorCurrentResize = {};
  135. this.init();
  136. }
  137. smc_Editor.prototype.init = function()
  138. {
  139. // Define the event wrapper functions.
  140. var oCaller = this;
  141. this.aEventWrappers = {
  142. editorKeyUp: function(oEvent) {return oCaller.editorKeyUp(oEvent);},
  143. shortcutCheck: function(oEvent) {return oCaller.shortcutCheck(oEvent);},
  144. editorBlur: function(oEvent) {return oCaller.editorBlur(oEvent);},
  145. editorFocus: function(oEvent) {return oCaller.editorFocus(oEvent);},
  146. startResize: function(oEvent) {return oCaller.startResize(oEvent);},
  147. resizeOverDocument: function(oEvent) {return oCaller.resizeOverDocument(oEvent);},
  148. endResize: function(oEvent) {return oCaller.endResize(oEvent);},
  149. resizeOverIframe: function(oEvent) {return oCaller.resizeOverIframe(oEvent);}
  150. };
  151. // Set the textHandle.
  152. this.oTextHandle = document.getElementById(this.opt.sUniqueId);
  153. // Ensure the currentText is set correctly depending on the mode.
  154. if (this.sCurrentText == '' && !this.bRichTextEnabled)
  155. this.sCurrentText = getInnerHTML(this.oTextHandle).php_unhtmlspecialchars();
  156. // Only try to do this if rich text is supported.
  157. if (this.bRichTextPossible)
  158. {
  159. // Make the iframe itself, stick it next to the current text area, and give it an ID.
  160. this.oFrameHandle = document.createElement('iframe');
  161. this.oFrameHandle.src = 'about:blank';
  162. this.oFrameHandle.id = 'html_' + this.opt.sUniqueId;
  163. this.oFrameHandle.className = 'rich_editor_frame';
  164. this.oFrameHandle.style.display = 'none';
  165. this.oFrameHandle.style.margin = '0px';
  166. this.oFrameHandle.tabIndex = this.oTextHandle.tabIndex;
  167. this.oTextHandle.parentNode.appendChild(this.oFrameHandle);
  168. // Create some handy shortcuts.
  169. this.oFrameDocument = this.oFrameHandle.contentDocument ? this.oFrameHandle.contentDocument : ('contentWindow' in this.oFrameHandle ? this.oFrameHandle.contentWindow.document : this.oFrameHandle.document);
  170. this.oFrameWindow = 'contentWindow' in this.oFrameHandle ? this.oFrameHandle.contentWindow : this.oFrameHandle.document.parentWindow;
  171. // Create the debug window... and stick this under the main frame - make it invisible by default.
  172. this.oBreadHandle = document.createElement('div');
  173. this.oBreadHandle.id = 'bread_' . uid;
  174. this.oBreadHandle.style.visibility = 'visible';
  175. this.oBreadHandle.style.display = 'none';
  176. this.oFrameHandle.parentNode.appendChild(this.oBreadHandle);
  177. // Size the iframe dimensions to something sensible.
  178. this.oFrameHandle.style.width = this.sEditWidth;
  179. this.oFrameHandle.style.height = this.sEditHeight;
  180. this.oFrameHandle.style.visibility = 'visible';
  181. // Only bother formatting the debug window if debug is enabled.
  182. if (this.showDebug)
  183. {
  184. this.oBreadHandle.style.width = this.sEditWidth;
  185. this.oBreadHandle.style.height = '20px';
  186. this.oBreadHandle.className = 'windowbg2';
  187. this.oBreadHandle.style.border = '1px black solid';
  188. this.oBreadHandle.style.display = '';
  189. }
  190. // Populate the editor with nothing by default.
  191. if (!is_opera95up)
  192. {
  193. this.oFrameDocument.open();
  194. this.oFrameDocument.write('');
  195. this.oFrameDocument.close();
  196. }
  197. // Right to left mode?
  198. if (this.opt.bRTL)
  199. {
  200. this.oFrameDocument.dir = "rtl";
  201. this.oFrameDocument.body.dir = "rtl";
  202. }
  203. // Mark it as editable...
  204. if (this.oFrameDocument.body.contentEditable)
  205. this.oFrameDocument.body.contentEditable = true;
  206. else
  207. {
  208. this.oFrameHandle.style.display = '';
  209. this.oFrameDocument.designMode = 'on';
  210. this.oFrameHandle.style.display = 'none';
  211. }
  212. // Now we need to try and style the editor - internet explorer allows us to do the whole lot.
  213. if (document.styleSheets['editor_css'] || document.styleSheets['editor_ie_css'])
  214. {
  215. var oMyStyle = this.oFrameDocument.createElement('style');
  216. this.oFrameDocument.documentElement.firstChild.appendChild(oMyStyle);
  217. oMyStyle.styleSheet.cssText = document.styleSheets['editor_ie_css'] ? document.styleSheets['editor_ie_css'].cssText : document.styleSheets['editor_css'].cssText;
  218. }
  219. // Otherwise we seem to have to try to rip out each of the styles one by one!
  220. else if (document.styleSheets.length)
  221. {
  222. var bFoundSomething = false;
  223. // First we need to find the right style sheet.
  224. for (var i = 0, iNumStyleSheets = document.styleSheets.length; i < iNumStyleSheets; i++)
  225. {
  226. // Start off looking for the right style sheet.
  227. if (!document.styleSheets[i].href || document.styleSheets[i].href.indexOf('editor') < 1)
  228. continue;
  229. // Firefox won't allow us to get a CSS file which ain't in the right URL.
  230. try
  231. {
  232. if (document.styleSheets[i].cssRules.length < 1)
  233. continue;
  234. }
  235. catch (e)
  236. {
  237. continue;
  238. }
  239. // Manually try to find the rich_editor class.
  240. for (var r = 0, iNumRules = document.styleSheets[i].cssRules.length; r < iNumRules; r++)
  241. {
  242. // Got the main editor?
  243. if (document.styleSheets[i].cssRules[r].selectorText == '.rich_editor')
  244. {
  245. // Set some possible styles.
  246. if (document.styleSheets[i].cssRules[r].style.color)
  247. this.oFrameDocument.body.style.color = document.styleSheets[i].cssRules[r].style.color;
  248. if (document.styleSheets[i].cssRules[r].style.backgroundColor)
  249. this.oFrameDocument.body.style.backgroundColor = document.styleSheets[i].cssRules[r].style.backgroundColor;
  250. if (document.styleSheets[i].cssRules[r].style.fontSize)
  251. this.oFrameDocument.body.style.fontSize = document.styleSheets[i].cssRules[r].style.fontSize;
  252. if (document.styleSheets[i].cssRules[r].style.fontFamily)
  253. this.oFrameDocument.body.style.fontFamily = document.styleSheets[i].cssRules[r].style.fontFamily;
  254. if (document.styleSheets[i].cssRules[r].style.border)
  255. this.oFrameDocument.body.style.border = document.styleSheets[i].cssRules[r].style.border;
  256. bFoundSomething = true;
  257. }
  258. // The frame?
  259. else if (document.styleSheets[i].cssRules[r].selectorText == '.rich_editor_frame')
  260. {
  261. if (document.styleSheets[i].cssRules[r].style.border)
  262. this.oFrameHandle.style.border = document.styleSheets[i].cssRules[r].style.border;
  263. }
  264. }
  265. }
  266. // Didn't find it?
  267. if (!bFoundSomething)
  268. {
  269. // Do something that is better than nothing.
  270. this.oFrameDocument.body.style.color = 'black';
  271. this.oFrameDocument.body.style.backgroundColor = 'white';
  272. this.oFrameDocument.body.style.fontSize = '78%';
  273. this.oFrameDocument.body.style.fontFamily = '"Verdana", "Arial", "Helvetica", "sans-serif"';
  274. this.oFrameDocument.body.style.border = 'none';
  275. this.oFrameHandle.style.border = '1px solid #808080';
  276. if (is_opera)
  277. this.oFrameDocument.body.style.height = '99%';
  278. }
  279. }
  280. // Apply the class...
  281. this.oFrameDocument.body.className = 'rich_editor';
  282. // Set the frame padding/margin inside the editor.
  283. this.oFrameDocument.body.style.padding = '1px';
  284. this.oFrameDocument.body.style.margin = '0';
  285. // Listen for input.
  286. this.oFrameDocument.instanceRef = this;
  287. this.oFrameHandle.instanceRef = this;
  288. this.oTextHandle.instanceRef = this;
  289. // Attach addEventListener for those browsers that don't support it.
  290. createEventListener(this.oFrameHandle);
  291. createEventListener(this.oFrameDocument);
  292. createEventListener(this.oTextHandle);
  293. createEventListener(window);
  294. createEventListener(document);
  295. // Attach functions to the key and mouse events.
  296. this.oFrameDocument.addEventListener('keyup', this.aEventWrappers.editorKeyUp, true);
  297. this.oFrameDocument.addEventListener('mouseup', this.aEventWrappers.editorKeyUp, true);
  298. this.oFrameDocument.addEventListener('keydown', this.aEventWrappers.shortcutCheck, true);
  299. this.oTextHandle.addEventListener('keydown', this.aEventWrappers.shortcutCheck, true);
  300. if (is_ie)
  301. {
  302. this.oFrameDocument.addEventListener('blur', this.aEventWrappers.editorBlur, true);
  303. this.oFrameDocument.addEventListener('focus', this.aEventWrappers.editorFocus, true);
  304. }
  305. // Show the iframe only if wysiwyrg is on - and hide the text area.
  306. this.oTextHandle.style.display = this.bRichTextEnabled ? 'none' : '';
  307. this.oFrameHandle.style.display = this.bRichTextEnabled ? '' : 'none';
  308. this.oBreadHandle.style.display = this.bRichTextEnabled ? '' : 'none';
  309. }
  310. // If we can't do advanced stuff then just do the basics.
  311. else
  312. {
  313. // Cannot have WYSIWYG anyway!
  314. this.bRichTextEnabled = false;
  315. // We need some of the event handlers.
  316. createEventListener(this.oTextHandle);
  317. createEventListener(window);
  318. createEventListener(document);
  319. }
  320. // Make sure we set the message mode correctly.
  321. document.getElementById(this.opt.sUniqueId + '_mode').value = this.bRichTextEnabled ? 1 : 0;
  322. // Show the resizer.
  323. if (document.getElementById(this.opt.sUniqueId + '_resizer') && (!is_opera || is_opera95up) && !(is_chrome && !this.bRichTextEnabled))
  324. {
  325. // Currently nothing is being resized...I assume!
  326. window.smf_oCurrentResizeEditor = null;
  327. this.oResizerElement = document.getElementById(this.opt.sUniqueId + '_resizer');
  328. this.oResizerElement.style.display = '';
  329. createEventListener(this.oResizerElement);
  330. this.oResizerElement.addEventListener('mousedown', this.aEventWrappers.startResize, false);
  331. }
  332. // Set the text - if WYSIWYG is enabled that is.
  333. if (this.bRichTextEnabled)
  334. {
  335. this.insertText(this.sCurrentText, true);
  336. // Better make us the focus!
  337. this.setFocus();
  338. }
  339. // Finally, register shortcuts.
  340. this.registerDefaultShortcuts();
  341. this.updateEditorControls();
  342. }
  343. // Return the current text.
  344. smc_Editor.prototype.getText = function(bPrepareEntities, bModeOverride)
  345. {
  346. var bCurMode = typeof(bModeOverride) != 'undefined' ? bModeOverride : this.bRichTextEnabled;
  347. if (!bCurMode || this.oFrameDocument == null)
  348. {
  349. var sText = this.oTextHandle.value;
  350. if (bPrepareEntities)
  351. sText = sText.replace(/</g, '#smlt#').replace(/>/g, '#smgt#').replace(/&/g, '#smamp#');
  352. }
  353. else
  354. {
  355. var sText = this.oFrameDocument.body.innerHTML;
  356. if (bPrepareEntities)
  357. sText = sText.replace(/&lt;/g, '#smlt#').replace(/&gt;/g, '#smgt#').replace(/&amp;/g, '#smamp#');
  358. }
  359. // Clean it up - including removing semi-colons.
  360. if (bPrepareEntities)
  361. sText = sText.replace(/&nbsp;/g, ' ').replace(/;/g, '#smcol#');
  362. // Return it.
  363. return sText;
  364. }
  365. // Return the current text.
  366. smc_Editor.prototype.unprotectText = function(sText)
  367. {
  368. var bCurMode = typeof(bModeOverride) != 'undefined' ? bModeOverride : this.bRichTextEnabled;
  369. // This restores smlt, smgt and smamp into boring entities, to unprotect against XML'd information like quotes.
  370. sText = sText.replace(/#smlt#/g, '&lt;').replace(/#smgt#/g, '&gt;').replace(/#smamp#/g, '&amp;');
  371. // Return it.
  372. return sText;
  373. }
  374. smc_Editor.prototype.editorKeyUp = function()
  375. {
  376. // Rebuild the breadcrumb.
  377. this.updateEditorControls();
  378. }
  379. smc_Editor.prototype.editorBlur = function()
  380. {
  381. if (!is_ie)
  382. return;
  383. // Need to do something here.
  384. }
  385. smc_Editor.prototype.editorFocus = function()
  386. {
  387. if (!is_ie)
  388. return;
  389. // Need to do something here.
  390. }
  391. // Rebuild the breadcrumb etc - and set things to the correct context.
  392. smc_Editor.prototype.updateEditorControls = function()
  393. {
  394. // Everything else is specific to HTML mode.
  395. if (!this.bRichTextEnabled)
  396. {
  397. // Set none of the buttons active.
  398. if (this.opt.oBBCBox)
  399. this.opt.oBBCBox.setActive([]);
  400. return;
  401. }
  402. var aCrumb = new Array();
  403. var aAllCrumbs = new Array();
  404. var iMaxLength = 6;
  405. // What is the current element?
  406. var oCurTag = this.getCurElement();
  407. var i = 0;
  408. while (typeof(oCurTag) == 'object' && oCurTag != null && oCurTag.nodeName.toLowerCase() != 'body' && i < iMaxLength)
  409. {
  410. aCrumb[i++] = oCurTag;
  411. oCurTag = oCurTag.parentNode;
  412. }
  413. // Now print out the tree.
  414. var sTree = '';
  415. var sCurFontName = '';
  416. var sCurFontSize = '';
  417. var sCurFontColor = '';
  418. for (var i = 0, iNumCrumbs = aCrumb.length; i < iNumCrumbs; i++)
  419. {
  420. var sCrumbName = aCrumb[i].nodeName.toLowerCase();
  421. // Does it have an alternative name?
  422. if (sCrumbName in this.breadCrumbNameTags)
  423. sCrumbName = this.breadCrumbNameTags[sCrumbName];
  424. // Don't bother with this...
  425. else if (sCrumbName == 'p')
  426. continue;
  427. // A link?
  428. else if (sCrumbName == 'a')
  429. {
  430. var sUrlInfo = aCrumb[i].getAttribute('href');
  431. sCrumbName = 'url';
  432. if (typeof(sUrlInfo) == 'string')
  433. {
  434. if (sUrlInfo.substr(0, 3) == 'ftp')
  435. sCrumbName = 'ftp';
  436. else if (sUrlInfo.substr(0, 6) == 'mailto')
  437. sCrumbName = 'email';
  438. }
  439. }
  440. else if (sCrumbName == 'span' || sCrumbName == 'div')
  441. {
  442. if (aCrumb[i].style)
  443. {
  444. for (var j = 0, iNumStyles = this.aBreadCrumbNameStyles.length; j < iNumStyles; j++)
  445. {
  446. // Do we have a font?
  447. if (aCrumb[i].style.fontFamily && aCrumb[i].style.fontFamily != '' && sCurFontName == '')
  448. {
  449. sCurFontName = aCrumb[i].style.fontFamily;
  450. sCrumbName = 'face';
  451. }
  452. // ... or a font size?
  453. if (aCrumb[i].style.fontSize && aCrumb[i].style.fontSize != '' && sCurFontSize == '')
  454. {
  455. sCurFontSize = aCrumb[i].style.fontSize;
  456. sCrumbName = 'size';
  457. }
  458. // ... even color?
  459. if (aCrumb[i].style.color && aCrumb[i].style.color != '' && sCurFontColor == '')
  460. {
  461. sCurFontColor = aCrumb[i].style.color;
  462. if (in_array(sCurFontColor, this.oFontColors))
  463. sCurFontColor = array_search(sCurFontColor, this.oFontColors);
  464. sCrumbName = 'color';
  465. }
  466. if (this.aBreadCrumbNameStyles[j].sStyleType == 'text-align' && aCrumb[i].style.textAlign && aCrumb[i].style.textAlign == this.aBreadCrumbNameStyles[j].sStyleValue)
  467. sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag;
  468. else if (this.aBreadCrumbNameStyles[j].sStyleType == 'text-decoration' && aCrumb[i].style.textDecoration && aCrumb[i].style.textDecoration == this.aBreadCrumbNameStyles[j].sStyleValue)
  469. sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag;
  470. else if (this.aBreadCrumbNameStyles[j].sStyleType == 'font-weight' && aCrumb[i].style.fontWeight && aCrumb[i].style.fontWeight == this.aBreadCrumbNameStyles[j].sStyleValue)
  471. sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag;
  472. else if (this.aBreadCrumbNameStyles[j].sStyleType == 'font-style' && aCrumb[i].style.fontStyle && aCrumb[i].style.fontStyle == this.aBreadCrumbNameStyles[j].sStyleValue)
  473. sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag;
  474. }
  475. }
  476. }
  477. // Do we have a font?
  478. else if (sCrumbName == 'font')
  479. {
  480. if (aCrumb[i].getAttribute('face') && sCurFontName == '')
  481. {
  482. sCurFontName = aCrumb[i].getAttribute('face').toLowerCase();
  483. sCrumbName = 'face';
  484. }
  485. if (aCrumb[i].getAttribute('size') && sCurFontSize == '')
  486. {
  487. sCurFontSize = aCrumb[i].getAttribute('size');
  488. sCrumbName = 'size';
  489. }
  490. if (aCrumb[i].getAttribute('color') && sCurFontColor == '')
  491. {
  492. sCurFontColor = aCrumb[i].getAttribute('color');
  493. if (in_array(sCurFontColor, this.oFontColors))
  494. sCurFontColor = array_search(sCurFontColor, this.oFontColors);
  495. sCrumbName = 'color';
  496. }
  497. // Something else - ignore.
  498. if (sCrumbName == 'font')
  499. continue;
  500. }
  501. sTree += (i != 0 ? '&nbsp;<strong>&gt;</strong>' : '') + '&nbsp;' + sCrumbName;
  502. aAllCrumbs[aAllCrumbs.length] = sCrumbName;
  503. }
  504. // Since we're in WYSIWYG state, show the toggle button as active.
  505. aAllCrumbs[aAllCrumbs.length] = 'toggle';
  506. this.opt.oBBCBox.setActive(aAllCrumbs);
  507. // Try set the font boxes correct.
  508. this.opt.oBBCBox.setSelect('sel_face', sCurFontName);
  509. this.opt.oBBCBox.setSelect('sel_size', sCurFontSize);
  510. this.opt.oBBCBox.setSelect('sel_color', sCurFontColor);
  511. if (this.showDebug)
  512. setInnerHTML(this.oBreadHandle, sTree);
  513. }
  514. // Set the HTML content to be that of the text box - if we are in wysiwyg mode.
  515. smc_Editor.prototype.doSubmit = function()
  516. {
  517. if (this.bRichTextEnabled)
  518. this.oTextHandle.value = this.oFrameDocument.body.innerHTML;
  519. }
  520. // Populate the box with text.
  521. smc_Editor.prototype.insertText = function(sText, bClear, bForceEntityReverse, iMoveCursorBack)
  522. {
  523. if (bForceEntityReverse)
  524. sText = this.unprotectText(sText);
  525. // Erase it all?
  526. if (bClear)
  527. {
  528. if (this.bRichTextEnabled)
  529. {
  530. // This includes a work around for FF to get the cursor to show!
  531. this.oFrameDocument.body.innerHTML = sText;
  532. // If FF trick the cursor into coming back!
  533. if (is_ff || is_opera)
  534. {
  535. // For some entirely unknown reason FF3 Beta 2 and some Opera versions
  536. // require this.
  537. this.oFrameDocument.body.contentEditable = false;
  538. this.oFrameDocument.designMode = 'off';
  539. this.oFrameDocument.designMode = 'on';
  540. }
  541. }
  542. else
  543. this.oTextHandle.value = sText;
  544. }
  545. else
  546. {
  547. this.setFocus();
  548. if (this.bRichTextEnabled)
  549. {
  550. // IE croaks if you have an image selected and try to insert!
  551. if ('selection' in this.oFrameDocument && this.oFrameDocument.selection.type != 'Text' && this.oFrameDocument.selection.type != 'None' && this.oFrameDocument.selection.clear)
  552. this.oFrameDocument.selection.clear();
  553. var oRange = this.getRange();
  554. if (oRange.pasteHTML)
  555. {
  556. oRange.pasteHTML(sText);
  557. // Do we want to move the cursor back at all?
  558. if (iMoveCursorBack)
  559. oRange.moveEnd('character', -iMoveCursorBack);
  560. oRange.select();
  561. }
  562. else
  563. {
  564. // If the cursor needs to be positioned, insert the last fragment first.
  565. if (typeof(iMoveCursorBack) != 'undefined' && iMoveCursorBack > 0 && sText.length > iMoveCursorBack)
  566. {
  567. var oSelection = this.getSelect(false, false);
  568. var oRange = oSelection.getRangeAt(0);
  569. oRange.insertNode(this.oFrameDocument.createTextNode(sText.substr(sText.length - iMoveCursorBack)));
  570. }
  571. this.smf_execCommand('inserthtml', false, typeof(iMoveCursorBack) == 'undefined' ? sText : sText.substr(0, sText.length - iMoveCursorBack));
  572. }
  573. }
  574. else
  575. {
  576. replaceText(sText, this.oTextHandle);
  577. }
  578. }
  579. }
  580. // Special handler for WYSIWYG.
  581. smc_Editor.prototype.smf_execCommand = function(sCommand, bUi, sValue)
  582. {
  583. return this.oFrameDocument.execCommand(sCommand, bUi, sValue);
  584. }
  585. smc_Editor.prototype.insertSmiley = function(oSmileyProperties)
  586. {
  587. // In text mode we just add it in as we always did.
  588. if (!this.bRichTextEnabled)
  589. {
  590. // For gecko clients, do a smart insert of the smile
  591. if ('selectionStart' in this.oTextHandle)
  592. {
  593. var begin = this.oTextHandle.value.substr(this.oTextHandle.selectionStart - 1, 1);
  594. var end = this.oTextHandle.value.substr(this.oTextHandle.selectionEnd, 1);
  595. this.insertText((begin != ' ' ? ' ' : '') + oSmileyProperties.sCode + (end != ' ' ? ' ' : ''));
  596. }
  597. else
  598. this.insertText(' ' + oSmileyProperties.sCode);
  599. }
  600. // Otherwise we need to do a whole image...
  601. else
  602. {
  603. var iUniqueSmileyId = 1000 + Math.floor(Math.random() * 100000);
  604. this.insertText('<img src="' + oSmileyProperties.sSrc + '" id="smiley_' + iUniqueSmileyId + '_' + oSmileyProperties.sSrc.replace(/^.*\//, '') + '" onresizestart="return false;" align="bottom" alt="" title="' + oSmileyProperties.sDescription.php_htmlspecialchars() + '" style="padding: 0 3px 0 3px;" />');
  605. }
  606. }
  607. smc_Editor.prototype.handleButtonClick = function (oButtonProperties)
  608. {
  609. this.setFocus();
  610. // A special SMF function?
  611. if (oButtonProperties.sCode in this.oSmfExec)
  612. this[this.oSmfExec[oButtonProperties.sCode]]();
  613. else
  614. {
  615. // In text this is easy...
  616. if (!this.bRichTextEnabled)
  617. {
  618. // Replace?
  619. if (!('sAfter' in oButtonProperties) || oButtonProperties.sAfter == null)
  620. replaceText(oButtonProperties.sBefore.replace(/\\n/g, '\n'), this.oTextHandle)
  621. // Surround!
  622. else
  623. surroundText(oButtonProperties.sBefore.replace(/\\n/g, '\n'), oButtonProperties.sAfter.replace(/\\n/g, '\n'), this.oTextHandle)
  624. }
  625. else
  626. {
  627. // Is it easy?
  628. if (oButtonProperties.sCode in this.oSimpleExec)
  629. this.smf_execCommand(this.oSimpleExec[oButtonProperties.sCode], false, null);
  630. // A link?
  631. else if (oButtonProperties.sCode == 'url' || oButtonProperties.sCode == 'email' || oButtonProperties.sCode == 'ftp')
  632. this.insertLink(oButtonProperties.sCode);
  633. // Maybe an image?
  634. else if (oButtonProperties.sCode == 'img')
  635. this.insertImage();
  636. // Everything else means doing something ourselves.
  637. else if ('sBefore' in oButtonProperties)
  638. this.insertCustomHTML(oButtonProperties.sBefore.replace(/\\n/g, '\n'), oButtonProperties.sAfter.replace(/\\n/g, '\n'));
  639. }
  640. }
  641. this.updateEditorControls();
  642. // Finally set the focus.
  643. this.setFocus();
  644. }
  645. // Changing a select box?
  646. smc_Editor.prototype.handleSelectChange = function (oSelectProperties)
  647. {
  648. this.setFocus();
  649. var sValue = oSelectProperties.oSelect.value;
  650. if (sValue == '')
  651. return true;
  652. // Changing font face?
  653. if (oSelectProperties.sName == 'sel_face')
  654. {
  655. // Not in HTML mode?
  656. if (!this.bRichTextEnabled)
  657. {
  658. sValue = sValue.replace(/"/, '');
  659. surroundText('[font=' + sValue + ']', '[/font]', this.oTextHandle);
  660. oSelectProperties.oSelect.selectedIndex = 0;
  661. }
  662. else
  663. {
  664. if (is_webkit)
  665. this.smf_execCommand('styleWithCSS', false, true);
  666. this.smf_execCommand('fontname', false, sValue);
  667. }
  668. }
  669. // Font size?
  670. else if (oSelectProperties.sName == 'sel_size')
  671. {
  672. // Are we in boring mode?
  673. if (!this.bRichTextEnabled)
  674. {
  675. surroundText('[size=' + this.aFontSizes[sValue] + 'pt]', '[/size]', this.oTextHandle);
  676. oSelectProperties.oSelect.selectedIndex = 0;
  677. }
  678. else
  679. this.smf_execCommand('fontsize', false, sValue);
  680. }
  681. // Or color even?
  682. else if (oSelectProperties.sName == 'sel_color')
  683. {
  684. // Are we in boring mode?
  685. if (!this.bRichTextEnabled)
  686. {
  687. surroundText('[color=' + sValue + ']', '[/color]', this.oTextHandle);
  688. oSelectProperties.oSelect.selectedIndex = 0;
  689. }
  690. else
  691. this.smf_execCommand('forecolor', false, sValue);
  692. }
  693. this.updateEditorControls();
  694. return true;
  695. }
  696. // Put in some custom HTML.
  697. smc_Editor.prototype.insertCustomHTML = function(sLeftTag, sRightTag)
  698. {
  699. var sSelection = this.getSelect(true, true);
  700. if (sSelection.length == 0)
  701. sSelection = '';
  702. // Are we overwriting?
  703. if (sRightTag == '')
  704. this.insertText(sLeftTag);
  705. // If something was selected, replace and position cursor at the end of it.
  706. else if (sSelection.length > 0)
  707. this.insertText(sLeftTag + sSelection + sRightTag, false, false, 0);
  708. // Wrap the tags around the cursor position.
  709. else
  710. this.insertText(sLeftTag + sRightTag, false, false, sRightTag.length);
  711. }
  712. // Insert a URL link.
  713. smc_Editor.prototype.insertLink = function(sType)
  714. {
  715. if (sType == 'email')
  716. var sPromptText = oEditorStrings['prompt_text_email'];
  717. else if (sType == 'ftp')
  718. var sPromptText = oEditorStrings['prompt_text_ftp'];
  719. else
  720. var sPromptText = oEditorStrings['prompt_text_url'];
  721. // IE has a nice prompt for this - others don't.
  722. if (sType != 'email' && sType != 'ftp' && is_ie)
  723. this.smf_execCommand('createlink', true, 'http://');
  724. else
  725. {
  726. // Ask them where to link to.
  727. var sText = prompt(sPromptText, sType == 'email' ? '' : (sType == 'ftp' ? 'ftp://' : 'http://'));
  728. if (!sText)
  729. return;
  730. if (sType == 'email' && sText.indexOf('mailto:') != 0)
  731. sText = 'mailto:' + sText;
  732. // Check if we have text selected and if not force us to have some.
  733. var oCurText = this.getSelect(true, true);
  734. if (oCurText.toString().length != 0)
  735. {
  736. this.smf_execCommand('unlink');
  737. this.smf_execCommand('createlink', false, sText);
  738. }
  739. else
  740. this.insertText('<a href="' + sText + '">' + sText + '</a>');
  741. }
  742. }
  743. smc_Editor.prototype.insertImage = function(sSrc)
  744. {
  745. if (!sSrc)
  746. {
  747. sSrc = prompt(oEditorStrings['prompt_text_img'], 'http://');
  748. if (!sSrc || sSrc.length < 10)
  749. return;
  750. }
  751. this.smf_execCommand('insertimage', false, sSrc);
  752. }
  753. smc_Editor.prototype.getSelect = function(bWantText, bWantHTMLText)
  754. {
  755. if (is_ie && 'selection' in this.oFrameDocument)
  756. {
  757. // Just want plain text?
  758. if (bWantText && !bWantHTMLText)
  759. return this.oFrameDocument.selection.createRange().text;
  760. // We want the HTML flavoured variety?
  761. else if (bWantHTMLText)
  762. return this.oFrameDocument.selection.createRange().htmlText;
  763. return this.oFrameDocument.selection;
  764. }
  765. // This is mainly Firefox.
  766. if ('getSelection' in this.oFrameWindow)
  767. {
  768. // Plain text?
  769. if (bWantText && !bWantHTMLText)
  770. return this.oFrameWindow.getSelection().toString();
  771. // HTML is harder - currently using: http://www.faqts.com/knowledge_base/view.phtml/aid/32427
  772. else if (bWantHTMLText)
  773. {
  774. var oSelection = this.oFrameWindow.getSelection();
  775. if (oSelection.rangeCount > 0)
  776. {
  777. var oRange = oSelection.getRangeAt(0);
  778. var oClonedSelection = oRange.cloneContents();
  779. var oDiv = this.oFrameDocument.createElement('div');
  780. oDiv.appendChild(oClonedSelection);
  781. return oDiv.innerHTML;
  782. }
  783. else
  784. return '';
  785. }
  786. // Want the whole object then.
  787. return this.oFrameWindow.getSelection();
  788. }
  789. // If we're here it's not good.
  790. return this.oFrameDocument.getSelection();
  791. }
  792. smc_Editor.prototype.getRange = function()
  793. {
  794. // Get the current selection.
  795. var oSelection = this.getSelect();
  796. if (!oSelection)
  797. return null;
  798. if (is_ie && oSelection.createRange)
  799. return oSelection.createRange();
  800. return oSelection.rangeCount == 0 ? null : oSelection.getRangeAt(0);
  801. }
  802. // Get the current element.
  803. smc_Editor.prototype.getCurElement = function()
  804. {
  805. var oRange = this.getRange();
  806. if (!oRange)
  807. return null;
  808. if (is_ie)
  809. {
  810. if (oRange.item)
  811. return oRange.item(0);
  812. else
  813. return oRange.parentElement();
  814. }
  815. else
  816. {
  817. var oElement = oRange.commonAncestorContainer;
  818. return this.getParentElement(oElement);
  819. }
  820. }
  821. smc_Editor.prototype.getParentElement = function(oNode)
  822. {
  823. if (oNode.nodeType == 1)
  824. return oNode;
  825. for (var i = 0; i < 50; i++)
  826. {
  827. if (!oNode.parentNode)
  828. break;
  829. oNode = oNode.parentNode;
  830. if (oNode.nodeType == 1)
  831. return oNode;
  832. }
  833. return null;
  834. }
  835. // Remove formatting for the selected text.
  836. smc_Editor.prototype.removeFormatting = function()
  837. {
  838. // Do both at once.
  839. if (this.bRichTextEnabled)
  840. {
  841. this.smf_execCommand('removeformat');
  842. this.smf_execCommand('unlink');
  843. }
  844. // Otherwise do a crude move indeed.
  845. else
  846. {
  847. // Get the current selection first.
  848. if (this.oTextHandle.caretPos)
  849. var sCurrentText = this.oTextHandle.caretPos.text;
  850. else if ('selectionStart' in this.oTextHandle)
  851. var sCurrentText = this.oTextHandle.value.substr(this.oTextHandle.selectionStart, (this.oTextHandle.selectionEnd - this.oTextHandle.selectionStart));
  852. else
  853. return;
  854. // Do bits that are likely to have attributes.
  855. sCurrentText = sCurrentText.replace(RegExp("\\[/?(url|img|iurl|ftp|email|img|color|font|size|list|bdo).*?\\]", "g"), '');
  856. // Then just anything that looks like BBC.
  857. sCurrentText = sCurrentText.replace(RegExp("\\[/?[A-Za-z]+\\]", "g"), '');
  858. replaceText(sCurrentText, this.oTextHandle);
  859. }
  860. }
  861. // Toggle wysiwyg/normal mode.
  862. smc_Editor.prototype.toggleView = function(bView)
  863. {
  864. if (!this.bRichTextPossible)
  865. {
  866. alert(oEditorStrings['wont_work']);
  867. return false;
  868. }
  869. // Overriding or alternating?
  870. if (typeof(bView) == 'undefined')
  871. bView = !this.bRichTextEnabled;
  872. this.requestParsedMessage(bView);
  873. return true;
  874. }
  875. // Request the message in a different form.
  876. smc_Editor.prototype.requestParsedMessage = function(bView)
  877. {
  878. // Replace with a force reload.
  879. if (!window.XMLHttpRequest)
  880. {
  881. alert(oEditorStrings['func_disabled']);
  882. return;
  883. }
  884. // Get the text.
  885. var sText = this.getText(true, !bView).replace(/&#/g, "&#38;#").php_to8bit().php_urlencode();
  886. this.tmpMethod = sendXMLDocument;
  887. this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=' + (bView ? 1 : 0) + ';' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, this.onToggleDataReceived);
  888. delete tmpMethod;
  889. }
  890. smc_Editor.prototype.onToggleDataReceived = function(oXMLDoc)
  891. {
  892. var sText = '';
  893. for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++)
  894. sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue;
  895. // What is this new view we have?
  896. this.bRichTextEnabled = oXMLDoc.getElementsByTagName('message')[0].getAttribute('view') != '0';
  897. if (this.bRichTextEnabled)
  898. {
  899. this.oFrameHandle.style.display = '';
  900. if (this.showDebug)
  901. this.oBreadHandle.style.display = '';
  902. this.oTextHandle.style.display = 'none';
  903. }
  904. else
  905. {
  906. sText = sText.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
  907. this.oFrameHandle.style.display = 'none';
  908. this.oBreadHandle.style.display = 'none';
  909. this.oTextHandle.style.display = '';
  910. }
  911. // First we focus.
  912. this.setFocus();
  913. this.insertText(sText, true);
  914. // Record the new status.
  915. document.getElementById(this.opt.sUniqueId + '_mode').value = this.bRichTextEnabled ? '1' : '0';
  916. // Rebuild the bread crumb!
  917. this.updateEditorControls();
  918. }
  919. // Set the focus for the editing window.
  920. smc_Editor.prototype.setFocus = function(force_both)
  921. {
  922. if (!this.bRichTextEnabled)
  923. this.oTextHandle.focus();
  924. else if (is_ff || is_opera)
  925. this.oFrameHandle.focus();
  926. else
  927. this.oFrameWindow.focus();
  928. }
  929. // Start up the spellchecker!
  930. smc_Editor.prototype.spellCheckStart = function()
  931. {
  932. if (!spellCheck)
  933. return false;
  934. // If we're in HTML mode we need to get the non-HTML text.
  935. if (this.bRichTextEnabled)
  936. {
  937. var sText = escape(this.getText(true, 1).php_to8bit());
  938. this.tmpMethod = sendXMLDocument;
  939. this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=0;' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, this.onSpellCheckDataReceived);
  940. delete tmpMethod;
  941. }
  942. // Otherwise start spellchecking right away.
  943. else
  944. spellCheck(this.sFormId, this.opt.sUniqueId);
  945. return true;
  946. }
  947. // This contains the spellcheckable text.
  948. smc_Editor.prototype.onSpellCheckDataReceived = function(oXMLDoc)
  949. {
  950. var sText = '';
  951. for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++)
  952. sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue;
  953. sText = sText.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
  954. this.oTextHandle.value = sText;
  955. spellCheck(this.sFormId, this.opt.sUniqueId);
  956. }
  957. // Function called when the Spellchecker is finished and ready to pass back.
  958. smc_Editor.prototype.spellCheckEnd = function()
  959. {
  960. // If HTML edit put the text back!
  961. if (this.bRichTextEnabled)
  962. {
  963. var sText = escape(this.getText(true, 0).php_to8bit());
  964. this.tmpMethod = sendXMLDocument;
  965. this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=1;' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, smf_editorArray[this.iArrayPosition].onSpellCheckCompleteDataReceived);
  966. delete tmpMethod;
  967. }
  968. else
  969. this.setFocus();
  970. }
  971. // The corrected text.
  972. smc_Editor.prototype.onSpellCheckCompleteDataReceived = function(oXMLDoc)
  973. {
  974. var sText = '';
  975. for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++)
  976. sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue;
  977. this.insertText(sText, true);
  978. this.setFocus();
  979. }
  980. smc_Editor.prototype.resizeTextArea = function(newHeight, newWidth, is_change)
  981. {
  982. // Work out what the new height is.
  983. if (is_change)
  984. {
  985. // We'll assume pixels but may not be.
  986. newHeight = this._calculateNewDimension(this.oTextHandle.style.height, newHeight);
  987. if (newWidth)
  988. newWidth = this._calculateNewDimension(this.oTextHandle.style.width, newWidth);
  989. }
  990. // Do the HTML editor - but only if it's enabled!
  991. if (this.bRichTextPossible)
  992. {
  993. this.oFrameHandle.style.height = newHeight;
  994. if (newWidth)
  995. this.oFrameHandle.style.width = newWidth;
  996. }
  997. // Do the text box regardless!
  998. this.oTextHandle.style.height = newHeight;
  999. if (newWidth)
  1000. this.oTextHandle.style.width = newWidth;
  1001. }
  1002. // A utility instruction to save repetition when trying to work out what to change on a height/width.
  1003. smc_Editor.prototype._calculateNewDimension = function(old_size, change_size)
  1004. {
  1005. // We'll assume pixels but may not be.
  1006. changeReg = change_size.toString().match(/(-)?(\d+)(\D*)/);
  1007. curReg = old_size.toString().match(/(\d+)(\D*)/);
  1008. if (!changeReg[3])
  1009. changeReg[3] = 'px';
  1010. if (changeReg[1] == '-')
  1011. changeReg[2] = 0 - changeReg[2];
  1012. // Both the same type?
  1013. if (changeReg[3] == curReg[2])
  1014. {
  1015. new_size = parseInt(changeReg[2]) + parseInt(curReg[1]);
  1016. if (new_size < 50)
  1017. new_size = 50;
  1018. new_size = new_size.toString() + changeReg[3];
  1019. }
  1020. // Is the change a percentage?
  1021. else if (changeReg[3] == '%')
  1022. new_size = (parseInt(curReg[1]) + parseInt((parseInt(changeReg[2]) * parseInt(curReg[1])) / 100)).toString() + 'px';
  1023. // Otherwise just guess!
  1024. else
  1025. new_size = (parseInt(curReg[1]) + (parseInt(changeReg[2]) / 10)).toString() + '%';
  1026. return new_size;
  1027. }
  1028. // Register default keyboard shortcuts.
  1029. smc_Editor.prototype.registerDefaultShortcuts = function()
  1030. {
  1031. if (is_ff)
  1032. {
  1033. this.registerShortcut('b', 'ctrl', 'b');
  1034. this.registerShortcut('u', 'ctrl', 'u');
  1035. this.registerShortcut('i', 'ctrl', 'i');
  1036. this.registerShortcut('p', 'alt', 'preview');
  1037. this.registerShortcut('s', 'alt', 'submit');
  1038. }
  1039. }
  1040. // Register a keyboard shortcut.
  1041. smc_Editor.prototype.registerShortcut = function(sLetter, sModifiers, sCodeName)
  1042. {
  1043. if (!sCodeName)
  1044. return;
  1045. var oNewShortcut = {
  1046. code : sCodeName,
  1047. key: sLetter.toUpperCase().charCodeAt(0),
  1048. alt : false,
  1049. ctrl : false
  1050. };
  1051. var aSplitModifiers = sModifiers.split(',');
  1052. for(var i = 0, n = aSplitModifiers.length; i < n; i++)
  1053. if (aSplitModifiers[i] in oNewShortcut)
  1054. oNewShortcut[aSplitModifiers[i]] = true;
  1055. this.aKeyboardShortcuts[this.aKeyboardShortcuts.length] = oNewShortcut;
  1056. }
  1057. // Check whether the key has triggered a shortcut?
  1058. smc_Editor.prototype.checkShortcut = function(oEvent)
  1059. {
  1060. // To be a shortcut it needs to be one of these, duh!
  1061. if (!oEvent.altKey && !oEvent.ctrlKey)
  1062. return false;
  1063. var sReturnCode = false;
  1064. // Let's take a look at each of our shortcuts shall we?
  1065. for (var i = 0, n = this.aKeyboardShortcuts.length; i < n; i++)
  1066. {
  1067. // Found something?
  1068. if (oEvent.altKey == this.aKeyboardShortcuts[i].alt && oEvent.ctrlKey == this.aKeyboardShortcuts[i].ctrl && oEvent.keyCode == this.aKeyboardShortcuts[i].key)
  1069. sReturnCode = this.aKeyboardShortcuts[i].code;
  1070. }
  1071. return sReturnCode;
  1072. }
  1073. // The actual event check for the above!
  1074. smc_Editor.prototype.shortcutCheck = function(oEvent)
  1075. {
  1076. var sFoundCode = this.checkShortcut(oEvent);
  1077. // Run it and exit.
  1078. if (typeof(sFoundCode) == 'string' && sFoundCode != '')
  1079. {
  1080. var bCancelEvent = false;
  1081. if (sFoundCode == 'submit')
  1082. {
  1083. // So much to do!
  1084. var oForm = document.getElementById(this.sFormId);
  1085. submitThisOnce(oForm);
  1086. submitonce(oForm);
  1087. smc_saveEntities(oForm.name, ['subject', this.opt.sUniqueId, 'guestname', 'evtitle', 'question']);
  1088. oForm.submit();
  1089. bCancelEvent = true;
  1090. }
  1091. else if (sFoundCode == 'preview')
  1092. {
  1093. previewPost();
  1094. bCancelEvent = true;
  1095. }
  1096. else
  1097. bCancelEvent = this.opt.oBBCBox.emulateClick(sFoundCode);
  1098. if (bCancelEvent)
  1099. {
  1100. if (is_ie && oEvent.cancelBubble)
  1101. oEvent.cancelBubble = true;
  1102. else if (oEvent.stopPropagation)
  1103. {
  1104. oEvent.stopPropagation();
  1105. oEvent.preventDefault();
  1106. }
  1107. return false;
  1108. }
  1109. }
  1110. return true;
  1111. }
  1112. // This is the method called after clicking the resize bar.
  1113. smc_Editor.prototype.startResize = function(oEvent)
  1114. {
  1115. if ('event' in window)
  1116. oEvent = window.event;
  1117. if (!oEvent || window.smf_oCurrentResizeEditor != null)
  1118. return true;
  1119. window.smf_oCurrentResizeEditor = this.iArrayPosition;
  1120. var aCurCoordinates = smf_mousePose(oEvent);
  1121. this.osmc_EditorCurrentResize.old_y = aCurCoordinates[1];
  1122. this.osmc_EditorCurrentResize.old_rel_y = null;
  1123. this.osmc_EditorCurrentResize.cur_height = parseInt(this.oTextHandle.style.height);
  1124. // Set the necessary events for resizing.
  1125. var oResizeEntity = is_ie ? document : window;
  1126. oResizeEntity.addEventListener('mousemove', this.aEventWrappers.resizeOverDocument, false);
  1127. if (this.bRichTextPossible)
  1128. this.oFrameDocument.addEventListener('mousemove', this.aEventWrappers.resizeOverIframe, false);
  1129. document.addEventListener('mouseup', this.aEventWrappers.endResize, true);
  1130. if (this.bRichTextPossible)
  1131. this.oFrameDocument.addEventListener('mouseup', this.aEventWrappers.endResize, true);
  1132. return false;
  1133. }
  1134. // This is kind of a cheat, as it only works over the IFRAME.
  1135. smc_Editor.prototype.resizeOverIframe = function(oEvent)
  1136. {
  1137. if ('event' in window)
  1138. oEvent = window.event;
  1139. if (!oEvent || window.smf_oCurrentResizeEditor == null)
  1140. return true;
  1141. var newCords = smf_mousePose(oEvent);
  1142. if (this.osmc_EditorCurrentResize.old_rel_y == null)
  1143. this.osmc_EditorCurrentResize.old_rel_y = newCords[1];
  1144. else
  1145. {
  1146. var iNewHeight = newCords[1] - this.osmc_EditorCurrentResize.old_rel_y + this.osmc_EditorCurrentResize.cur_height;
  1147. if (iNewHeight < 0)
  1148. this.endResize();
  1149. else
  1150. this.resizeTextArea(iNewHeight + 'px', 0, false);
  1151. }
  1152. return false;
  1153. }
  1154. // This resizes an editor.
  1155. smc_Editor.prototype.resizeOverDocument = function (oEvent)
  1156. {
  1157. if ('event' in window)
  1158. oEvent = window.event;
  1159. if (!oEvent || window.smf_oCurrentResizeEditor == null)
  1160. return true;
  1161. var newCords = smf_mousePose(oEvent);
  1162. var iNewHeight = newCords[1] - this.osmc_EditorCurrentResize.old_y + this.osmc_EditorCurrentResize.cur_height;
  1163. if (iNewHeight < 0)
  1164. this.endResize();
  1165. else
  1166. this.resizeTextArea(iNewHeight + 'px', 0, false);
  1167. return false;
  1168. }
  1169. smc_Editor.prototype.endResize = function (oEvent)
  1170. {
  1171. if ('event' in window)
  1172. oEvent = window.event;
  1173. if (window.smf_oCurrentResizeEditor == null)
  1174. return true;
  1175. window.smf_oCurrentResizeEditor = null;
  1176. // Remove the event...
  1177. var oResizeEntity = is_ie ? document : window;
  1178. oResizeEntity.removeEventListener('mousemove', this.aEventWrappers.resizeOverDocument, false);
  1179. if (this.bRichTextPossible)
  1180. this.oFrameDocument.removeEventListener('mousemove', this.aEventWrappers.resizeOverIframe, false);
  1181. document.removeEventListener('mouseup', this.aEventWrappers.endResize, true);
  1182. if (this.bRichTextPossible)
  1183. this.oFrameDocument.removeEventListener('mouseup', this.aEventWrappers.endResize, true);
  1184. return false;
  1185. }
  1186. // *** smc_SmileyBox class.
  1187. function smc_SmileyBox(oOptions)
  1188. {
  1189. this.opt = oOptions;
  1190. this.oSmileyRowsContent = {};
  1191. this.oSmileyPopupWindow = null;
  1192. this.init();
  1193. }
  1194. smc_SmileyBox.prototype.init = function ()
  1195. {
  1196. // Get the HTML content of the smileys visible on the post screen.
  1197. this.getSmileyRowsContent('postform');
  1198. // Inject the HTML.
  1199. setInnerHTML(document.getElementById(this.opt.sContainerDiv), this.opt.sSmileyBoxTemplate.easyReplace({
  1200. smileyRows: this.oSmileyRowsContent.postform,
  1201. moreSmileys: this.opt.oSmileyLocations.popup.length == 0 ? '' : this.opt.sMoreSmileysTemplate.easyReplace({
  1202. moreSmileysId: this.opt.sUniqueId + '_addMoreSmileys'
  1203. })
  1204. }));
  1205. // Initialize the smileys.
  1206. this.initSmileys('postform', document);
  1207. // Initialize the [more] button.
  1208. if (this.opt.oSmileyLocations.popup.length > 0)
  1209. {
  1210. var oMoreLink = document.getElementById(this.opt.sUniqueId + '_addMoreSmileys');
  1211. oMoreLink.instanceRef = this;
  1212. oMoreLink.onclick = function () {
  1213. this.instanceRef.handleShowMoreSmileys();
  1214. return false;
  1215. }
  1216. }
  1217. }
  1218. // Loop through the smileys to setup the HTML.
  1219. smc_SmileyBox.prototype.getSmileyRowsContent = function (sLocation)
  1220. {
  1221. // If it's already defined, don't bother.
  1222. if (sLocation in this.oSmileyRowsContent)
  1223. return;
  1224. this.oSmileyRowsContent[sLocation] = '';
  1225. for (var iSmileyRowIndex = 0, iSmileyRowCount = this.opt.oSmileyLocations[sLocation].length; iSmileyRowIndex < iSmileyRowCount; iSmileyRowIndex++)
  1226. {
  1227. var sSmileyRowContent = '';
  1228. for (var iSmileyIndex = 0, iSmileyCount = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex].length; iSmileyIndex < iSmileyCount; iSmileyIndex++)
  1229. sSmileyRowContent += this.opt.sSmileyTemplate.easyReplace({
  1230. smileySource: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sSrc.php_htmlspecialchars(),
  1231. smileyDescription: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sDescription.php_htmlspecialchars(),
  1232. smileyCode: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sCode.php_htmlspecialchars(),
  1233. smileyId: this.opt.sUniqueId + '_' + sLocation + '_' + iSmileyRowIndex.toString() + '_' + iSmileyIndex.toString()
  1234. });
  1235. this.oSmileyRowsContent[sLocation] += this.opt.sSmileyRowTemplate.easyReplace({
  1236. smileyRow: sSmileyRowContent
  1237. });
  1238. }
  1239. }
  1240. smc_SmileyBox.prototype.initSmileys = function (sLocation, oDocument)
  1241. {
  1242. for (var iSmileyRowIndex = 0, iSmileyRowCount = this.opt.oSmileyLocations[sLocation].length; iSmileyRowIndex < iSmileyRowCount; iSmileyRowIndex++)
  1243. {
  1244. for (var iSmileyIndex = 0, iSmileyCount = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex].length; iSmileyIndex < iSmileyCount; iSmileyIndex++)
  1245. {
  1246. var oSmiley = oDocument.getElementById(this.opt.sUniqueId + '_' + sLocation + '_' + iSmileyRowIndex.toString() + '_' + iSmileyIndex.toString());
  1247. oSmiley.instanceRef = this;
  1248. oSmiley.style.cursor = 'pointer';
  1249. oSmiley.onclick = function () {
  1250. this.instanceRef.clickHandler(this);
  1251. return false;
  1252. }
  1253. }
  1254. }
  1255. }
  1256. smc_SmileyBox.prototype.clickHandler = function (oSmileyImg)
  1257. {
  1258. // Dissect the id...
  1259. var aMatches = oSmileyImg.id.match(/([^_]+)_(\d+)_(\d+)$/);
  1260. if (aMatches.length != 4)
  1261. return false;
  1262. // ...to determine its exact smiley properties.
  1263. var sLocation = aMatches[1];
  1264. var iSmileyRowIndex = aMatches[2];
  1265. var iSmileyIndex = aMatches[3];
  1266. var oProperties = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex];
  1267. if ('sClickHandler' in this.opt)
  1268. eval(this.opt.sClickHandler + '(oProperties)');
  1269. return false;
  1270. }
  1271. smc_SmileyBox.prototype.handleShowMoreSmileys = function ()
  1272. {
  1273. // Focus the window if it's already opened.
  1274. if (this.oSmileyPopupWindow != null && 'closed' in this.oSmileyPopupWindow && !this.oSmileyPopupWindow.closed)
  1275. {
  1276. this.oSmileyPopupWindow.focus();
  1277. return;
  1278. }
  1279. // Get the smiley HTML.
  1280. this.getSmileyRowsContent('popup');
  1281. // Open the popup.
  1282. this.oSmileyPopupWindow = window.open('about:blank', this.opt.sUniqueId + '_addMoreSmileysPopup', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,width=480,height=220,resizable=yes');
  1283. // Paste the template in the popup.
  1284. this.oSmileyPopupWindow.document.open('text/html', 'replace');
  1285. this.oSmileyPopupWindow.document.write(this.opt.sMoreSmileysPopupTemplate.easyReplace({
  1286. smileyRows: this.oSmileyRowsContent.popup,
  1287. moreSmileysCloseLinkId: this.opt.sUniqueId + '_closeMoreSmileys'
  1288. }));
  1289. this.oSmileyPopupWindow.document.close();
  1290. // Initialize the smileys that are in the popup window.
  1291. this.initSmileys('popup', this.oSmileyPopupWindow.document);
  1292. // Add a function to the close window button.
  1293. var aCloseLink = this.oSmileyPopupWindow.document.getElementById(this.opt.sUniqueId + '_closeMoreSmileys');
  1294. aCloseLink.instanceRef = this;
  1295. aCloseLink.onclick = function () {
  1296. this.instanceRef.oSmileyPopupWindow.close();
  1297. return false;
  1298. }
  1299. }
  1300. // *** smc_BBCButtonBox class.
  1301. function smc_BBCButtonBox(oOptions)
  1302. {
  1303. this.opt = oOptions;
  1304. this.init();
  1305. }
  1306. smc_BBCButtonBox.prototype.init = function ()
  1307. {
  1308. var sBbcContent = '';
  1309. for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++)
  1310. {
  1311. var sRowContent = '';
  1312. var bPreviousWasDivider = false;
  1313. for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++)
  1314. {
  1315. var oCurButton = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1316. switch (oCurButton.sType)
  1317. {
  1318. case 'button':
  1319. if (oCurButton.bEnabled)
  1320. {
  1321. sRowContent += this.opt.sButtonTemplate.easyReplace({
  1322. buttonId: this.opt.sUniqueId.php_htmlspecialchars() + '_button_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString(),
  1323. buttonSrc: oCurButton.sImage.php_htmlspecialchars(),
  1324. buttonDescription: oCurButton.sDescription.php_htmlspecialchars()
  1325. });
  1326. bPreviousWasDivider = false;
  1327. }
  1328. break;
  1329. case 'divider':
  1330. if (!bPreviousWasDivider)
  1331. sRowContent += this.opt.sDividerTemplate;
  1332. bPreviousWasDivider = true;
  1333. break;
  1334. case 'select':
  1335. var sOptions = '';
  1336. // Fighting javascript's idea of order in a for loop... :P
  1337. if ('' in oCurButton.oOptions)
  1338. sOptions = '<option value="">' + oCurButton.oOptions[''].php_htmlspecialchars() + '</option>';
  1339. for (var sSelectValue in oCurButton.oOptions)
  1340. // we've been through this before
  1341. if (sSelectValue != '')
  1342. sOptions += '<option value="' + sSelectValue.php_htmlspecialchars() + '">' + oCurButton.oOptions[sSelectValue].php_htmlspecialchars() + '</option>';
  1343. sRowContent += this.opt.sSelectTemplate.easyReplace({
  1344. selectName: oCurButton.sName,
  1345. selectId: this.opt.sUniqueId.php_htmlspecialchars() + '_select_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString(),
  1346. selectOptions: sOptions
  1347. });
  1348. bPreviousWasDivider = false;
  1349. break;
  1350. }
  1351. }
  1352. sBbcContent += this.opt.sButtonRowTemplate.easyReplace({
  1353. buttonRow: sRowContent
  1354. });
  1355. }
  1356. var oBbcContainer = document.getElementById(this.opt.sContainerDiv);
  1357. setInnerHTML(oBbcContainer, sBbcContent);
  1358. for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++)
  1359. {
  1360. for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++)
  1361. {
  1362. var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1363. switch (oCurControl.sType)
  1364. {
  1365. case 'button':
  1366. if (!oCurControl.bEnabled)
  1367. break;
  1368. oCurControl.oImg = document.getElementById(this.opt.sUniqueId.php_htmlspecialchars() + '_button_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString());
  1369. oCurControl.oImg.style.cursor = 'pointer';
  1370. if ('sButtonBackgroundImage' in this.opt)
  1371. oCurControl.oImg.style.backgroundImage = 'url(' + this.opt.sButtonBackgroundImage + ')';
  1372. oCurControl.oImg.instanceRef = this;
  1373. oCurControl.oImg.onmouseover = function () {
  1374. this.instanceRef.handleButtonMouseOver(this);
  1375. };
  1376. oCurControl.oImg.onmouseout = function () {
  1377. this.instanceRef.handleButtonMouseOut(this);
  1378. };
  1379. oCurControl.oImg.onclick = function () {
  1380. this.instanceRef.handleButtonClick(this);
  1381. };
  1382. oCurControl.oImg.bIsActive = false;
  1383. oCurControl.oImg.bHover = false;
  1384. break;
  1385. case 'select':
  1386. oCurControl.oSelect = document.getElementById(this.opt.sUniqueId.php_htmlspecialchars() + '_select_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString());
  1387. oCurControl.oSelect.instanceRef = this;
  1388. oCurControl.oSelect.onchange = oCurControl.onchange = function () {
  1389. this.instanceRef.handleSelectChange(this);
  1390. }
  1391. break;
  1392. }
  1393. }
  1394. }
  1395. }
  1396. smc_BBCButtonBox.prototype.handleButtonMouseOver = function (oButtonImg)
  1397. {
  1398. oButtonImg.bHover = true;
  1399. this.updateButtonStatus(oButtonImg);
  1400. }
  1401. smc_BBCButtonBox.prototype.handleButtonMouseOut = function (oButtonImg)
  1402. {
  1403. oButtonImg.bHover = false;
  1404. this.updateButtonStatus(oButtonImg);
  1405. }
  1406. smc_BBCButtonBox.prototype.updateButtonStatus = function (oButtonImg)
  1407. {
  1408. var sNewURL = '';
  1409. if (oButtonImg.bHover && oButtonImg.bIsActive && 'sActiveButtonBackgroundImageHover' in this.opt)
  1410. sNewURL = 'url(' + this.opt.sActiveButtonBackgroundImageHover + ')';
  1411. else if (!oButtonImg.bHover && oButtonImg.bIsActive && 'sActiveButtonBackgroundImage' in this.opt)
  1412. sNewURL = 'url(' + this.opt.sActiveButtonBackgroundImage + ')';
  1413. else if (oButtonImg.bHover && 'sButtonBackgroundImageHover' in this.opt)
  1414. sNewURL = 'url(' + this.opt.sButtonBackgroundImageHover + ')';
  1415. else if ('sButtonBackgroundImage' in this.opt)
  1416. sNewURL = 'url(' + this.opt.sButtonBackgroundImage + ')';
  1417. if (oButtonImg.style.backgroundImage != sNewURL)
  1418. oButtonImg.style.backgroundImage = sNewURL;
  1419. }
  1420. smc_BBCButtonBox.prototype.handleButtonClick = function (oButtonImg)
  1421. {
  1422. // Dissect the id attribute...
  1423. var aMatches = oButtonImg.id.match(/(\d+)_(\d+)$/);
  1424. if (aMatches.length != 3)
  1425. return false;
  1426. // ...so that we can point to the exact button.
  1427. var iButtonRowIndex = aMatches[1];
  1428. var iButtonIndex = aMatches[2];
  1429. var oProperties = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1430. oProperties.bIsActive = oButtonImg.bIsActive;
  1431. if ('sButtonClickHandler' in this.opt)
  1432. eval(this.opt.sButtonClickHandler + '(oProperties)');
  1433. return false;
  1434. }
  1435. smc_BBCButtonBox.prototype.handleSelectChange = function (oSelectControl)
  1436. {
  1437. // Dissect the id attribute...
  1438. var aMatches = oSelectControl.id.match(/(\d+)_(\d+)$/);
  1439. if (aMatches.length != 3)
  1440. return false;
  1441. // ...so that we can point to the exact button.
  1442. var iButtonRowIndex = aMatches[1];
  1443. var iButtonIndex = aMatches[2];
  1444. var oProperties = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1445. if ('sSelectChangeHandler' in this.opt)
  1446. eval(this.opt.sSelectChangeHandler + '(oProperties)');
  1447. return true;
  1448. }
  1449. smc_BBCButtonBox.prototype.setActive = function (aButtons)
  1450. {
  1451. for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++)
  1452. {
  1453. for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++)
  1454. {
  1455. var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1456. if (oCurControl.sType == 'button' && oCurControl.bEnabled)
  1457. {
  1458. oCurControl.oImg.bIsActive = in_array(oCurControl.sCode, aButtons);
  1459. this.updateButtonStatus(oCurControl.oImg);
  1460. }
  1461. }
  1462. }
  1463. }
  1464. smc_BBCButtonBox.prototype.emulateClick = function (sCode)
  1465. {
  1466. for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++)
  1467. {
  1468. for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++)
  1469. {
  1470. var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1471. if (oCurControl.sType == 'button' && oCurControl.sCode == sCode)
  1472. {
  1473. eval(this.opt.sButtonClickHandler + '(oCurControl)');
  1474. return true;
  1475. }
  1476. }
  1477. }
  1478. return false;
  1479. }
  1480. smc_BBCButtonBox.prototype.setSelect = function (sSelectName, sValue)
  1481. {
  1482. if (!('sButtonClickHandler' in this.opt))
  1483. return;
  1484. for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++)
  1485. {
  1486. for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++)
  1487. {
  1488. var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex];
  1489. if (oCurControl.sType == 'select' && oCurControl.sName == sSelectName)
  1490. oCurControl.oSelect.value = sValue;
  1491. }
  1492. }
  1493. }