Chris@76: // *** smc_Editor class. Chris@76: function smc_Editor(oOptions) Chris@76: { Chris@76: this.opt = oOptions; Chris@76: Chris@76: // Create some links to the editor object. Chris@76: this.oTextHandle = null; Chris@76: this.sCurrentText = 'sText' in this.opt ? this.opt.sText : ''; Chris@76: Chris@76: // How big? Chris@76: this.sEditWidth = 'sEditWidth' in this.opt ? this.opt.sEditWidth : '70%'; Chris@76: this.sEditHeight = 'sEditHeight' in this.opt ? this.opt.sEditHeight : '150px'; Chris@76: Chris@76: this.showDebug = false; Chris@76: this.bRichTextEnabled = 'bWysiwyg' in this.opt && this.opt.bWysiwyg; Chris@76: // This doesn't work on Opera as they cannot restore focus after clicking a BBC button. Chris@76: this.bRichTextPossible = !this.opt.bRichEditOff && ((is_ie5up && !is_ie50) || is_ff || is_opera95up || is_safari || is_chrome) && !(is_iphone || is_android); Chris@76: Chris@76: this.oFrameHandle = null; Chris@76: this.oFrameDocument = null; Chris@76: this.oFrameWindow = null; Chris@76: Chris@76: // These hold the breadcrumb. Chris@76: this.oBreadHandle = null; Chris@76: this.oResizerElement = null; Chris@76: Chris@76: // Kinda holds all the useful stuff. Chris@76: this.aKeyboardShortcuts = new Array(); Chris@76: Chris@76: // This tracks the cursor position on IE to avoid refocus problems. Chris@76: this.cursorX = 0; Chris@76: this.cursorY = 0; Chris@76: Chris@76: // This is all the elements that can have a simple execCommand. Chris@76: this.oSimpleExec = { Chris@76: b: 'bold', Chris@76: u: 'underline', Chris@76: i: 'italic', Chris@76: s: 'strikethrough', Chris@76: left: 'justifyleft', Chris@76: center: 'justifycenter', Chris@76: right: 'justifyright', Chris@76: hr: 'inserthorizontalrule', Chris@76: list: 'insertunorderedlist', Chris@76: orderlist: 'insertorderedlist', Chris@76: sub: 'subscript', Chris@76: sup: 'superscript', Chris@76: indent: 'indent', Chris@76: outdent: 'outdent' Chris@76: } Chris@76: Chris@76: // Codes to call a private function Chris@76: this.oSmfExec = { Chris@76: unformat: 'removeFormatting', Chris@76: toggle: 'toggleView' Chris@76: } Chris@76: Chris@76: // Any special breadcrumb mappings to ensure we show a consistant tag name. Chris@76: this.breadCrumbNameTags = { Chris@76: strike: 's', Chris@76: strong: 'b', Chris@76: em: 'i' Chris@76: } Chris@76: Chris@76: this.aBreadCrumbNameStyles = [ Chris@76: { Chris@76: sStyleType: 'text-decoration', Chris@76: sStyleValue: 'underline', Chris@76: sBbcTag: 'u' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'text-decoration', Chris@76: sStyleValue: 'line-through', Chris@76: sBbcTag: 's' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'text-align', Chris@76: sStyleValue: 'left', Chris@76: sBbcTag: 'left' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'text-align', Chris@76: sStyleValue: 'center', Chris@76: sBbcTag: 'center' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'text-align', Chris@76: sStyleValue: 'right', Chris@76: sBbcTag: 'right' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'font-weight', Chris@76: sStyleValue: 'bold', Chris@76: sBbcTag: 'b' Chris@76: }, Chris@76: { Chris@76: sStyleType: 'font-style', Chris@76: sStyleValue: 'italic', Chris@76: sBbcTag: 'i' Chris@76: } Chris@76: ]; Chris@76: Chris@76: // All the fonts in the world. Chris@76: this.aFontFaces = [ Chris@76: 'Arial', Chris@76: 'Arial Black', Chris@76: 'Impact', Chris@76: 'Verdana', Chris@76: 'Times New Roman', Chris@76: 'Georgia', Chris@76: 'Andale Mono', Chris@76: 'Trebuchet MS', Chris@76: 'Comic Sans MS' Chris@76: ]; Chris@76: // Font maps (HTML => CSS size) Chris@76: this.aFontSizes = [ Chris@76: 0, Chris@76: 8, Chris@76: 10, Chris@76: 12, Chris@76: 14, Chris@76: 18, Chris@76: 24, Chris@76: 36 Chris@76: ]; Chris@76: // Color maps! (hex => name) Chris@76: this.oFontColors = { Chris@76: black: '#000000', Chris@76: red: '#ff0000', Chris@76: yellow: '#ffff00', Chris@76: pink: '#ffc0cb', Chris@76: green: '#008000', Chris@76: orange: '#ffa500', Chris@76: purple: '#800080', Chris@76: blue: '#0000ff', Chris@76: beige: '#f5f5dc', Chris@76: brown: '#a52a2a', Chris@76: teal: '#008080', Chris@76: navy: '#000080', Chris@76: maroon: '#800000', Chris@76: limegreen: '#32cd32' Chris@76: } Chris@76: Chris@76: this.sFormId = 'sFormId' in this.opt ? this.opt.sFormId : 'postmodify'; Chris@76: this.iArrayPosition = smf_editorArray.length; Chris@76: Chris@76: // Current resize state. Chris@76: this.osmc_EditorCurrentResize = {}; Chris@76: Chris@76: this.init(); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.init = function() Chris@76: { Chris@76: // Define the event wrapper functions. Chris@76: var oCaller = this; Chris@76: this.aEventWrappers = { Chris@76: editorKeyUp: function(oEvent) {return oCaller.editorKeyUp(oEvent);}, Chris@76: shortcutCheck: function(oEvent) {return oCaller.shortcutCheck(oEvent);}, Chris@76: editorBlur: function(oEvent) {return oCaller.editorBlur(oEvent);}, Chris@76: editorFocus: function(oEvent) {return oCaller.editorFocus(oEvent);}, Chris@76: startResize: function(oEvent) {return oCaller.startResize(oEvent);}, Chris@76: resizeOverDocument: function(oEvent) {return oCaller.resizeOverDocument(oEvent);}, Chris@76: endResize: function(oEvent) {return oCaller.endResize(oEvent);}, Chris@76: resizeOverIframe: function(oEvent) {return oCaller.resizeOverIframe(oEvent);} Chris@76: }; Chris@76: Chris@76: // Set the textHandle. Chris@76: this.oTextHandle = document.getElementById(this.opt.sUniqueId); Chris@76: Chris@76: // Ensure the currentText is set correctly depending on the mode. Chris@76: if (this.sCurrentText == '' && !this.bRichTextEnabled) Chris@76: this.sCurrentText = getInnerHTML(this.oTextHandle).php_unhtmlspecialchars(); Chris@76: Chris@76: // Only try to do this if rich text is supported. Chris@76: if (this.bRichTextPossible) Chris@76: { Chris@76: // Make the iframe itself, stick it next to the current text area, and give it an ID. Chris@76: this.oFrameHandle = document.createElement('iframe'); Chris@76: this.oFrameHandle.src = 'about:blank'; Chris@76: this.oFrameHandle.id = 'html_' + this.opt.sUniqueId; Chris@76: this.oFrameHandle.className = 'rich_editor_frame'; Chris@76: this.oFrameHandle.style.display = 'none'; Chris@76: this.oFrameHandle.style.margin = '0px'; Chris@76: this.oFrameHandle.tabIndex = this.oTextHandle.tabIndex; Chris@76: this.oTextHandle.parentNode.appendChild(this.oFrameHandle); Chris@76: Chris@76: // Create some handy shortcuts. Chris@76: this.oFrameDocument = this.oFrameHandle.contentDocument ? this.oFrameHandle.contentDocument : ('contentWindow' in this.oFrameHandle ? this.oFrameHandle.contentWindow.document : this.oFrameHandle.document); Chris@76: this.oFrameWindow = 'contentWindow' in this.oFrameHandle ? this.oFrameHandle.contentWindow : this.oFrameHandle.document.parentWindow; Chris@76: Chris@76: // Create the debug window... and stick this under the main frame - make it invisible by default. Chris@76: this.oBreadHandle = document.createElement('div'); Chris@76: this.oBreadHandle.id = 'bread_' . uid; Chris@76: this.oBreadHandle.style.visibility = 'visible'; Chris@76: this.oBreadHandle.style.display = 'none'; Chris@76: this.oFrameHandle.parentNode.appendChild(this.oBreadHandle); Chris@76: Chris@76: // Size the iframe dimensions to something sensible. Chris@76: this.oFrameHandle.style.width = this.sEditWidth; Chris@76: this.oFrameHandle.style.height = this.sEditHeight; Chris@76: this.oFrameHandle.style.visibility = 'visible'; Chris@76: Chris@76: // Only bother formatting the debug window if debug is enabled. Chris@76: if (this.showDebug) Chris@76: { Chris@76: this.oBreadHandle.style.width = this.sEditWidth; Chris@76: this.oBreadHandle.style.height = '20px'; Chris@76: this.oBreadHandle.className = 'windowbg2'; Chris@76: this.oBreadHandle.style.border = '1px black solid'; Chris@76: this.oBreadHandle.style.display = ''; Chris@76: } Chris@76: Chris@76: // Populate the editor with nothing by default. Chris@76: if (!is_opera95up) Chris@76: { Chris@76: this.oFrameDocument.open(); Chris@76: this.oFrameDocument.write(''); Chris@76: this.oFrameDocument.close(); Chris@76: } Chris@76: Chris@76: // Right to left mode? Chris@76: if (this.opt.bRTL) Chris@76: { Chris@76: this.oFrameDocument.dir = "rtl"; Chris@76: this.oFrameDocument.body.dir = "rtl"; Chris@76: } Chris@76: Chris@76: // Mark it as editable... Chris@76: if (this.oFrameDocument.body.contentEditable) Chris@76: this.oFrameDocument.body.contentEditable = true; Chris@76: else Chris@76: { Chris@76: this.oFrameHandle.style.display = ''; Chris@76: this.oFrameDocument.designMode = 'on'; Chris@76: this.oFrameHandle.style.display = 'none'; Chris@76: } Chris@76: Chris@76: // Now we need to try and style the editor - internet explorer allows us to do the whole lot. Chris@76: if (document.styleSheets['editor_css'] || document.styleSheets['editor_ie_css']) Chris@76: { Chris@76: var oMyStyle = this.oFrameDocument.createElement('style'); Chris@76: this.oFrameDocument.documentElement.firstChild.appendChild(oMyStyle); Chris@76: oMyStyle.styleSheet.cssText = document.styleSheets['editor_ie_css'] ? document.styleSheets['editor_ie_css'].cssText : document.styleSheets['editor_css'].cssText; Chris@76: } Chris@76: // Otherwise we seem to have to try to rip out each of the styles one by one! Chris@76: else if (document.styleSheets.length) Chris@76: { Chris@76: var bFoundSomething = false; Chris@76: // First we need to find the right style sheet. Chris@76: for (var i = 0, iNumStyleSheets = document.styleSheets.length; i < iNumStyleSheets; i++) Chris@76: { Chris@76: // Start off looking for the right style sheet. Chris@76: if (!document.styleSheets[i].href || document.styleSheets[i].href.indexOf('editor') < 1) Chris@76: continue; Chris@76: Chris@76: // Firefox won't allow us to get a CSS file which ain't in the right URL. Chris@76: try Chris@76: { Chris@76: if (document.styleSheets[i].cssRules.length < 1) Chris@76: continue; Chris@76: } Chris@76: catch (e) Chris@76: { Chris@76: continue; Chris@76: } Chris@76: Chris@76: // Manually try to find the rich_editor class. Chris@76: for (var r = 0, iNumRules = document.styleSheets[i].cssRules.length; r < iNumRules; r++) Chris@76: { Chris@76: // Got the main editor? Chris@76: if (document.styleSheets[i].cssRules[r].selectorText == '.rich_editor') Chris@76: { Chris@76: // Set some possible styles. Chris@76: if (document.styleSheets[i].cssRules[r].style.color) Chris@76: this.oFrameDocument.body.style.color = document.styleSheets[i].cssRules[r].style.color; Chris@76: if (document.styleSheets[i].cssRules[r].style.backgroundColor) Chris@76: this.oFrameDocument.body.style.backgroundColor = document.styleSheets[i].cssRules[r].style.backgroundColor; Chris@76: if (document.styleSheets[i].cssRules[r].style.fontSize) Chris@76: this.oFrameDocument.body.style.fontSize = document.styleSheets[i].cssRules[r].style.fontSize; Chris@76: if (document.styleSheets[i].cssRules[r].style.fontFamily) Chris@76: this.oFrameDocument.body.style.fontFamily = document.styleSheets[i].cssRules[r].style.fontFamily; Chris@76: if (document.styleSheets[i].cssRules[r].style.border) Chris@76: this.oFrameDocument.body.style.border = document.styleSheets[i].cssRules[r].style.border; Chris@76: bFoundSomething = true; Chris@76: } Chris@76: // The frame? Chris@76: else if (document.styleSheets[i].cssRules[r].selectorText == '.rich_editor_frame') Chris@76: { Chris@76: if (document.styleSheets[i].cssRules[r].style.border) Chris@76: this.oFrameHandle.style.border = document.styleSheets[i].cssRules[r].style.border; Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // Didn't find it? Chris@76: if (!bFoundSomething) Chris@76: { Chris@76: // Do something that is better than nothing. Chris@76: this.oFrameDocument.body.style.color = 'black'; Chris@76: this.oFrameDocument.body.style.backgroundColor = 'white'; Chris@76: this.oFrameDocument.body.style.fontSize = '78%'; Chris@76: this.oFrameDocument.body.style.fontFamily = '"Verdana", "Arial", "Helvetica", "sans-serif"'; Chris@76: this.oFrameDocument.body.style.border = 'none'; Chris@76: this.oFrameHandle.style.border = '1px solid #808080'; Chris@76: if (is_opera) Chris@76: this.oFrameDocument.body.style.height = '99%'; Chris@76: } Chris@76: } Chris@76: Chris@76: // Apply the class... Chris@76: this.oFrameDocument.body.className = 'rich_editor'; Chris@76: Chris@76: // Set the frame padding/margin inside the editor. Chris@76: this.oFrameDocument.body.style.padding = '1px'; Chris@76: this.oFrameDocument.body.style.margin = '0'; Chris@76: Chris@76: // Listen for input. Chris@76: this.oFrameDocument.instanceRef = this; Chris@76: this.oFrameHandle.instanceRef = this; Chris@76: this.oTextHandle.instanceRef = this; Chris@76: Chris@76: // Attach addEventListener for those browsers that don't support it. Chris@76: createEventListener(this.oFrameHandle); Chris@76: createEventListener(this.oFrameDocument); Chris@76: createEventListener(this.oTextHandle); Chris@76: createEventListener(window); Chris@76: createEventListener(document); Chris@76: Chris@76: // Attach functions to the key and mouse events. Chris@76: this.oFrameDocument.addEventListener('keyup', this.aEventWrappers.editorKeyUp, true); Chris@76: this.oFrameDocument.addEventListener('mouseup', this.aEventWrappers.editorKeyUp, true); Chris@76: this.oFrameDocument.addEventListener('keydown', this.aEventWrappers.shortcutCheck, true); Chris@76: this.oTextHandle.addEventListener('keydown', this.aEventWrappers.shortcutCheck, true); Chris@76: Chris@76: if (is_ie) Chris@76: { Chris@76: this.oFrameDocument.addEventListener('blur', this.aEventWrappers.editorBlur, true); Chris@76: this.oFrameDocument.addEventListener('focus', this.aEventWrappers.editorFocus, true); Chris@76: } Chris@76: Chris@76: // Show the iframe only if wysiwyrg is on - and hide the text area. Chris@76: this.oTextHandle.style.display = this.bRichTextEnabled ? 'none' : ''; Chris@76: this.oFrameHandle.style.display = this.bRichTextEnabled ? '' : 'none'; Chris@76: this.oBreadHandle.style.display = this.bRichTextEnabled ? '' : 'none'; Chris@76: } Chris@76: // If we can't do advanced stuff then just do the basics. Chris@76: else Chris@76: { Chris@76: // Cannot have WYSIWYG anyway! Chris@76: this.bRichTextEnabled = false; Chris@76: Chris@76: // We need some of the event handlers. Chris@76: createEventListener(this.oTextHandle); Chris@76: createEventListener(window); Chris@76: createEventListener(document); Chris@76: } Chris@76: Chris@76: // Make sure we set the message mode correctly. Chris@76: document.getElementById(this.opt.sUniqueId + '_mode').value = this.bRichTextEnabled ? 1 : 0; Chris@76: Chris@76: // Show the resizer. Chris@76: if (document.getElementById(this.opt.sUniqueId + '_resizer') && (!is_opera || is_opera95up) && !(is_chrome && !this.bRichTextEnabled)) Chris@76: { Chris@76: // Currently nothing is being resized...I assume! Chris@76: window.smf_oCurrentResizeEditor = null; Chris@76: Chris@76: this.oResizerElement = document.getElementById(this.opt.sUniqueId + '_resizer'); Chris@76: this.oResizerElement.style.display = ''; Chris@76: Chris@76: createEventListener(this.oResizerElement); Chris@76: this.oResizerElement.addEventListener('mousedown', this.aEventWrappers.startResize, false); Chris@76: } Chris@76: Chris@76: // Set the text - if WYSIWYG is enabled that is. Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: this.insertText(this.sCurrentText, true); Chris@76: Chris@76: // Better make us the focus! Chris@76: this.setFocus(); Chris@76: } Chris@76: Chris@76: // Finally, register shortcuts. Chris@76: this.registerDefaultShortcuts(); Chris@76: this.updateEditorControls(); Chris@76: } Chris@76: Chris@76: // Return the current text. Chris@76: smc_Editor.prototype.getText = function(bPrepareEntities, bModeOverride) Chris@76: { Chris@76: var bCurMode = typeof(bModeOverride) != 'undefined' ? bModeOverride : this.bRichTextEnabled; Chris@76: Chris@76: if (!bCurMode || this.oFrameDocument == null) Chris@76: { Chris@76: var sText = this.oTextHandle.value; Chris@76: if (bPrepareEntities) Chris@76: sText = sText.replace(//g, '#smgt#').replace(/&/g, '#smamp#'); Chris@76: } Chris@76: else Chris@76: { Chris@76: var sText = this.oFrameDocument.body.innerHTML; Chris@76: if (bPrepareEntities) Chris@76: sText = sText.replace(/</g, '#smlt#').replace(/>/g, '#smgt#').replace(/&/g, '#smamp#'); Chris@76: } Chris@76: Chris@76: // Clean it up - including removing semi-colons. Chris@76: if (bPrepareEntities) Chris@76: sText = sText.replace(/ /g, ' ').replace(/;/g, '#smcol#'); Chris@76: Chris@76: // Return it. Chris@76: return sText; Chris@76: } Chris@76: Chris@76: // Return the current text. Chris@76: smc_Editor.prototype.unprotectText = function(sText) Chris@76: { Chris@76: var bCurMode = typeof(bModeOverride) != 'undefined' ? bModeOverride : this.bRichTextEnabled; Chris@76: Chris@76: // This restores smlt, smgt and smamp into boring entities, to unprotect against XML'd information like quotes. Chris@76: sText = sText.replace(/#smlt#/g, '<').replace(/#smgt#/g, '>').replace(/#smamp#/g, '&'); Chris@76: Chris@76: // Return it. Chris@76: return sText; Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.editorKeyUp = function() Chris@76: { Chris@76: // Rebuild the breadcrumb. Chris@76: this.updateEditorControls(); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.editorBlur = function() Chris@76: { Chris@76: if (!is_ie) Chris@76: return; Chris@76: Chris@76: // Need to do something here. Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.editorFocus = function() Chris@76: { Chris@76: if (!is_ie) Chris@76: return; Chris@76: Chris@76: // Need to do something here. Chris@76: } Chris@76: Chris@76: // Rebuild the breadcrumb etc - and set things to the correct context. Chris@76: smc_Editor.prototype.updateEditorControls = function() Chris@76: { Chris@76: // Everything else is specific to HTML mode. Chris@76: if (!this.bRichTextEnabled) Chris@76: { Chris@76: // Set none of the buttons active. Chris@76: if (this.opt.oBBCBox) Chris@76: this.opt.oBBCBox.setActive([]); Chris@76: return; Chris@76: } Chris@76: Chris@76: var aCrumb = new Array(); Chris@76: var aAllCrumbs = new Array(); Chris@76: var iMaxLength = 6; Chris@76: Chris@76: // What is the current element? Chris@76: var oCurTag = this.getCurElement(); Chris@76: Chris@76: var i = 0; Chris@76: while (typeof(oCurTag) == 'object' && oCurTag != null && oCurTag.nodeName.toLowerCase() != 'body' && i < iMaxLength) Chris@76: { Chris@76: aCrumb[i++] = oCurTag; Chris@76: oCurTag = oCurTag.parentNode; Chris@76: } Chris@76: Chris@76: // Now print out the tree. Chris@76: var sTree = ''; Chris@76: var sCurFontName = ''; Chris@76: var sCurFontSize = ''; Chris@76: var sCurFontColor = ''; Chris@76: for (var i = 0, iNumCrumbs = aCrumb.length; i < iNumCrumbs; i++) Chris@76: { Chris@76: var sCrumbName = aCrumb[i].nodeName.toLowerCase(); Chris@76: Chris@76: // Does it have an alternative name? Chris@76: if (sCrumbName in this.breadCrumbNameTags) Chris@76: sCrumbName = this.breadCrumbNameTags[sCrumbName]; Chris@76: // Don't bother with this... Chris@76: else if (sCrumbName == 'p') Chris@76: continue; Chris@76: // A link? Chris@76: else if (sCrumbName == 'a') Chris@76: { Chris@76: var sUrlInfo = aCrumb[i].getAttribute('href'); Chris@76: sCrumbName = 'url'; Chris@76: if (typeof(sUrlInfo) == 'string') Chris@76: { Chris@76: if (sUrlInfo.substr(0, 3) == 'ftp') Chris@76: sCrumbName = 'ftp'; Chris@76: else if (sUrlInfo.substr(0, 6) == 'mailto') Chris@76: sCrumbName = 'email'; Chris@76: } Chris@76: } Chris@76: else if (sCrumbName == 'span' || sCrumbName == 'div') Chris@76: { Chris@76: if (aCrumb[i].style) Chris@76: { Chris@76: for (var j = 0, iNumStyles = this.aBreadCrumbNameStyles.length; j < iNumStyles; j++) Chris@76: { Chris@76: // Do we have a font? Chris@76: if (aCrumb[i].style.fontFamily && aCrumb[i].style.fontFamily != '' && sCurFontName == '') Chris@76: { Chris@76: sCurFontName = aCrumb[i].style.fontFamily; Chris@76: sCrumbName = 'face'; Chris@76: } Chris@76: // ... or a font size? Chris@76: if (aCrumb[i].style.fontSize && aCrumb[i].style.fontSize != '' && sCurFontSize == '') Chris@76: { Chris@76: sCurFontSize = aCrumb[i].style.fontSize; Chris@76: sCrumbName = 'size'; Chris@76: } Chris@76: // ... even color? Chris@76: if (aCrumb[i].style.color && aCrumb[i].style.color != '' && sCurFontColor == '') Chris@76: { Chris@76: sCurFontColor = aCrumb[i].style.color; Chris@76: if (in_array(sCurFontColor, this.oFontColors)) Chris@76: sCurFontColor = array_search(sCurFontColor, this.oFontColors); Chris@76: sCrumbName = 'color'; Chris@76: } Chris@76: Chris@76: if (this.aBreadCrumbNameStyles[j].sStyleType == 'text-align' && aCrumb[i].style.textAlign && aCrumb[i].style.textAlign == this.aBreadCrumbNameStyles[j].sStyleValue) Chris@76: sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag; Chris@76: else if (this.aBreadCrumbNameStyles[j].sStyleType == 'text-decoration' && aCrumb[i].style.textDecoration && aCrumb[i].style.textDecoration == this.aBreadCrumbNameStyles[j].sStyleValue) Chris@76: sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag; Chris@76: else if (this.aBreadCrumbNameStyles[j].sStyleType == 'font-weight' && aCrumb[i].style.fontWeight && aCrumb[i].style.fontWeight == this.aBreadCrumbNameStyles[j].sStyleValue) Chris@76: sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag; Chris@76: else if (this.aBreadCrumbNameStyles[j].sStyleType == 'font-style' && aCrumb[i].style.fontStyle && aCrumb[i].style.fontStyle == this.aBreadCrumbNameStyles[j].sStyleValue) Chris@76: sCrumbName = this.aBreadCrumbNameStyles[j].sBbcTag; Chris@76: } Chris@76: } Chris@76: } Chris@76: // Do we have a font? Chris@76: else if (sCrumbName == 'font') Chris@76: { Chris@76: if (aCrumb[i].getAttribute('face') && sCurFontName == '') Chris@76: { Chris@76: sCurFontName = aCrumb[i].getAttribute('face').toLowerCase(); Chris@76: sCrumbName = 'face'; Chris@76: } Chris@76: if (aCrumb[i].getAttribute('size') && sCurFontSize == '') Chris@76: { Chris@76: sCurFontSize = aCrumb[i].getAttribute('size'); Chris@76: sCrumbName = 'size'; Chris@76: } Chris@76: if (aCrumb[i].getAttribute('color') && sCurFontColor == '') Chris@76: { Chris@76: sCurFontColor = aCrumb[i].getAttribute('color'); Chris@76: if (in_array(sCurFontColor, this.oFontColors)) Chris@76: sCurFontColor = array_search(sCurFontColor, this.oFontColors); Chris@76: sCrumbName = 'color'; Chris@76: } Chris@76: // Something else - ignore. Chris@76: if (sCrumbName == 'font') Chris@76: continue; Chris@76: } Chris@76: Chris@76: sTree += (i != 0 ? ' >' : '') + ' ' + sCrumbName; Chris@76: aAllCrumbs[aAllCrumbs.length] = sCrumbName; Chris@76: } Chris@76: Chris@76: // Since we're in WYSIWYG state, show the toggle button as active. Chris@76: aAllCrumbs[aAllCrumbs.length] = 'toggle'; Chris@76: Chris@76: this.opt.oBBCBox.setActive(aAllCrumbs); Chris@76: Chris@76: // Try set the font boxes correct. Chris@76: this.opt.oBBCBox.setSelect('sel_face', sCurFontName); Chris@76: this.opt.oBBCBox.setSelect('sel_size', sCurFontSize); Chris@76: this.opt.oBBCBox.setSelect('sel_color', sCurFontColor); Chris@76: Chris@76: if (this.showDebug) Chris@76: setInnerHTML(this.oBreadHandle, sTree); Chris@76: } Chris@76: Chris@76: // Set the HTML content to be that of the text box - if we are in wysiwyg mode. Chris@76: smc_Editor.prototype.doSubmit = function() Chris@76: { Chris@76: if (this.bRichTextEnabled) Chris@76: this.oTextHandle.value = this.oFrameDocument.body.innerHTML; Chris@76: } Chris@76: Chris@76: // Populate the box with text. Chris@76: smc_Editor.prototype.insertText = function(sText, bClear, bForceEntityReverse, iMoveCursorBack) Chris@76: { Chris@76: if (bForceEntityReverse) Chris@76: sText = this.unprotectText(sText); Chris@76: Chris@76: // Erase it all? Chris@76: if (bClear) Chris@76: { Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: // This includes a work around for FF to get the cursor to show! Chris@76: this.oFrameDocument.body.innerHTML = sText; Chris@76: Chris@76: // If FF trick the cursor into coming back! Chris@76: if (is_ff || is_opera) Chris@76: { Chris@76: // For some entirely unknown reason FF3 Beta 2 and some Opera versions Chris@76: // require this. Chris@76: this.oFrameDocument.body.contentEditable = false; Chris@76: Chris@76: this.oFrameDocument.designMode = 'off'; Chris@76: this.oFrameDocument.designMode = 'on'; Chris@76: } Chris@76: } Chris@76: else Chris@76: this.oTextHandle.value = sText; Chris@76: } Chris@76: else Chris@76: { Chris@76: this.setFocus(); Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: // IE croaks if you have an image selected and try to insert! Chris@76: if ('selection' in this.oFrameDocument && this.oFrameDocument.selection.type != 'Text' && this.oFrameDocument.selection.type != 'None' && this.oFrameDocument.selection.clear) Chris@76: this.oFrameDocument.selection.clear(); Chris@76: Chris@76: var oRange = this.getRange(); Chris@76: Chris@76: if (oRange.pasteHTML) Chris@76: { Chris@76: oRange.pasteHTML(sText); Chris@76: Chris@76: // Do we want to move the cursor back at all? Chris@76: if (iMoveCursorBack) Chris@76: oRange.moveEnd('character', -iMoveCursorBack); Chris@76: Chris@76: oRange.select(); Chris@76: } Chris@76: else Chris@76: { Chris@76: // If the cursor needs to be positioned, insert the last fragment first. Chris@76: if (typeof(iMoveCursorBack) != 'undefined' && iMoveCursorBack > 0 && sText.length > iMoveCursorBack) Chris@76: { Chris@76: var oSelection = this.getSelect(false, false); Chris@76: var oRange = oSelection.getRangeAt(0); Chris@76: oRange.insertNode(this.oFrameDocument.createTextNode(sText.substr(sText.length - iMoveCursorBack))); Chris@76: } Chris@76: Chris@76: this.smf_execCommand('inserthtml', false, typeof(iMoveCursorBack) == 'undefined' ? sText : sText.substr(0, sText.length - iMoveCursorBack)); Chris@76: } Chris@76: } Chris@76: else Chris@76: { Chris@76: replaceText(sText, this.oTextHandle); Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: Chris@76: // Special handler for WYSIWYG. Chris@76: smc_Editor.prototype.smf_execCommand = function(sCommand, bUi, sValue) Chris@76: { Chris@76: return this.oFrameDocument.execCommand(sCommand, bUi, sValue); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.insertSmiley = function(oSmileyProperties) Chris@76: { Chris@76: // In text mode we just add it in as we always did. Chris@76: if (!this.bRichTextEnabled) Chris@76: this.insertText(' ' + oSmileyProperties.sCode); Chris@76: Chris@76: // Otherwise we need to do a whole image... Chris@76: else Chris@76: { Chris@76: var iUniqueSmileyId = 1000 + Math.floor(Math.random() * 100000); Chris@76: this.insertText(''); Chris@76: } Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.handleButtonClick = function (oButtonProperties) Chris@76: { Chris@76: this.setFocus(); Chris@76: Chris@76: // A special SMF function? Chris@76: if (oButtonProperties.sCode in this.oSmfExec) Chris@76: this[this.oSmfExec[oButtonProperties.sCode]](); Chris@76: Chris@76: else Chris@76: { Chris@76: // In text this is easy... Chris@76: if (!this.bRichTextEnabled) Chris@76: { Chris@76: // Replace? Chris@76: if (!('sAfter' in oButtonProperties) || oButtonProperties.sAfter == null) Chris@76: replaceText(oButtonProperties.sBefore.replace(/\\n/g, '\n'), this.oTextHandle) Chris@76: Chris@76: // Surround! Chris@76: else Chris@76: surroundText(oButtonProperties.sBefore.replace(/\\n/g, '\n'), oButtonProperties.sAfter.replace(/\\n/g, '\n'), this.oTextHandle) Chris@76: } Chris@76: else Chris@76: { Chris@76: // Is it easy? Chris@76: if (oButtonProperties.sCode in this.oSimpleExec) Chris@76: this.smf_execCommand(this.oSimpleExec[oButtonProperties.sCode], false, null); Chris@76: Chris@76: // A link? Chris@76: else if (oButtonProperties.sCode == 'url' || oButtonProperties.sCode == 'email' || oButtonProperties.sCode == 'ftp') Chris@76: this.insertLink(oButtonProperties.sCode); Chris@76: Chris@76: // Maybe an image? Chris@76: else if (oButtonProperties.sCode == 'img') Chris@76: this.insertImage(); Chris@76: Chris@76: // Everything else means doing something ourselves. Chris@76: else if ('sBefore' in oButtonProperties) Chris@76: this.insertCustomHTML(oButtonProperties.sBefore.replace(/\\n/g, '\n'), oButtonProperties.sAfter.replace(/\\n/g, '\n')); Chris@76: Chris@76: } Chris@76: } Chris@76: Chris@76: this.updateEditorControls(); Chris@76: Chris@76: // Finally set the focus. Chris@76: this.setFocus(); Chris@76: } Chris@76: Chris@76: // Changing a select box? Chris@76: smc_Editor.prototype.handleSelectChange = function (oSelectProperties) Chris@76: { Chris@76: this.setFocus(); Chris@76: Chris@76: var sValue = oSelectProperties.oSelect.value; Chris@76: if (sValue == '') Chris@76: return true; Chris@76: Chris@76: // Changing font face? Chris@76: if (oSelectProperties.sName == 'sel_face') Chris@76: { Chris@76: // Not in HTML mode? Chris@76: if (!this.bRichTextEnabled) Chris@76: { Chris@76: sValue = sValue.replace(/"/, ''); Chris@76: surroundText('[font=' + sValue + ']', '[/font]', this.oTextHandle); Chris@76: oSelectProperties.oSelect.selectedIndex = 0; Chris@76: } Chris@76: else Chris@76: { Chris@76: if (is_webkit) Chris@76: this.smf_execCommand('styleWithCSS', false, true); Chris@76: this.smf_execCommand('fontname', false, sValue); Chris@76: } Chris@76: } Chris@76: Chris@76: // Font size? Chris@76: else if (oSelectProperties.sName == 'sel_size') Chris@76: { Chris@76: // Are we in boring mode? Chris@76: if (!this.bRichTextEnabled) Chris@76: { Chris@76: surroundText('[size=' + this.aFontSizes[sValue] + 'pt]', '[/size]', this.oTextHandle); Chris@76: oSelectProperties.oSelect.selectedIndex = 0; Chris@76: } Chris@76: Chris@76: else Chris@76: this.smf_execCommand('fontsize', false, sValue); Chris@76: } Chris@76: // Or color even? Chris@76: else if (oSelectProperties.sName == 'sel_color') Chris@76: { Chris@76: // Are we in boring mode? Chris@76: if (!this.bRichTextEnabled) Chris@76: { Chris@76: surroundText('[color=' + sValue + ']', '[/color]', this.oTextHandle); Chris@76: oSelectProperties.oSelect.selectedIndex = 0; Chris@76: } Chris@76: Chris@76: else Chris@76: this.smf_execCommand('forecolor', false, sValue); Chris@76: } Chris@76: Chris@76: this.updateEditorControls(); Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: // Put in some custom HTML. Chris@76: smc_Editor.prototype.insertCustomHTML = function(sLeftTag, sRightTag) Chris@76: { Chris@76: var sSelection = this.getSelect(true, true); Chris@76: if (sSelection.length == 0) Chris@76: sSelection = ''; Chris@76: Chris@76: // Are we overwriting? Chris@76: if (sRightTag == '') Chris@76: this.insertText(sLeftTag); Chris@76: // If something was selected, replace and position cursor at the end of it. Chris@76: else if (sSelection.length > 0) Chris@76: this.insertText(sLeftTag + sSelection + sRightTag, false, false, 0); Chris@76: // Wrap the tags around the cursor position. Chris@76: else Chris@76: this.insertText(sLeftTag + sRightTag, false, false, sRightTag.length); Chris@76: Chris@76: } Chris@76: Chris@76: // Insert a URL link. Chris@76: smc_Editor.prototype.insertLink = function(sType) Chris@76: { Chris@76: if (sType == 'email') Chris@76: var sPromptText = oEditorStrings['prompt_text_email']; Chris@76: else if (sType == 'ftp') Chris@76: var sPromptText = oEditorStrings['prompt_text_ftp']; Chris@76: else Chris@76: var sPromptText = oEditorStrings['prompt_text_url']; Chris@76: Chris@76: // IE has a nice prompt for this - others don't. Chris@76: if (sType != 'email' && sType != 'ftp' && is_ie) Chris@76: this.smf_execCommand('createlink', true, 'http://'); Chris@76: Chris@76: else Chris@76: { Chris@76: // Ask them where to link to. Chris@76: var sText = prompt(sPromptText, sType == 'email' ? '' : (sType == 'ftp' ? 'ftp://' : 'http://')); Chris@76: if (!sText) Chris@76: return; Chris@76: Chris@76: if (sType == 'email' && sText.indexOf('mailto:') != 0) Chris@76: sText = 'mailto:' + sText; Chris@76: Chris@76: // Check if we have text selected and if not force us to have some. Chris@76: var oCurText = this.getSelect(true, true); Chris@76: Chris@76: if (oCurText.toString().length != 0) Chris@76: { Chris@76: this.smf_execCommand('unlink'); Chris@76: this.smf_execCommand('createlink', false, sText); Chris@76: } Chris@76: else Chris@76: this.insertText('' + sText + ''); Chris@76: } Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.insertImage = function(sSrc) Chris@76: { Chris@76: if (!sSrc) Chris@76: { Chris@76: sSrc = prompt(oEditorStrings['prompt_text_img'], 'http://'); Chris@76: if (!sSrc || sSrc.length < 10) Chris@76: return; Chris@76: } Chris@76: this.smf_execCommand('insertimage', false, sSrc); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.getSelect = function(bWantText, bWantHTMLText) Chris@76: { Chris@76: if (is_ie && 'selection' in this.oFrameDocument) Chris@76: { Chris@76: // Just want plain text? Chris@76: if (bWantText && !bWantHTMLText) Chris@76: return this.oFrameDocument.selection.createRange().text; Chris@76: // We want the HTML flavoured variety? Chris@76: else if (bWantHTMLText) Chris@76: return this.oFrameDocument.selection.createRange().htmlText; Chris@76: Chris@76: return this.oFrameDocument.selection; Chris@76: } Chris@76: Chris@76: // This is mainly Firefox. Chris@76: if ('getSelection' in this.oFrameWindow) Chris@76: { Chris@76: // Plain text? Chris@76: if (bWantText && !bWantHTMLText) Chris@76: return this.oFrameWindow.getSelection().toString(); Chris@76: Chris@76: // HTML is harder - currently using: http://www.faqts.com/knowledge_base/view.phtml/aid/32427 Chris@76: else if (bWantHTMLText) Chris@76: { Chris@76: var oSelection = this.oFrameWindow.getSelection(); Chris@76: if (oSelection.rangeCount > 0) Chris@76: { Chris@76: var oRange = oSelection.getRangeAt(0); Chris@76: var oClonedSelection = oRange.cloneContents(); Chris@76: var oDiv = this.oFrameDocument.createElement('div'); Chris@76: oDiv.appendChild(oClonedSelection); Chris@76: return oDiv.innerHTML; Chris@76: } Chris@76: else Chris@76: return ''; Chris@76: } Chris@76: Chris@76: // Want the whole object then. Chris@76: return this.oFrameWindow.getSelection(); Chris@76: } Chris@76: Chris@76: // If we're here it's not good. Chris@76: return this.oFrameDocument.getSelection(); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.getRange = function() Chris@76: { Chris@76: // Get the current selection. Chris@76: var oSelection = this.getSelect(); Chris@76: Chris@76: if (!oSelection) Chris@76: return null; Chris@76: Chris@76: if (is_ie && oSelection.createRange) Chris@76: return oSelection.createRange(); Chris@76: Chris@76: return oSelection.rangeCount == 0 ? null : oSelection.getRangeAt(0); Chris@76: } Chris@76: Chris@76: // Get the current element. Chris@76: smc_Editor.prototype.getCurElement = function() Chris@76: { Chris@76: var oRange = this.getRange(); Chris@76: Chris@76: if (!oRange) Chris@76: return null; Chris@76: Chris@76: if (is_ie) Chris@76: { Chris@76: if (oRange.item) Chris@76: return oRange.item(0); Chris@76: else Chris@76: return oRange.parentElement(); Chris@76: } Chris@76: else Chris@76: { Chris@76: var oElement = oRange.commonAncestorContainer; Chris@76: return this.getParentElement(oElement); Chris@76: } Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.getParentElement = function(oNode) Chris@76: { Chris@76: if (oNode.nodeType == 1) Chris@76: return oNode; Chris@76: Chris@76: for (var i = 0; i < 50; i++) Chris@76: { Chris@76: if (!oNode.parentNode) Chris@76: break; Chris@76: Chris@76: oNode = oNode.parentNode; Chris@76: if (oNode.nodeType == 1) Chris@76: return oNode; Chris@76: } Chris@76: return null; Chris@76: } Chris@76: Chris@76: // Remove formatting for the selected text. Chris@76: smc_Editor.prototype.removeFormatting = function() Chris@76: { Chris@76: // Do both at once. Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: this.smf_execCommand('removeformat'); Chris@76: this.smf_execCommand('unlink'); Chris@76: } Chris@76: // Otherwise do a crude move indeed. Chris@76: else Chris@76: { Chris@76: // Get the current selection first. Chris@76: if (this.oTextHandle.caretPos) Chris@76: var sCurrentText = this.oTextHandle.caretPos.text; Chris@76: Chris@76: else if ('selectionStart' in this.oTextHandle) Chris@76: var sCurrentText = this.oTextHandle.value.substr(this.oTextHandle.selectionStart, (this.oTextHandle.selectionEnd - this.oTextHandle.selectionStart)); Chris@76: Chris@76: else Chris@76: return; Chris@76: Chris@76: // Do bits that are likely to have attributes. Chris@76: sCurrentText = sCurrentText.replace(RegExp("\\[/?(url|img|iurl|ftp|email|img|color|font|size|list|bdo).*?\\]", "g"), ''); Chris@76: // Then just anything that looks like BBC. Chris@76: sCurrentText = sCurrentText.replace(RegExp("\\[/?[A-Za-z]+\\]", "g"), ''); Chris@76: Chris@76: replaceText(sCurrentText, this.oTextHandle); Chris@76: } Chris@76: } Chris@76: Chris@76: // Toggle wysiwyg/normal mode. Chris@76: smc_Editor.prototype.toggleView = function(bView) Chris@76: { Chris@76: if (!this.bRichTextPossible) Chris@76: { Chris@76: alert(oEditorStrings['wont_work']); Chris@76: return false; Chris@76: } Chris@76: Chris@76: // Overriding or alternating? Chris@76: if (typeof(bView) == 'undefined') Chris@76: bView = !this.bRichTextEnabled; Chris@76: Chris@76: this.requestParsedMessage(bView); Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: // Request the message in a different form. Chris@76: smc_Editor.prototype.requestParsedMessage = function(bView) Chris@76: { Chris@76: // Replace with a force reload. Chris@76: if (!window.XMLHttpRequest) Chris@76: { Chris@76: alert(oEditorStrings['func_disabled']); Chris@76: return; Chris@76: } Chris@76: Chris@76: // Get the text. Chris@76: var sText = this.getText(true, !bView).replace(/&#/g, "&#").php_to8bit().php_urlencode(); Chris@76: Chris@76: this.tmpMethod = sendXMLDocument; Chris@76: this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=' + (bView ? 1 : 0) + ';' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, this.onToggleDataReceived); Chris@76: delete tmpMethod; Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.onToggleDataReceived = function(oXMLDoc) Chris@76: { Chris@76: var sText = ''; Chris@76: for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++) Chris@76: sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue; Chris@76: Chris@76: // What is this new view we have? Chris@76: this.bRichTextEnabled = oXMLDoc.getElementsByTagName('message')[0].getAttribute('view') != '0'; Chris@76: Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: this.oFrameHandle.style.display = ''; Chris@76: if (this.showDebug) Chris@76: this.oBreadHandle.style.display = ''; Chris@76: this.oTextHandle.style.display = 'none'; Chris@76: } Chris@76: else Chris@76: { Chris@76: sText = sText.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); Chris@76: this.oFrameHandle.style.display = 'none'; Chris@76: this.oBreadHandle.style.display = 'none'; Chris@76: this.oTextHandle.style.display = ''; Chris@76: } Chris@76: Chris@76: // First we focus. Chris@76: this.setFocus(); Chris@76: Chris@76: this.insertText(sText, true); Chris@76: Chris@76: // Record the new status. Chris@76: document.getElementById(this.opt.sUniqueId + '_mode').value = this.bRichTextEnabled ? '1' : '0'; Chris@76: Chris@76: // Rebuild the bread crumb! Chris@76: this.updateEditorControls(); Chris@76: } Chris@76: Chris@76: // Set the focus for the editing window. Chris@76: smc_Editor.prototype.setFocus = function(force_both) Chris@76: { Chris@76: if (!this.bRichTextEnabled) Chris@76: this.oTextHandle.focus(); Chris@76: else if (is_ff || is_opera) Chris@76: this.oFrameHandle.focus(); Chris@76: else Chris@76: this.oFrameWindow.focus(); Chris@76: } Chris@76: Chris@76: // Start up the spellchecker! Chris@76: smc_Editor.prototype.spellCheckStart = function() Chris@76: { Chris@76: if (!spellCheck) Chris@76: return false; Chris@76: Chris@76: // If we're in HTML mode we need to get the non-HTML text. Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: var sText = escape(this.getText(true, 1).php_to8bit()); Chris@76: Chris@76: this.tmpMethod = sendXMLDocument; Chris@76: this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=0;' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, this.onSpellCheckDataReceived); Chris@76: delete tmpMethod; Chris@76: } Chris@76: // Otherwise start spellchecking right away. Chris@76: else Chris@76: spellCheck(this.sFormId, this.opt.sUniqueId); Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: // This contains the spellcheckable text. Chris@76: smc_Editor.prototype.onSpellCheckDataReceived = function(oXMLDoc) Chris@76: { Chris@76: var sText = ''; Chris@76: for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++) Chris@76: sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue; Chris@76: Chris@76: sText = sText.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); Chris@76: Chris@76: this.oTextHandle.value = sText; Chris@76: spellCheck(this.sFormId, this.opt.sUniqueId); Chris@76: } Chris@76: Chris@76: // Function called when the Spellchecker is finished and ready to pass back. Chris@76: smc_Editor.prototype.spellCheckEnd = function() Chris@76: { Chris@76: // If HTML edit put the text back! Chris@76: if (this.bRichTextEnabled) Chris@76: { Chris@76: var sText = escape(this.getText(true, 0).php_to8bit()); Chris@76: Chris@76: this.tmpMethod = sendXMLDocument; Chris@76: this.tmpMethod(smf_prepareScriptUrl(smf_scripturl) + 'action=jseditor;view=1;' + this.opt.sSessionVar + '=' + this.opt.sSessionId + ';xml', 'message=' + sText, smf_editorArray[this.iArrayPosition].onSpellCheckCompleteDataReceived); Chris@76: delete tmpMethod; Chris@76: } Chris@76: else Chris@76: this.setFocus(); Chris@76: } Chris@76: Chris@76: // The corrected text. Chris@76: smc_Editor.prototype.onSpellCheckCompleteDataReceived = function(oXMLDoc) Chris@76: { Chris@76: var sText = ''; Chris@76: for (var i = 0; i < oXMLDoc.getElementsByTagName('message')[0].childNodes.length; i++) Chris@76: sText += oXMLDoc.getElementsByTagName('message')[0].childNodes[i].nodeValue; Chris@76: Chris@76: this.insertText(sText, true); Chris@76: this.setFocus(); Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.resizeTextArea = function(newHeight, newWidth, is_change) Chris@76: { Chris@76: // Work out what the new height is. Chris@76: if (is_change) Chris@76: { Chris@76: // We'll assume pixels but may not be. Chris@76: newHeight = this._calculateNewDimension(this.oTextHandle.style.height, newHeight); Chris@76: if (newWidth) Chris@76: newWidth = this._calculateNewDimension(this.oTextHandle.style.width, newWidth); Chris@76: } Chris@76: Chris@76: // Do the HTML editor - but only if it's enabled! Chris@76: if (this.bRichTextPossible) Chris@76: { Chris@76: this.oFrameHandle.style.height = newHeight; Chris@76: if (newWidth) Chris@76: this.oFrameHandle.style.width = newWidth; Chris@76: } Chris@76: // Do the text box regardless! Chris@76: this.oTextHandle.style.height = newHeight; Chris@76: if (newWidth) Chris@76: this.oTextHandle.style.width = newWidth; Chris@76: } Chris@76: Chris@76: // A utility instruction to save repetition when trying to work out what to change on a height/width. Chris@76: smc_Editor.prototype._calculateNewDimension = function(old_size, change_size) Chris@76: { Chris@76: // We'll assume pixels but may not be. Chris@76: changeReg = change_size.toString().match(/(-)?(\d+)(\D*)/); Chris@76: curReg = old_size.toString().match(/(\d+)(\D*)/); Chris@76: Chris@76: if (!changeReg[3]) Chris@76: changeReg[3] = 'px'; Chris@76: Chris@76: if (changeReg[1] == '-') Chris@76: changeReg[2] = 0 - changeReg[2]; Chris@76: Chris@76: // Both the same type? Chris@76: if (changeReg[3] == curReg[2]) Chris@76: { Chris@76: new_size = parseInt(changeReg[2]) + parseInt(curReg[1]); Chris@76: if (new_size < 50) Chris@76: new_size = 50; Chris@76: new_size = new_size.toString() + changeReg[3]; Chris@76: } Chris@76: // Is the change a percentage? Chris@76: else if (changeReg[3] == '%') Chris@76: new_size = (parseInt(curReg[1]) + parseInt((parseInt(changeReg[2]) * parseInt(curReg[1])) / 100)).toString() + 'px'; Chris@76: // Otherwise just guess! Chris@76: else Chris@76: new_size = (parseInt(curReg[1]) + (parseInt(changeReg[2]) / 10)).toString() + '%'; Chris@76: Chris@76: return new_size; Chris@76: } Chris@76: Chris@76: // Register default keyboard shortcuts. Chris@76: smc_Editor.prototype.registerDefaultShortcuts = function() Chris@76: { Chris@76: if (is_ff) Chris@76: { Chris@76: this.registerShortcut('b', 'ctrl', 'b'); Chris@76: this.registerShortcut('u', 'ctrl', 'u'); Chris@76: this.registerShortcut('i', 'ctrl', 'i'); Chris@76: this.registerShortcut('p', 'alt', 'preview'); Chris@76: this.registerShortcut('s', 'alt', 'submit'); Chris@76: } Chris@76: } Chris@76: Chris@76: // Register a keyboard shortcut. Chris@76: smc_Editor.prototype.registerShortcut = function(sLetter, sModifiers, sCodeName) Chris@76: { Chris@76: if (!sCodeName) Chris@76: return; Chris@76: Chris@76: var oNewShortcut = { Chris@76: code : sCodeName, Chris@76: key: sLetter.toUpperCase().charCodeAt(0), Chris@76: alt : false, Chris@76: ctrl : false Chris@76: }; Chris@76: Chris@76: var aSplitModifiers = sModifiers.split(','); Chris@76: for(var i = 0, n = aSplitModifiers.length; i < n; i++) Chris@76: if (aSplitModifiers[i] in oNewShortcut) Chris@76: oNewShortcut[aSplitModifiers[i]] = true; Chris@76: Chris@76: this.aKeyboardShortcuts[this.aKeyboardShortcuts.length] = oNewShortcut; Chris@76: } Chris@76: Chris@76: // Check whether the key has triggered a shortcut? Chris@76: smc_Editor.prototype.checkShortcut = function(oEvent) Chris@76: { Chris@76: // To be a shortcut it needs to be one of these, duh! Chris@76: if (!oEvent.altKey && !oEvent.ctrlKey) Chris@76: return false; Chris@76: Chris@76: var sReturnCode = false; Chris@76: Chris@76: // Let's take a look at each of our shortcuts shall we? Chris@76: for (var i = 0, n = this.aKeyboardShortcuts.length; i < n; i++) Chris@76: { Chris@76: // Found something? Chris@76: if (oEvent.altKey == this.aKeyboardShortcuts[i].alt && oEvent.ctrlKey == this.aKeyboardShortcuts[i].ctrl && oEvent.keyCode == this.aKeyboardShortcuts[i].key) Chris@76: sReturnCode = this.aKeyboardShortcuts[i].code; Chris@76: } Chris@76: Chris@76: return sReturnCode; Chris@76: } Chris@76: Chris@76: // The actual event check for the above! Chris@76: smc_Editor.prototype.shortcutCheck = function(oEvent) Chris@76: { Chris@76: var sFoundCode = this.checkShortcut(oEvent); Chris@76: Chris@76: // Run it and exit. Chris@76: if (typeof(sFoundCode) == 'string' && sFoundCode != '') Chris@76: { Chris@76: var bCancelEvent = false; Chris@76: if (sFoundCode == 'submit') Chris@76: { Chris@76: // So much to do! Chris@76: var oForm = document.getElementById(this.sFormId); Chris@76: submitThisOnce(oForm); Chris@76: submitonce(oForm); Chris@76: smc_saveEntities(oForm.name, ['subject', this.opt.sUniqueId, 'guestname', 'evtitle', 'question']); Chris@76: oForm.submit(); Chris@76: Chris@76: bCancelEvent = true; Chris@76: } Chris@76: else if (sFoundCode == 'preview') Chris@76: { Chris@76: previewPost(); Chris@76: bCancelEvent = true; Chris@76: } Chris@76: else Chris@76: bCancelEvent = this.opt.oBBCBox.emulateClick(sFoundCode); Chris@76: Chris@76: if (bCancelEvent) Chris@76: { Chris@76: if (is_ie && oEvent.cancelBubble) Chris@76: oEvent.cancelBubble = true; Chris@76: Chris@76: else if (oEvent.stopPropagation) Chris@76: { Chris@76: oEvent.stopPropagation(); Chris@76: oEvent.preventDefault(); Chris@76: } Chris@76: Chris@76: return false; Chris@76: } Chris@76: } Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: // This is the method called after clicking the resize bar. Chris@76: smc_Editor.prototype.startResize = function(oEvent) Chris@76: { Chris@76: if ('event' in window) Chris@76: oEvent = window.event; Chris@76: Chris@76: if (!oEvent || window.smf_oCurrentResizeEditor != null) Chris@76: return true; Chris@76: Chris@76: window.smf_oCurrentResizeEditor = this.iArrayPosition; Chris@76: Chris@76: var aCurCoordinates = smf_mousePose(oEvent); Chris@76: this.osmc_EditorCurrentResize.old_y = aCurCoordinates[1]; Chris@76: this.osmc_EditorCurrentResize.old_rel_y = null; Chris@76: this.osmc_EditorCurrentResize.cur_height = parseInt(this.oTextHandle.style.height); Chris@76: Chris@76: // Set the necessary events for resizing. Chris@76: var oResizeEntity = is_ie ? document : window; Chris@76: oResizeEntity.addEventListener('mousemove', this.aEventWrappers.resizeOverDocument, false); Chris@76: Chris@76: if (this.bRichTextPossible) Chris@76: this.oFrameDocument.addEventListener('mousemove', this.aEventWrappers.resizeOverIframe, false); Chris@76: Chris@76: document.addEventListener('mouseup', this.aEventWrappers.endResize, true); Chris@76: Chris@76: if (this.bRichTextPossible) Chris@76: this.oFrameDocument.addEventListener('mouseup', this.aEventWrappers.endResize, true); Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: // This is kind of a cheat, as it only works over the IFRAME. Chris@76: smc_Editor.prototype.resizeOverIframe = function(oEvent) Chris@76: { Chris@76: if ('event' in window) Chris@76: oEvent = window.event; Chris@76: Chris@76: if (!oEvent || window.smf_oCurrentResizeEditor == null) Chris@76: return true; Chris@76: Chris@76: var newCords = smf_mousePose(oEvent); Chris@76: Chris@76: if (this.osmc_EditorCurrentResize.old_rel_y == null) Chris@76: this.osmc_EditorCurrentResize.old_rel_y = newCords[1]; Chris@76: else Chris@76: { Chris@76: var iNewHeight = newCords[1] - this.osmc_EditorCurrentResize.old_rel_y + this.osmc_EditorCurrentResize.cur_height; Chris@76: if (iNewHeight < 0) Chris@76: this.endResize(); Chris@76: else Chris@76: this.resizeTextArea(iNewHeight + 'px', 0, false); Chris@76: } Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: // This resizes an editor. Chris@76: smc_Editor.prototype.resizeOverDocument = function (oEvent) Chris@76: { Chris@76: if ('event' in window) Chris@76: oEvent = window.event; Chris@76: Chris@76: if (!oEvent || window.smf_oCurrentResizeEditor == null) Chris@76: return true; Chris@76: Chris@76: var newCords = smf_mousePose(oEvent); Chris@76: Chris@76: var iNewHeight = newCords[1] - this.osmc_EditorCurrentResize.old_y + this.osmc_EditorCurrentResize.cur_height; Chris@76: if (iNewHeight < 0) Chris@76: this.endResize(); Chris@76: else Chris@76: this.resizeTextArea(iNewHeight + 'px', 0, false); Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: smc_Editor.prototype.endResize = function (oEvent) Chris@76: { Chris@76: if ('event' in window) Chris@76: oEvent = window.event; Chris@76: Chris@76: if (window.smf_oCurrentResizeEditor == null) Chris@76: return true; Chris@76: Chris@76: window.smf_oCurrentResizeEditor = null; Chris@76: Chris@76: // Remove the event... Chris@76: var oResizeEntity = is_ie ? document : window; Chris@76: oResizeEntity.removeEventListener('mousemove', this.aEventWrappers.resizeOverDocument, false); Chris@76: Chris@76: if (this.bRichTextPossible) Chris@76: this.oFrameDocument.removeEventListener('mousemove', this.aEventWrappers.resizeOverIframe, false); Chris@76: Chris@76: document.removeEventListener('mouseup', this.aEventWrappers.endResize, true); Chris@76: Chris@76: if (this.bRichTextPossible) Chris@76: this.oFrameDocument.removeEventListener('mouseup', this.aEventWrappers.endResize, true); Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: // *** smc_SmileyBox class. Chris@76: function smc_SmileyBox(oOptions) Chris@76: { Chris@76: this.opt = oOptions; Chris@76: this.oSmileyRowsContent = {}; Chris@76: this.oSmileyPopupWindow = null; Chris@76: this.init(); Chris@76: } Chris@76: Chris@76: smc_SmileyBox.prototype.init = function () Chris@76: { Chris@76: // Get the HTML content of the smileys visible on the post screen. Chris@76: this.getSmileyRowsContent('postform'); Chris@76: Chris@76: // Inject the HTML. Chris@76: setInnerHTML(document.getElementById(this.opt.sContainerDiv), this.opt.sSmileyBoxTemplate.easyReplace({ Chris@76: smileyRows: this.oSmileyRowsContent.postform, Chris@76: moreSmileys: this.opt.oSmileyLocations.popup.length == 0 ? '' : this.opt.sMoreSmileysTemplate.easyReplace({ Chris@76: moreSmileysId: this.opt.sUniqueId + '_addMoreSmileys' Chris@76: }) Chris@76: })); Chris@76: Chris@76: // Initialize the smileys. Chris@76: this.initSmileys('postform', document); Chris@76: Chris@76: // Initialize the [more] button. Chris@76: if (this.opt.oSmileyLocations.popup.length > 0) Chris@76: { Chris@76: var oMoreLink = document.getElementById(this.opt.sUniqueId + '_addMoreSmileys'); Chris@76: oMoreLink.instanceRef = this; Chris@76: oMoreLink.onclick = function () { Chris@76: this.instanceRef.handleShowMoreSmileys(); Chris@76: return false; Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: // Loop through the smileys to setup the HTML. Chris@76: smc_SmileyBox.prototype.getSmileyRowsContent = function (sLocation) Chris@76: { Chris@76: // If it's already defined, don't bother. Chris@76: if (sLocation in this.oSmileyRowsContent) Chris@76: return; Chris@76: Chris@76: this.oSmileyRowsContent[sLocation] = ''; Chris@76: Chris@76: for (var iSmileyRowIndex = 0, iSmileyRowCount = this.opt.oSmileyLocations[sLocation].length; iSmileyRowIndex < iSmileyRowCount; iSmileyRowIndex++) Chris@76: { Chris@76: var sSmileyRowContent = ''; Chris@76: for (var iSmileyIndex = 0, iSmileyCount = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex].length; iSmileyIndex < iSmileyCount; iSmileyIndex++) Chris@76: sSmileyRowContent += this.opt.sSmileyTemplate.easyReplace({ Chris@76: smileySource: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sSrc.php_htmlspecialchars(), Chris@76: smileyDescription: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sDescription.php_htmlspecialchars(), Chris@76: smileyCode: this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex].sCode.php_htmlspecialchars(), Chris@76: smileyId: this.opt.sUniqueId + '_' + sLocation + '_' + iSmileyRowIndex.toString() + '_' + iSmileyIndex.toString() Chris@76: }); Chris@76: Chris@76: this.oSmileyRowsContent[sLocation] += this.opt.sSmileyRowTemplate.easyReplace({ Chris@76: smileyRow: sSmileyRowContent Chris@76: }); Chris@76: } Chris@76: } Chris@76: Chris@76: smc_SmileyBox.prototype.initSmileys = function (sLocation, oDocument) Chris@76: { Chris@76: for (var iSmileyRowIndex = 0, iSmileyRowCount = this.opt.oSmileyLocations[sLocation].length; iSmileyRowIndex < iSmileyRowCount; iSmileyRowIndex++) Chris@76: { Chris@76: for (var iSmileyIndex = 0, iSmileyCount = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex].length; iSmileyIndex < iSmileyCount; iSmileyIndex++) Chris@76: { Chris@76: var oSmiley = oDocument.getElementById(this.opt.sUniqueId + '_' + sLocation + '_' + iSmileyRowIndex.toString() + '_' + iSmileyIndex.toString()); Chris@76: oSmiley.instanceRef = this; Chris@76: oSmiley.style.cursor = 'pointer'; Chris@76: oSmiley.onclick = function () { Chris@76: this.instanceRef.clickHandler(this); Chris@76: return false; Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: smc_SmileyBox.prototype.clickHandler = function (oSmileyImg) Chris@76: { Chris@76: // Dissect the id... Chris@76: var aMatches = oSmileyImg.id.match(/([^_]+)_(\d+)_(\d+)$/); Chris@76: if (aMatches.length != 4) Chris@76: return false; Chris@76: Chris@76: // ...to determine its exact smiley properties. Chris@76: var sLocation = aMatches[1]; Chris@76: var iSmileyRowIndex = aMatches[2]; Chris@76: var iSmileyIndex = aMatches[3]; Chris@76: var oProperties = this.opt.oSmileyLocations[sLocation][iSmileyRowIndex][iSmileyIndex]; Chris@76: Chris@76: if ('sClickHandler' in this.opt) Chris@76: eval(this.opt.sClickHandler + '(oProperties)'); Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: smc_SmileyBox.prototype.handleShowMoreSmileys = function () Chris@76: { Chris@76: // Focus the window if it's already opened. Chris@76: if (this.oSmileyPopupWindow != null && 'closed' in this.oSmileyPopupWindow && !this.oSmileyPopupWindow.closed) Chris@76: { Chris@76: this.oSmileyPopupWindow.focus(); Chris@76: return; Chris@76: } Chris@76: Chris@76: // Get the smiley HTML. Chris@76: this.getSmileyRowsContent('popup'); Chris@76: Chris@76: // Open the popup. Chris@76: 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'); Chris@76: Chris@76: // Paste the template in the popup. Chris@76: this.oSmileyPopupWindow.document.open('text/html', 'replace'); Chris@76: this.oSmileyPopupWindow.document.write(this.opt.sMoreSmileysPopupTemplate.easyReplace({ Chris@76: smileyRows: this.oSmileyRowsContent.popup, Chris@76: moreSmileysCloseLinkId: this.opt.sUniqueId + '_closeMoreSmileys' Chris@76: })); Chris@76: this.oSmileyPopupWindow.document.close(); Chris@76: Chris@76: // Initialize the smileys that are in the popup window. Chris@76: this.initSmileys('popup', this.oSmileyPopupWindow.document); Chris@76: Chris@76: // Add a function to the close window button. Chris@76: var aCloseLink = this.oSmileyPopupWindow.document.getElementById(this.opt.sUniqueId + '_closeMoreSmileys'); Chris@76: aCloseLink.instanceRef = this; Chris@76: aCloseLink.onclick = function () { Chris@76: this.instanceRef.oSmileyPopupWindow.close(); Chris@76: return false; Chris@76: } Chris@76: } Chris@76: Chris@76: Chris@76: // *** smc_BBCButtonBox class. Chris@76: function smc_BBCButtonBox(oOptions) Chris@76: { Chris@76: this.opt = oOptions; Chris@76: this.init(); Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.init = function () Chris@76: { Chris@76: var sBbcContent = ''; Chris@76: for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++) Chris@76: { Chris@76: var sRowContent = ''; Chris@76: var bPreviousWasDivider = false; Chris@76: for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++) Chris@76: { Chris@76: var oCurButton = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: switch (oCurButton.sType) Chris@76: { Chris@76: case 'button': Chris@76: if (oCurButton.bEnabled) Chris@76: { Chris@76: sRowContent += this.opt.sButtonTemplate.easyReplace({ Chris@76: buttonId: this.opt.sUniqueId.php_htmlspecialchars() + '_button_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString(), Chris@76: buttonSrc: oCurButton.sImage.php_htmlspecialchars(), Chris@76: buttonDescription: oCurButton.sDescription.php_htmlspecialchars() Chris@76: }); Chris@76: Chris@76: bPreviousWasDivider = false; Chris@76: } Chris@76: break; Chris@76: Chris@76: case 'divider': Chris@76: if (!bPreviousWasDivider) Chris@76: sRowContent += this.opt.sDividerTemplate; Chris@76: Chris@76: bPreviousWasDivider = true; Chris@76: break; Chris@76: Chris@76: case 'select': Chris@76: var sOptions = ''; Chris@76: Chris@76: // Fighting javascript's idea of order in a for loop... :P Chris@76: if ('' in oCurButton.oOptions) Chris@76: sOptions = ''; Chris@76: for (var sSelectValue in oCurButton.oOptions) Chris@76: // we've been through this before Chris@76: if (sSelectValue != '') Chris@76: sOptions += ''; Chris@76: Chris@76: sRowContent += this.opt.sSelectTemplate.easyReplace({ Chris@76: selectName: oCurButton.sName, Chris@76: selectId: this.opt.sUniqueId.php_htmlspecialchars() + '_select_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString(), Chris@76: selectOptions: sOptions Chris@76: }); Chris@76: Chris@76: bPreviousWasDivider = false; Chris@76: break; Chris@76: } Chris@76: } Chris@76: sBbcContent += this.opt.sButtonRowTemplate.easyReplace({ Chris@76: buttonRow: sRowContent Chris@76: }); Chris@76: } Chris@76: Chris@76: var oBbcContainer = document.getElementById(this.opt.sContainerDiv); Chris@76: setInnerHTML(oBbcContainer, sBbcContent); Chris@76: Chris@76: for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++) Chris@76: { Chris@76: for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++) Chris@76: { Chris@76: var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: switch (oCurControl.sType) Chris@76: { Chris@76: case 'button': Chris@76: if (!oCurControl.bEnabled) Chris@76: break; Chris@76: Chris@76: oCurControl.oImg = document.getElementById(this.opt.sUniqueId.php_htmlspecialchars() + '_button_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString()); Chris@76: oCurControl.oImg.style.cursor = 'pointer'; Chris@76: if ('sButtonBackgroundImage' in this.opt) Chris@76: oCurControl.oImg.style.backgroundImage = 'url(' + this.opt.sButtonBackgroundImage + ')'; Chris@76: Chris@76: oCurControl.oImg.instanceRef = this; Chris@76: oCurControl.oImg.onmouseover = function () { Chris@76: this.instanceRef.handleButtonMouseOver(this); Chris@76: }; Chris@76: oCurControl.oImg.onmouseout = function () { Chris@76: this.instanceRef.handleButtonMouseOut(this); Chris@76: }; Chris@76: oCurControl.oImg.onclick = function () { Chris@76: this.instanceRef.handleButtonClick(this); Chris@76: }; Chris@76: Chris@76: oCurControl.oImg.bIsActive = false; Chris@76: oCurControl.oImg.bHover = false; Chris@76: break; Chris@76: Chris@76: case 'select': Chris@76: oCurControl.oSelect = document.getElementById(this.opt.sUniqueId.php_htmlspecialchars() + '_select_' + iButtonRowIndex.toString() + '_' + iButtonIndex.toString()); Chris@76: Chris@76: oCurControl.oSelect.instanceRef = this; Chris@76: oCurControl.oSelect.onchange = oCurControl.onchange = function () { Chris@76: this.instanceRef.handleSelectChange(this); Chris@76: } Chris@76: break; Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.handleButtonMouseOver = function (oButtonImg) Chris@76: { Chris@76: oButtonImg.bHover = true; Chris@76: this.updateButtonStatus(oButtonImg); Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.handleButtonMouseOut = function (oButtonImg) Chris@76: { Chris@76: oButtonImg.bHover = false; Chris@76: this.updateButtonStatus(oButtonImg); Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.updateButtonStatus = function (oButtonImg) Chris@76: { Chris@76: var sNewURL = ''; Chris@76: if (oButtonImg.bHover && oButtonImg.bIsActive && 'sActiveButtonBackgroundImageHover' in this.opt) Chris@76: sNewURL = 'url(' + this.opt.sActiveButtonBackgroundImageHover + ')'; Chris@76: else if (!oButtonImg.bHover && oButtonImg.bIsActive && 'sActiveButtonBackgroundImage' in this.opt) Chris@76: sNewURL = 'url(' + this.opt.sActiveButtonBackgroundImage + ')'; Chris@76: else if (oButtonImg.bHover && 'sButtonBackgroundImageHover' in this.opt) Chris@76: sNewURL = 'url(' + this.opt.sButtonBackgroundImageHover + ')'; Chris@76: else if ('sButtonBackgroundImage' in this.opt) Chris@76: sNewURL = 'url(' + this.opt.sButtonBackgroundImage + ')'; Chris@76: Chris@76: if (oButtonImg.style.backgroundImage != sNewURL) Chris@76: oButtonImg.style.backgroundImage = sNewURL; Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.handleButtonClick = function (oButtonImg) Chris@76: { Chris@76: // Dissect the id attribute... Chris@76: var aMatches = oButtonImg.id.match(/(\d+)_(\d+)$/); Chris@76: if (aMatches.length != 3) Chris@76: return false; Chris@76: Chris@76: // ...so that we can point to the exact button. Chris@76: var iButtonRowIndex = aMatches[1]; Chris@76: var iButtonIndex = aMatches[2]; Chris@76: var oProperties = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: oProperties.bIsActive = oButtonImg.bIsActive; Chris@76: Chris@76: if ('sButtonClickHandler' in this.opt) Chris@76: eval(this.opt.sButtonClickHandler + '(oProperties)'); Chris@76: Chris@76: return false; Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.handleSelectChange = function (oSelectControl) Chris@76: { Chris@76: // Dissect the id attribute... Chris@76: var aMatches = oSelectControl.id.match(/(\d+)_(\d+)$/); Chris@76: if (aMatches.length != 3) Chris@76: return false; Chris@76: Chris@76: // ...so that we can point to the exact button. Chris@76: var iButtonRowIndex = aMatches[1]; Chris@76: var iButtonIndex = aMatches[2]; Chris@76: var oProperties = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: Chris@76: if ('sSelectChangeHandler' in this.opt) Chris@76: eval(this.opt.sSelectChangeHandler + '(oProperties)'); Chris@76: Chris@76: return true; Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.setActive = function (aButtons) Chris@76: { Chris@76: for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++) Chris@76: { Chris@76: for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++) Chris@76: { Chris@76: var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: if (oCurControl.sType == 'button' && oCurControl.bEnabled) Chris@76: { Chris@76: oCurControl.oImg.bIsActive = in_array(oCurControl.sCode, aButtons); Chris@76: this.updateButtonStatus(oCurControl.oImg); Chris@76: } Chris@76: } Chris@76: } Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.emulateClick = function (sCode) Chris@76: { Chris@76: for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++) Chris@76: { Chris@76: for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++) Chris@76: { Chris@76: var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: if (oCurControl.sType == 'button' && oCurControl.sCode == sCode) Chris@76: { Chris@76: eval(this.opt.sButtonClickHandler + '(oCurControl)'); Chris@76: return true; Chris@76: } Chris@76: } Chris@76: } Chris@76: return false; Chris@76: } Chris@76: Chris@76: smc_BBCButtonBox.prototype.setSelect = function (sSelectName, sValue) Chris@76: { Chris@76: if (!('sButtonClickHandler' in this.opt)) Chris@76: return; Chris@76: Chris@76: for (var iButtonRowIndex = 0, iRowCount = this.opt.aButtonRows.length; iButtonRowIndex < iRowCount; iButtonRowIndex++) Chris@76: { Chris@76: for (var iButtonIndex = 0, iButtonCount = this.opt.aButtonRows[iButtonRowIndex].length; iButtonIndex < iButtonCount; iButtonIndex++) Chris@76: { Chris@76: var oCurControl = this.opt.aButtonRows[iButtonRowIndex][iButtonIndex]; Chris@76: if (oCurControl.sType == 'select' && oCurControl.sName == sSelectName) Chris@76: oCurControl.oSelect.value = sValue; Chris@76: } Chris@76: } Chris@76: }