/************************************************************************** * * @@@BUILDINFO@@@ 35omvUI-2.jsx 2.0.1.74 12-June-2007 * Copyright 2006-2007 Adobe Systems Incorporated * All Rights Reserved. * * NOTICE: All information contained herein is, and remains the property of * Adobe Systems Incorporated and its suppliers, if any. The intellectual * and technical concepts contained herein are proprietary to Adobe Systems * Incorporated and its suppliers and may be covered by U.S. and Foreign * Patents,patents in process,and are protected by trade secret or copyright * law. Dissemination of this information or reproduction of this material * is strictly forbidden unless prior written permission is obtained from * Adobe Systems Incorporated. **************************************************************************/ // Object Model Viewer. // Current limitations: // 1) The first TOC level is ignored. // 2) Namespace and interface declarations are not interpreted. // 3) Only the first is interpreted. // Create an OMV viewer. Takes the BridgeTalk ID of the target. // Properties: // data the OMVData object containing XML. // w the window // classes the Classes listbox // types the Element Types listbox // elements the Properties and Methods listbox // display the HTML display // classesItems an object with class names as properties and the class list items as values function OMV (data) { this.data = data; this.classesItems = {}; this.classHrefs = { // Object : "$COMMON/javascript.xml#/", Array : "$COMMON/javascript.xml#/", Math : "$COMMON/javascript.xml#/", Date : "$COMMON/javascript.xml#/", Function : "$COMMON/javascript.xml#/", String : "$COMMON/javascript.xml#/", Number : "$COMMON/javascript.xml#/", Boolean : "$COMMON/javascript.xml#/", RegExp : "$COMMON/javascript.xml#/", Error : "$COMMON/javascript.xml#/", File : "$COMMON/javascript.xml#/", Folder : "$COMMON/javascript.xml#/", Socket : "$COMMON/javascript.xml#/", ReflectionInfo : "$COMMON/javascript.xml#/", Reflection : "$COMMON/javascript.xml#/", Dictionary : "$COMMON/javascript.xml#/", QName : "$COMMON/javascript.xml#/", Namespace : "$COMMON/javascript.xml#/", XML : "$COMMON/javascript.xml#/", UnitValue : "$COMMON/javascript.xml#/", ScriptUI : "$COMMON/scriptui.xml#/", Window : "$COMMON/scriptui.xml#/", LayoutManager : "$COMMON/scriptui.xml#/", ScriptUIGraphics: "$COMMON/scriptui.xml#/", ScriptUIPen : "$COMMON/scriptui.xml#/", ScriptUIBrush : "$COMMON/scriptui.xml#/", ScriptUIPath : "$COMMON/scriptui.xml#/", ScriptUIFont : "$COMMON/scriptui.xml#/", ScriptUIImage : "$COMMON/scriptui.xml#/", DrawState : "$COMMON/scriptui.xml#/", StaticText : "$COMMON/scriptui.xml#/", Button : "$COMMON/scriptui.xml#/", IconButton : "$COMMON/scriptui.xml#/", EditText : "$COMMON/scriptui.xml#/", ListBox : "$COMMON/scriptui.xml#/", DropDownList : "$COMMON/scriptui.xml#/", ListItem : "$COMMON/scriptui.xml#/", Checkbox : "$COMMON/scriptui.xml#/", Scrollbar : "$COMMON/scriptui.xml#/", RadioButton : "$COMMON/scriptui.xml#/", Slider : "$COMMON/scriptui.xml#/", Progressbar : "$COMMON/scriptui.xml#/", TreeView : "$COMMON/scriptui.xml#/", FlashPlayer : "$COMMON/scriptui.xml#/", Group : "$COMMON/scriptui.xml#/", Panel : "$COMMON/scriptui.xml#/", Point : "$COMMON/scriptui.xml#/", Dimension : "$COMMON/scriptui.xml#/", Bounds : "$COMMON/scriptui.xml#/", UIEvent : "$COMMON/scriptui.xml#/", MenuElement : "$COMMON/scriptui.xml#/" }; // The preferred size is == the default size of a doc window this.w = new Window ( "documentwindow { \ preferredSize : [470, 510], \ orientation : 'column', \ margins : 2, \ spacing : 2, \ properties : \ { \ minimumSize : [350, 180], \ closeOnKey : 'OSCmnd+W', \ }, \ grp : Group { \ orientation : 'row', \ size : [ 100, 300 ], \ alignment : ['fill', 'top' ], \ classes : Group { \ orientation : 'column', \ size : [ 100, 300 ], \ alignment : ['fill', 'top' ], \ label : StaticText { \ alignment : 'left', \ text : '$$$/ESToolkit/OMV/Classes=Classes', \ }, \ classes : ListBox { \ properties : { \ multiselect : true, \ helpTip : '$$$/ESToolkit/OMV/htClasses=Classes', \ } \ alignment : ['fill', 'fill' ] \ }, \ }, \ elements : Group { \ orientation : 'column', \ size : [ 100, 300 ], \ alignment : ['fill', 'top' ], \ label : StaticText { \ alignment : 'left', \ text : '$$$/ESToolkit/OMV/Elements=Properties and Methods', \ }, \ types : ListBox { \ size : [ 100, 70 ], \ alignment : ['fill', 'top' ], \ helpTip : '$$$/ESToolkit/OMV/htTypes=Types', \ }, \ elements : ListBox { \ properties : { \ multiselect : true \ }, \ alignment : ['fill', 'fill' ], \ helpTip : '$$$/ESToolkit/OMV/htElements=Elements', \ } \ } \ }, \ find : Group { \ orientation : 'row', \ alignment : 'fill', \ btns : Group { \ margins : 0, \ spacing : 2, \ back : IconButton { \ preferredSize: [24, 24], \ enabled : false, \ helpTip : '$$$/ESToolkit/OMV/htBack=Go to previous entry.', \ }, \ fwd : IconButton { \ preferredSize: [24, 24], \ enabled : false, \ helpTip : '$$$/ESToolkit/OMV/htNext=Go to next entry.', \ }, \ copy : IconButton { \ preferredSize: [24, 24], \ enabled : false, \ helpTip : '$$$/ESToolkit/OMV/htCopy=Copy description to clipboard', \ }, \ }, \ label : StaticText { \ alignment : ['left', 'center' ], \ text : '$$$/ESToolkit/FindReplaceDlg/FindLbl=Find:', \ }, \ find : EditText { \ preferredSize: [100,20], \ alignment : ['fill', 'top' ], \ helpTip : '$$$/ESToolkit/OMV/htFind=Type in the element you are looking for here.', \ } \ }, \ dispBorder : Panel { \ properties : { \ borderStyle : 'sunken', \ }, \ alignment : ['fill', 'fill' ], \ display : FlashPlayer { \ minimumSize : [10, 10], \ alignment : ['fill', 'fill' ] \ } \ } \ }"); this.classes = this.w.grp.classes.classes; this.types = this.w.grp.elements.types; this.elements = this.w.grp.elements.elements; this.display = this.w.dispBorder.display; this.find = this.w.find.find; this.findLabel= this.w.find.label; this.fwd = this.w.find.btns.fwd; this.back = this.w.find.btns.back; this.copy = this.w.find.btns.copy; this.w.omv = this.classes.omv = this.types.omv = this.elements.omv = this.display.omv = this.find.omv = this.fwd.omv = this.back.omv = this.copy.omv = this; OMV.windows.push (this.w); this.w.text = this.data.xml.map.@title; this.fwd.icon = ScriptUI.newImage ('#BrowseRight_R', '#BrowseRight_N'); this.back.icon = ScriptUI.newImage ('#BrowseLeft_R', '#BrowseLeft_N'); this.copy.icon = ScriptUI.newImage ('#Copy_R', '#Copy_N'); this.copy.enabled = true; this.fwd.enabled = false; this.back.enabled = false; // This is set to nonzero if only a list box selection changes, // and no data is supposed to be reloaded. this.ignoreChanges = 0; this.w.onNotify = function( reason ) { if( reason == 'shutdown' ) { globalBroadcaster.unregisterClient( this ); this.omv.detachHandlers(); this.hide(); } } this.w.onClose = function() { // no XML = no use for this window if (!this.omv.data.xml) return true; // otherwise, just hide it this.hide(); return false; } globalBroadcaster.registerClient( this.w ); this.w.onResize = function () { this.layout.resize(); } this.setupHTMLControl (this.display); var ok = true; // LAYOUT BUG: need to show now already this.w.show(); this.startHTML(); if (this.data.showProgress) { this.dlg = new ProgressBox ('$$$/ESToolkit/OMV/SetupUI=Initializing the UI...'); ok = this.loadTOC(); this.dlg.stop(); this.dlg = null; } else ok = this.loadTOC(); /* if (ok) { // LAYOUT BUG: enable this statement this.w.show(); this.startHTML(); } */ } // This is the array of all OMV windows. OMV.windows = []; // This is the default font size of the OMV HTML viewer. OMV.htmlFontSize = 11; // The OMV icons are here, addressed by their names. OMV.icons = {}; // The list of OMV that need to unpdate their HTML. // HTML is updated delayed. OMV.update = []; // Set up all OMV entries in the Help menu. OMV.setup = function() { // Set up the OMVData OMVData.setup(); // Set up the icons this.icons.ENUMERATION = ScriptUI.newImage ("#Enumeration"); this.icons.CLASS = ScriptUI.newImage ("#Class"); this.icons.METHOD = ScriptUI.newImage ("#Method"); this.icons.ROPROPERTY = ScriptUI.newImage ("#PropertyRO"); this.icons.RWPROPERTY = ScriptUI.newImage ("#PropertyRW"); } ////////////////////////////////////////////////////////////////// // // onChange Handlers // These handlers are attached to the list and edit boxes. // The Classes onChange handler is attached after the // list box has been filled to avoid unnecessary calls. // ////////////////////////////////////////////////////////////////// OMV.prototype.attachHandlers = function() { // Classes change notification. this.classes.onChange = function() { if (this.omv.ignoreChanges) return; var item = this.selection; if (item) { var xml = null; if (item.length == 1) { if (!item[0].xml) item[0].xml = this.omv.data.findXML (item[0].clsName); if (!item[0].xml) return; this.omv.loadClass (item[0].xml); return; } else { xml = XML("").children(); for (var i = 0; i < item.length; i++) { if (!item[i].xml) item[i].xml = this.omv.data.findXML (item[i].clsName); xml += item[i].xml; } } } this.omv.ignoreChanges++; this.omv.types.xml = null; this.omv.types.removeAll(); this.omv.elements.xml = null; this.omv.elements.removeAll(); this.omv.ignoreChanges--; this.omv.displayXML (xml); } // Element types change notification. this.types.onChange = function() { if (this.omv.ignoreChanges) return; var item = this.selection; if (item) this.omv.loadClassElements (item.xml); else { this.omv.ignoreChanges++; this.omv.elements.xml = null; this.omv.elements.removeAll(); this.omv.setHTML (null); this.omv.ignoreChanges--; } } // Methods/properties change notification this.elements.onChange = function() { if (this.omv.ignoreChanges) return; var item = this.selection; var xml = null; if (item) { if (item.length > 1) { xml = XML("").children(); for (var i = 0; i < item.length; i++) xml += item[i].xml; } else xml = item[0].xml; } this.omv.displayXML (xml); } this.find.onChanging = function() { if (!this.ignoreChanges) this.omv.findText (this.text); } } OMV.prototype.detachHandlers = function() { delete this.classes.onChange; delete this.types.onChange; delete this.elements.onChange; delete this.find.onChanging; } ////////////////////////////////////////////////////////////////// // // Deleting // Called when a dynamic OMV was reloaded // ////////////////////////////////////////////////////////////////// OMV.prototype.detach = function() { for (var i = 0; i < OMV.windows.length; i++) { if (OMV.windows [i] == this.w) { OMV.windows.splice (i, 1); break; } } this.w.hide(); this.w = null; this.data.omv = null; this.data.menu.omv = null; this.data.menu.enabled = true; } ////////////////////////////////////////////////////////////////// // // Disabling // ////////////////////////////////////////////////////////////////// // Disable this UI due to errors. // Also a callback from the OMVData instance in case on errors. OMV.prototype.disable = function() { this.data.badXML(); this.data.menu.enabled = false; this.data.xml = null; if (this.w) this.w.close(); } ////////////////////////////////////////////////////////////////// // // Data Loading // ////////////////////////////////////////////////////////////////// // Load the TOC into the Classes listbox. Returns false if aborted. OMV.prototype.loadTOC = function() { var list = this.sortedXML (this.data.map.children(), "navtitle"); if (this.dlg) this.dlg.setProgress (0, list.length); for (var i = 0; i < list.length; i++) { if (this.dlg && !this.dlg.setProgress (i)) { this.disable(); return false; } var href = this.data.splitHref (list[i].@href.toString()); // no packages! var xpath = 'classdef[@name = "' + href.cls + '"]'; var xml = null; if (this.data.xml['package']) { xml = this.data.xml['package'].xpath (xpath); if (!xml.length()) { this.disable(); return false; } } var item = this.classes.add ("item", list [i].@navtitle); this.classesItems [href.cls] = item; this.classHrefs [href.cls] = "#/"; item.xml = xml; item.omv = this; item.clsName = href.cls; if (item.xml) item.icon = ((item.xml.@enumeration == "true") ? OMV.icons.ENUMERATION : OMV.icons.CLASS); } // Attach onChange handlers here this.attachHandlers(); return true; } // Load the next-level class info (which is the elements group). OMV.prototype.loadClass = function (xml, noStack) { if (xml == this.types.xml) return; var currentItem = this.types.selection ? this.types.selection.text : ""; this.types.removeAll(); this.types.xml = xml; var item; var selItem = null; var types = [ "constructor", "class", "instance", "prototype", "event" ]; var typeNames = [ "$$$/ESToolkit/OMV/Types/Constructors=Constructors", "$$$/ESToolkit/OMV/Types/ClassElements=Class Elements", "$$$/ESToolkit/OMV/Types/InstanceElements=Instance Elements", "$$$/ESToolkit/OMV/Types/PrototypeElements=Prototype Elements", "$$$/ESToolkit/OMV/Types/Events=Events" ]; this.ignoreChanges++; for (var i = 0; i < types.length; i++) { var container = xml.xpath ("elements[@type='" + types [i] + "']"); if (container.length() > 0) { item = this.types.add ("item", localize (typeNames [i])); item.xml = container; item.omv = this; // Select either the first occurence, the last type, or instance elements if ((!selItem && types [i] == "instance") || item.text == currentItem) selItem = item; } } if (!selItem) selItem = this.types.items [0]; this.ignoreChanges--; this.types.selection = selItem; // and load the HTML if (!noStack) this.pushHTMLStack (xml); this.setHTML (this.getHTML (xml)); } // Fill in the elements for a class. The parent is the 2nd level. OMV.prototype.loadClassElements = function (xml) { // this is the container if (this.elements.xml == xml) return; this.elements.xml = xml; this.ignoreChanges++; this.elements.removeAll(); var href = xml.parent().@name.toString() + "/" + xml.@type + "/"; var isEnum = (xml.parent().@enumeration == "true"); var props = this.sortedXML (xml.property, "name"); var meths = this.sortedXML (xml.method, "name"); var name, type; for (var i = 0; i < props.length; i++) { name = this.makeElementName (props [i]); var item = this.elements.add ("item", name); item.xml = props [i]; item.omv = this; if (props[i].@name == "activeDocument") item.yes = true; if (isEnum) item.icon = OMV.icons.ENUMERATION; else item.icon = (props[i].@rwaccess == "readonly") ? OMV.icons.ROPROPERTY : OMV.icons.RWPROPERTY; } for (var i = 0; i < meths.length; i++) { name = this.makeElementName (meths [i]); item = this.elements.add ("item", name); item.xml = meths [i]; item.omv = this; item.icon = OMV.icons.METHOD; } this.ignoreChanges--; } // Create an element name. Properties get a colon and the data type, // and methods get the parameter list and the return type. If a data // type is linkable, makeTypeInfo() creates a link. OMV.prototype.makeElementName = function (xml) { var name = xml.@name; var type = this.makeTypeInfo (xml.datatype, false); if (xml.localName() != "method") { if (type == "") type = "any"; name += ": " + type; } else { var args = "("; var params = xml.parameters.children(); for (var j = 0; j < params.length(); j++) { if (j) args += ", "; args += params [j].@name; } args += ")"; if (args.length > 2) name += " "; name += args; if (type != "") name += ": " + type; } return name; } ////////////////////////////////////////////////////////////////// // // HTML Generation // ////////////////////////////////////////////////////////////////// // Generate HTML for a given XML. This XML could be one or more // class-level entries, or one or more element level entries. OMV.prototype.getHTML = function (xml) { var html = null; if (!xml) html = XML (''); else { if (xml.length() == 1) { switch (xml.localName()) { case "classdef": html = this.getClassHTML (xml); break; case "method": html = this.getMethodHTML (xml); break; case "property": html = this.getPropertyHTML (xml); break; } } if (html == null) { html = new XML (''); if (xml) { var br = new XML ('
'); var sorted = this.sortedXML (xml, "name"); for (var i = 0; i < sorted.length; i++) { if (sorted [i].localName() == "classdef") html.body.appendChild (this.makeLink (this.data.getHrefForXML (sorted [i]), sorted [i].@name.toString())); else { var name; if (sorted[i].parent().@type == "constructor") name = "new " + this.makeElementName (sorted [i]); else name = sorted [i].parent().parent().@name + "." + this.makeElementName (sorted [i]); html.body.appendChild (this.makeLink (this.data.getHrefForXML (sorted [i]), name)); } html.body.appendChild (br); } } } } return html; } // Generate and return HTML for a class. OMV.prototype.getClassHTML = function (xml) { var html = XML (''); html.body.appendChild (XML('

