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