' + xml.@name + '

')); if (xml.superclass.length() > 0) { var p = XML ("

"); p.appendChild (XML ("Base Class: ")); var href = xml.superclass.@href.toString(); if (href == "") href = this.data.getHrefForXML (xml.superclass); p.appendChild (this.makeLink (href, xml.@name.toString())); html.body.appendChild (p); } this.appendHelpText (html.body, xml); this.appendExamples (html.body, xml); return html; } // Generate and return HTML for a property. OMV.prototype.getPropertyHTML = function (propXML) { var html = XML (''); var type = this.makeTypeInfo (propXML.datatype, true); if (type == "") type = "any"; var rw = ""; switch (propXML.@rwaccess.toString()) { case "readonly": rw = "(Read Only)"; break; case "writeonly": rw = "(Write Only)"; break; } html.body.appendChild (XML('

' + propXML.parent().parent().@name + '.' + propXML.@name + ' ' + rw + '

')); html.body.appendChild (XML('

Data Type: ' + this.makeFullTypeInfo (propXML.datatype) + '

')); this.appendHelpText (html.body, propXML); this.appendExamples (html.body, propXML); return html; } // Generate and return HTML for a method. OMV.prototype.getMethodHTML = function (methXML) { var html = XML (''); // create the bold method name var block = XML(''); block.appendChild (methXML.parent().parent().@name + '.' + methXML.@name + " ("); var params = methXML.parameters.children(); for (var j = 0; j < params.length(); j++) { var text = (j > 0) ? ", " : ""; text += params [j].@name + ":"; block.appendChild (text); var typeXML = this.makeTypeInfo (params [j].datatype, true, true); if (typeXML.length() == 0) typeXML = "any"; block.appendChild (typeXML); } block.appendChild (")"); var type = this.makeTypeInfo (methXML.datatype, true); if (type.toString() != "") { block.appendChild (":"); block.appendChild (type); } block.normalize(); var p = XML ('

'); p.font.appendChild (block); html.body.appendChild (p); this.appendHelpText (html.body, methXML); for (var j = 0; j < params.length(); j++) { var param = params [j]; var type = this.makeFullTypeInfo (param.datatype); if (type == "") type = "any"; var tempXML = '

' + param.@name; if (param.@optional == "true" || param.datatype.value != "") tempXML += " (optional)"; tempXML += ':

'; var p = XML (tempXML); p.appendChild ("Data Type: "); p.appendChild (type); html.body.appendChild (p); this.appendHelpText (html.body, param); } this.appendExamples (html.body, methXML); return html; } // Error message for bad HTML, or missing HTML display. OMV.prototype.badHTML = function() { errorBox ('$$$/ESToolkit/Alerts/BadFlash=Cannot display HTML!\nHelp is not available.'); this.disable(); } // Sort the given XML list and return an Array obbject wth the sorted elements. // The sort is case insensitive. OMV.prototype.sortedXML = function (xml, attrname) { var arr = []; for (var i = 0; i < xml.length(); i++) { var s = xml [i]['@' + attrname].toString().toUpperCase(); arr.push (s + '\n' + i); } arr.sort(); for (i = 0; i < arr.length; i++) arr [i] = xml [arr [i].split ('\n')[1]]; return arr; } // Create a type info string out of a element // datatypeXML - the element // doXML - return XML rather than a string // onlyType - return type only, no details OMV.prototype.makeTypeInfo = function (datatypeXML, doXML, onlyType) { // make sure that we process only the first element of a possible list if (datatypeXML.length() > 1) datatypeXML = datatypeXML [0]; // we don't want localization here for now. var xml = XML (''); var type = datatypeXML.type.toString(); // small fixup if (type == "bool") type = "boolean"; var elem = datatypeXML.array; var fmt; if (elem.length()) fmt = (elem.@size == "") ? "Array of %1" : "Array [%2] of %1"; else fmt = "%1"; if (doXML) { var href = datatypeXML.type.@href.toString(); if (!href.length && datatypeXML.parent()) { // no HREF? Make sure that the datatype is not the same as the class def var tempxml = datatypeXML.parent().parent(); while (tempxml && tempxml.localName() != "classdef") tempxml = tempxml.parent(); if (tempxml && tempxml.@name != type) { // This is a different data type; try to find one based on the text href = this.classHrefs [type]; if (!href) href = ""; else // Apend the text href += type; } } if (href.length) { // check either for a valid file reference, or a known class var split = this.data.splitHref (href); if ((split.file.length && File (split.file).exists) || this.classesItems [type]) { // Create a two-element array with the class name set to \n // so we can split the message at the class name var s = localize (fmt, "\n", elem.@size); s = s.split ("\n"); // 1st part of the message xml.appendChild (s [0]); xml.appendChild (this.makeLink (href, type)); xml.appendChild (s [1]); // show that we dont need to append anything fmt = null; } } } if (fmt) xml.appendChild (localize (fmt, type, elem.@size)); if (!onlyType) { elem = datatypeXML.minimum; if (elem.length()) xml.appendChild (", " + localize ("Minimum: %1", elem.toString())); elem = datatypeXML.maximum; if (elem.length()) xml.appendChild (", " + localize ("Maximum: %1", elem.toString())); elem = datatypeXML.value.toString(); if (elem != "") { // If the type is Number, check for possible display as 4-byte const if (type == "number") { var n = Number (elem); if (n >= 0x20202020) { var chars = ""; for (var i = 0; i < 4; i++, n <<= 8) { var ch = String.fromCharCode ((n >> 24) & 0xFF); if (ch >= " " && ch <= "~") chars += ch; } if (chars.length == 4) elem += " ('" + chars + "')"; } } fmt = (datatypeXML.parent().@rwaccess == "readonly") ? "Value: %1" : "Default Value: %1"; xml.appendChild (", " + localize (fmt, elem)); } } xml = xml.children(); xml.normalize(); return doXML ? xml : xml.toString(); } // Create type info XML out of a element list // If the data type is a list, createXML like "XXX or YYY" // datatypeXML - the element - maybe a list OMV.prototype.makeFullTypeInfo = function (datatypeXML) { // root element is ignored var s = XML (''); for (var i = 0; i < datatypeXML.length(); i++) { if (i > 0) s.appendChild ("or"); s.appendChild (this.makeTypeInfo (datatypeXML [i], true)); } return s; } // Append the short and/or the full description to given HTML. OMV.prototype.appendHelpText = function (html, xml, usePara) { var text = xml.shortdesc; var p; if (text.length()) { p = text.copy(); p.setName ("p"); this.expandLinks (p); html.appendChild (p); } text = xml.description; if (text.length()) { p = text.copy(); p.setName ("p"); this.expandLinks (p); html.appendChild (p); } } // Append any examples to the given HTML. OMV.prototype.appendExamples = function (html, xml) { var ex = xml.example; if (ex.length() > 0) html.appendChild (XML (ex.length() == 1 ? "

Example:

" : "

Examples:

")); for (var i = 0; i < ex.length(); i++) { var p; var elem = ex [i]; var href = elem.@href.toString(); if (href) { var f = this.data.splitHref (href); f = new File (f.file); if (f.open()) { p = XML('

'); var body = p.font; while (!f.eof) { var text = f.readln(); // Change leading whitespace to the non-breaking variant var text2 = ""; var nbsp = String.fromCharCode (160); for (var ch = 0; ch < text.length; ch++) { switch (text [ch]) { case "\t": text2 += nbsp + nbsp + nbsp + nbsp; break; case ' ': text2 += nbsp; break; default: text2 += text.substr (ch); text = ""; } } p.font.appendChild (text2); p.font.appendChild (XML ("
")); } f.close(); html.appendChild (p); } } else { html.appendChild (elem.children().copy()); this.expandLinks (html); } } } // Extend all elements in the given HTML to // link text OMV.prototype.expandLinks = function (html) { if (html.localName() == "a") { var href = html.@href.toString(); // Do not insert "event:" if the Href starts with http: or file: if (href.indexOf ("http:") < 0 && href.indexOf ("file:") < 0) href = "event:" + href; return new XML('' + html.toString() + ''); } else if (html.nodeKind() == "element") { var kids = html.children(); var newKids = new XML('<>'); for (var i = 0; i < kids.length(); i++) newKids += this.expandLinks (kids [i]); html.setChildren (newKids); } return html; } // Create a HREF attribute for the given href. // This href has the form [file]#/Classname[/Containertype/Elementname] // to be used as argument to findText(). // The first argument is either XML, or the raw link text. // The return value of the complete tag. OMV.prototype.makeLink = function (href, text) { if (href=="") // no HREF? Then no link return XML (text); href = this.data.splitHref (href); if (!text) { text = href.cls; if (href.name) text += '.' + href.name; } return XML ('' + text + ''); } ////////////////////////////////////////////////////////////////// // // Searching // ////////////////////////////////////////////////////////////////// // Find a string. If the string contains a dot, split into class name and // element name. If words is true, the search must be accurate (whole words). OMV.prototype.findText = function (what, wholeWord) { var xml = this.data.findXML (what, wholeWord); this.ignoreChanges++; this.displayXML (xml); this.setFindField (xml); this.ignoreChanges--; } // Find a HREF. OMV.prototype.findHref = function (href) { this.displayXML (this.data.getXMLForHref (href)); } // Helper: find a list element that has the given XML appended. OMV.prototype._getListItemForXML = function (parent, xml) { var items = parent.items; for (var i = 0; i < items.length; i++) { var item = items [i]; if (item.xml == xml) return item; } return null; } // Helper: Set a multiselection if it has changed. // Both arrays are assumed to be sorted by item index. OMV.prototype._setSelection = function (parent, newSel) { var oldSel = parent.selection; if (!oldSel) { if (newSel) parent.selection = newSel; } else if (!newSel) parent.selection = newSel; else if (oldSel.length != newSel.length) parent.selection = newSel; else for (var i = 0; i < oldSel.length; i++) { if (oldSel[i].index != newSel[i].index) { parent.selection = null; parent.selection = newSel; break; } } } // Select the given XML in the appropriate lists. // If the XML is multiple elements, select all elements. // The XML may be a list of classes or a list of elements in // a single container, but not both classes and elements, or // multiple element containers. OMV.prototype.selectXML = function (xml) { if (!this.w.visible) return; this.ignoreChanges++; if (xml) { var sel = []; var array = this.sortedXML (xml, "name"); var isClass = xml[0].localName() == "classdef"; if (isClass) { for (var i = 0; i < array.length; i++) { var item = this._getListItemForXML (this.classes, xml); if (item) sel.push (item); } } else if (xml.xpath ("../..").length() == 1) sel.push (this._getListItemForXML (this.classes, xml[0].parent().parent())); this._setSelection (this.classes, sel); if (sel.length != 1) { this.types.xml = null; this.elements.xml = null; this.types.removeAll(); this.elements.removeAll(); } else { sel = null; // select types var containerxml, elementxml; if (isClass) { this.loadClass (xml, true); // select a container containerxml = xml.elements; if (containerxml.length() != 1) { // if there are multiple, start with instance elements if possible containerxml = xml.xpath ('elements[@type="instance"]'); if (containerxml.length() == 0) containerxml = xml.elements [0]; } } else // use xpath to catch multiple parents containerxml = xml.xpath (".."); if (containerxml.length() > 0) this.loadClass (containerxml.parent(), true); if (containerxml.length() == 1) { item = this._getListItemForXML (this.types, containerxml); if (item) { this.types.selection = item; this.loadClassElements (containerxml); } else { this.types.selection = null; this.elements.xml = null; this.elements.removeAll(); } } var elements = []; if (!isClass && this.types.selection) { for (var i = 0; i < array.length; i++) { var item = this._getListItemForXML (this.elements, xml); if (item) elements.push (item); } } this._setSelection (this.elements, elements); } } else { this.display.html = null; this.setHTML(); } this.ignoreChanges--; } // Set the contents of the Find text field to the given text or XML. OMV.prototype.setFindField = function (what) { if (typeof what == "xml") { if (what.length() != 1) return; var name = what[0].@name.toString(); what = (what[0].localName() == "classdef") ? name : what.parent().parent().@name + '.' + name; } if (what != null && what != this.find.text) { this.ignoreChanges++; this.find.text = what; this.ignoreChanges--; } } // Display the given XML and select the appropriate lists. // If the XML is multiple elements, select all elements and // create a list of clickable elements in the HTML display. // The XML may be a list of classes or a list of elements in // a single container, but not both classes and elements, or // multiple element containers. OMV.prototype.displayXML = function (xml) { if (!this.w.visible) return; this.selectXML (xml); if (xml) { this.pushHTMLStack (xml); this.setHTML (this.getHTML (xml)); } } ////////////////////////////////////////////////////////////////// // // HTML Control // ////////////////////////////////////////////////////////////////// OMV.prototype.setupHTMLControl = function (ctrl) { /// This is the HTML page stack. this.htmlStack = []; this.htmlPos = -1; /* This function is called from the htmlViewer control via ExternalInterface::call to get the page content for the given 'link' */ ctrl.getContentForLink = function (theCookie, href) { var html; // The link is a string created by makeLink() below. // The format is [file]#/classname[/containertype/elementname]. var split = this.omv.data.splitHref (href); if (split.file.length) { // An external file; load the OMV for that file and display the link var omvData = OMVData.getByFile (split.file); if (omvData) { var xml = omvData.getXMLForHref (href); if (xml) { omvData.show(); omvData.ui.selectXML (xml); } } // we do not want to change the HTML, so return the current HTML html = this.omv.prepareHTML (this.omv.display.html) + "

"; } else { var xml = this.omv.data.getXMLForHref (href); this.omv.selectXML (xml); if (xml) { // add the XML to the HTML stack this.omv.pushHTMLStack (xml); html = this.omv.getHTML (xml); } else html = XML( 'Broken link: ' + href + ''); html = this.omv.prepareHTML (html); } return html; } // invoke SWF's copy-to-clipboard func this.copy.onClick = function() { this.omv.display.invokePlayerFunction("copyToClipboard"); } this.fwd.onClick = function() { if (this.omv.htmlPos < this.omv.htmlStack.length-1) { var xml = this.omv.htmlStack [this.omv.htmlPos+1]; this.omv.htmlPos++; this.enabled = (this.omv.htmlPos < this.omv.htmlStack.length-1); this.omv.back.enabled = (this.omv.htmlPos > 0); this.omv.selectXML (xml); this.omv.setHTML (this.omv.getHTML (xml)); } } this.back.onClick = function() { if (this.omv.htmlPos > 0) { var xml = this.omv.htmlStack [this.omv.htmlPos -1]; this.omv.htmlPos--; this.enabled = (this.omv.htmlPos > 0); this.omv.fwd.enabled = (this.omv.htmlPos < this.omv.htmlStack.length-1); this.omv.selectXML (xml); this.omv.setHTML (this.omv.getHTML (xml)); } } } // Start the HTML "movie" OMV.prototype.startHTML = function() { var movieToPlay = new File (app.requiredFolder + "/more/ESTK_HTML.swf"); if (!movieToPlay.exists) this.badHTML(); else { try { this.display.loadMovie (movieToPlay); } catch (e) { this.badHTML(); } } } // Prepare the given HTML (which is complete) for the HTML widget. // The returned value is the HTML as string. OMV.prototype.prepareHTML = function (html) { if (!html) html = this.display.html; if (!html) return this.display.html = XML(""); html = html.removeNamespace ("http://www.w3.org/2001/XMLSchema-instance"); html = html.body.children(); this.display.html = html; var s = html.toXMLString(); s = s.replace (/\n/mg, ""); XML.prettyPrinting = false; var newhtml = XML (''); newhtml.appendChild (html); html = newhtml.toXMLString(); XML.prettyPrinting = true; return html; } // Set the HTML at the HTML widget. OMV.prototype.setHTML = function (html) { this.prepareHTML (html); OMV.update.push (this); addDelayedTask (updateOMV); } function updateOMV() { for (var i = 0; i < OMV.update.length; i++) { var omv = OMV.update [i]; omv.display.invokePlayerFunction("htmlViewerInitialize", "cookie", omv.display.html, { flexStyles: { fontGridFitType: "subpixel", fontThickness: 50, fontSharpness: 50 }, flexProperties: { condenseWhite: true } }); } OMV.update = []; } // Push an entry on the HTML stack. The entry is the XML to display. OMV.prototype.pushHTMLStack = function (xml) { if (!xml) return; // do not push the same XML twice if (this.htmlStack.length > 0 && this.htmlStack [this.htmlPos] == xml) return; this.htmlStack.splice (this.htmlPos+1); this.htmlStack.push (xml); this.htmlPos++; this.back.enabled = (this.htmlPos > 0); this.fwd.enabled = false; }