You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by jm...@apache.org on 2006/06/22 22:59:36 UTC
svn commit: r416494 - in /incubator/xap/trunk: src/xap/ src/xap/taghandling/
testsrc/ testsrc/xap/taghandling/
Author: jmargaris
Date: Thu Jun 22 15:59:35 2006
New Revision: 416494
URL: http://svn.apache.org/viewvc?rev=416494&view=rev
Log:
having a subdirectory called "tags" was a bad idea
Added:
incubator/xap/trunk/src/xap/taghandling/
incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js (with props)
incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js (with props)
incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js (with props)
incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js (with props)
incubator/xap/trunk/src/xap/taghandling/plugin.xml (with props)
incubator/xap/trunk/testsrc/xap/taghandling/
incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html (with props)
incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html (with props)
incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html (with props)
incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js (with props)
incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html (with props)
incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml (with props)
Modified:
incubator/xap/trunk/src/xap/Xap.js
incubator/xap/trunk/testsrc/XapUnitTestSuite.html
Modified: incubator/xap/trunk/src/xap/Xap.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/Xap.js?rev=416494&r1=416493&r2=416494&view=diff
==============================================================================
--- incubator/xap/trunk/src/xap/Xap.js (original)
+++ incubator/xap/trunk/src/xap/Xap.js Thu Jun 22 15:59:35 2006
@@ -135,9 +135,9 @@
//xap.tags (TODO rename?_
- Utils.importFile( sourceRootDir + "/src/xap/tags/AbstractTagImpl.js" );
- Utils.importFile( sourceRootDir + "/src/xap/tags/PluginDocumentHandler.js" );
- Utils.importFile( sourceRootDir + "/src/xap/tags/PluginRegistryImpl.js" );
+ Utils.importFile( sourceRootDir + "/src/xap/taghandling/AbstractTagImpl.js" );
+ Utils.importFile( sourceRootDir + "/src/xap/taghandling/PluginDocumentHandler.js" );
+ Utils.importFile( sourceRootDir + "/src/xap/taghandling/PluginRegistryImpl.js" );
Added: incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+//TODO we need to handle qualifying URLs properly based on the request page again
+
+/**
+ * @fileoverview The base class for all element to peer object
+ * bridges.
+ *
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+/**
+ * Creates a new AbstractTagImpl, this is typically called by the parsing
+ * framework and should not be called directly by other code.
+ *
+ * @class The base class for all user-defined tag-handling classes.
+ * <br><br>
+ *
+ * Whenever a new document fragment is added to the UI document, the following
+ * steps take place:
+ * <ol>
+ * <li>The name of the root tag is looked up in the default and any extra
+ * tag-mapping files to find the class that is supposed to that handle that tag.
+ * If no class is found that is the end of the process.</li>
+ * <li>Assuming the class exists, a member of that class is constructed via
+ * a no-arg constructor.</li>
+ * <li>The handling instance (AKA the tag-handler) and the element are added
+ * to hashtables so that one can be looked up from the other.</li>
+ * <li>The tag-handler setSession() method is called so that it can access the session.
+ * It is <b>not</b> added to the application as an MCO.</li>
+ * <li>The tag-handler is added to the Element as an
+ * AttributeChangeListener and a StructureChangeListener.</li>
+ * <li>setElement() is called with the XML element that is mapped to the tag-handler.</li>
+ * <li>Finally, init() is called.</li>
+ * </ol>
+ *
+ * It is important to understand that when a document fragment is added to the
+ * UI document that fragment may have a number of descendents. Those descendents
+ * do <b>not</b> automatically go through the same process. However,
+ * this class provides parseInitialChildren() to mimic recursive parsing of the children.
+ * Similarly, an Element can be added to the UI document with attributes already in place.
+ * Those initial attributes will not create attributeChange events. However, this
+ * class provides parseInitialAttributes() to help processing in that case.
+ *
+ * <br><br>
+ * To respond correctly to dynamic changes in the document, a tag handler
+ * should respond to AttributeChangeEvents and StructureChangeEvents in a suitable
+ * fashion.
+ * <br><br>
+ * It is possible for a single tag-handler to handle an entire subtree of
+ * elements. In this case the tag-handler can add itself as an AttributeChangeListener
+ * and/or StructureChangeListener on each element in the controlled subtree.
+ *
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+function AbstractTagImpl() {
+ this._element = null;
+ this._peer = null;
+ this._clientSession = null;
+}
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+
+
+/**
+ * Returns the element this tag mapped to.
+ */
+AbstractTagImpl.prototype.getElement = function() {
+ return this._element;
+}
+
+/**
+ * Sets the element this tag maps to, this is called during the
+ * automatic intiliazation process.
+ *
+ * @param e The element this tag maps to.
+ */
+AbstractTagImpl.prototype.setElement = function( el ) {
+ this._element = el;
+}
+
+/**
+ * Returns the object that this bridge controls.
+ */
+AbstractTagImpl.prototype.getPeer = function() {
+ return this._peer;
+}
+
+/**
+ * Subclasses should override this method to provide proper initialization
+ * behavior. This is the final call in the tag-handler creation process.
+ */
+AbstractTagImpl.prototype.init = function() {}
+
+
+//-----------------------------------------------------------------------
+// Protected Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * Sets the object that this bridge controls.To use
+ * <code>UiContentHandler.getHandlerForPeer()</code> it is not enough
+ * to call this method, the developer must also call
+ * <code>UiContentHandler.setHandlerForPeer()</code>. This call is made
+ * automatically in ContainerBridge but classes that extend AbstractTagImpl
+ * directly must call them themselves if they need the ability to do the peer
+ * to handler lookup.
+ */
+AbstractTagImpl.prototype.setPeer = function( obj ){
+ this._peer = obj;
+ this.getUiContentHandler().setHandlerForPeer( obj, this);
+}
+
+/**
+ * @return The UI document
+ */
+AbstractTagImpl.prototype.getUiDocument = function() {
+ return this.getSession().getDocumentContainer().getUiDocument();
+}
+
+/**
+ * This method is provided for convenience to deal with elements
+ * that start with a number of attributes when they are added to the
+ * document. This method will run through all the initial attributes
+ * and construct an AttributeChangeEvent for each attribute, then
+ * call onAttributeSet with that change event. This simulates
+ * an element that was added with no attributes and then had attributes
+ * added at a later point.
+ * <br><br>
+ * This method takes an element to handle the case where one
+ * tag handler handles multiple tags. In most normal applications
+ * this element will be the result of getElement()
+ *
+ * @param e The element to parse the initial attributes from.
+ */
+AbstractTagImpl.prototype.parseInitialAttributes = function( e ) {
+ var attributes = e.attributes;
+
+ var names = new Array(attributes.length);
+
+ //have to copy them over, because as we add attributes the enumeration
+ //itself changes. This is a problem if adding an attribute causes
+ //more attributes to be added, which can happen with class when
+ //the stylesheet attributes are added, and we get tricked into
+ //thinking they are not from the stylesheet. Instead, we think
+ //they were an initial attribute since they were tacked on to the
+ //enumeration
+
+ for (var i = 0; i<attributes.length; i++){
+ var attributeName = e.attributes[i].nodeName;
+ names[i] = attributeName;
+ }
+
+ for ( var i=0; i < names.length; i++ ) {
+ var attributeName = names[i];
+ var attributeValue = e.getAttribute( attributeName );
+ var event = new AttributeChangeEvent( e, attributeName, attributeValue );
+ // change the value
+ this.beforeAttributeSet( event );
+ this.onAttributeSet( event );
+ }
+}
+
+/**
+ * This method is provided for convenience to deal with elements
+ * that start with a number of children when they are added to the
+ * document. For each initial child, this method will call
+ * UiContentHandler.parseChild() on that child element, which initiates
+ * the tag-handling steps defined above. After calling parseChild() on a
+ * child element a StructureChangeEvent is created and sent to onChildAdded().
+ * This simulates
+ * an element that was added with no children and then had children
+ * added at a later point.
+ * <br><br>
+ * This method takes an element to handle the case where one
+ * tag handler handles multiple tags. In most normal applications
+ * this element will be the result of getElement()
+ *
+ * @param e The element to parse the initial children of.
+ */
+AbstractTagImpl.prototype.parseInitialChildren = function( e ) {
+ var session = this.getSession();
+ var contentHandler = session.getUiDocumentHandler();
+
+ var children = new Array(e.childNodes.length);
+ for ( var i = 0; i<children.length; i++){
+ children[i] = e.childNodes[i];
+ }
+ //TODO we need this for iterator but we really need a more efficient
+ //way to do this
+ for ( var i = 0; i < children.length; i++ ) {
+ var child = children[i];
+ if ( child.nodeType==DOM_ELEMENT_NODE ) {
+ contentHandler.parseChild( child );
+
+ //-1 index means an append, even though we already have
+ //all the child elements we want to pretend we are adding
+ //them right now, so just fire off each one as if it was appended
+ var event = new StructureChangeEvent( e, child, -1 );
+ this.beforeChildAdded( event );
+ this.onChildAdded( event );
+ }
+ if ( child.nodeType==DOM_TEXT_NODE ) {
+ //TODO this needs some work in that they are supposed to be able
+ //to CHANGE the text in the beforeChildAdded and that is supposed to
+ //be what we actually add. This can happen with databinding syntax
+ //where the text is replaced with filled-in values. What we really
+ //need to do here is fire the before, then if the new value is different
+ //from the old actually REPLACE the old text value with the new one.
+ //for reference the old code looked like:
+ // writeBackRemoveChild(i);
+ // e.insertChildAt(i,(String)o);
+ //This worked but was somewhat inneficient in that it always removed
+ //and re-added the text node. Perhaps in this case what we should do
+ //is instead of actually change the text node just change the VALUE
+ //of the text node instead. So if we see a text node with data binding like:
+ // <button>{ someOtherButton.text }</button>
+ //we replace the someOtherButton.text with the resolved value by changing
+ //the value of the text node while keeping the same text node overall.
+
+ var event = new StructureChangeEvent( e, child, -1 );
+ this.beforeChildAdded( event );
+ this.onChildAdded( event );
+
+ }
+ }
+}
+
+
+/**
+ * Returns the URL context for the current thread. The URL context can be
+ * used to translate relative URLs into non-relative URLs. For example,
+ * if the page MYAPP/pages/myPage.jsp contains onCommand="pages2/anotherPage.xml",
+ * the URL context is "MYAPP/pages/" and the onCommand should refer to
+ * "MYAPP/pages/pages2/anotherPage.xml"
+ *
+ * @return The URL context of the current thread, which can be null.
+ */
+AbstractTagImpl.prototype.getUrlContext = function() {
+ return this.getSession().getUrlContext();
+}
+
+///**
+// * Turns a potentially relative URL into a fully qualified one.
+// * If this is called from the parsing thread during the parsing of a page,
+// * the url is qualified relative to that page's origin. Otherwise the
+// * url should begin with http:/, https:// or "/"
+// * @param relativeUrl The URL to qualify.
+// * @return A fully qualified URL.
+// * @throws MalformedURLException
+// */
+//AbstractTagImpl.prototype.createQualifiedUrl = function( relativeUrl ) {
+// var urlContext = this.getUrlContext();
+// if ( urlContext != null ) {
+// return this.getSession().getRequestService().
+// createFullyQualifiedUrl( urlContext,
+// relativeUrl);
+// }
+// return this.getSession().getRequestService().createFullyQualifiedUrl(relativeUrl);
+//
+//}
+//
+//AbstractTagImpl.prototype.createQualifiedUrlAsString = function( relativeUrl ) {
+// var urlContext = this.getUrlContext();
+// if ( urlContext != null ) {
+// return this.getSession().getRequestService().
+// createFullyQualifiedUrlAsString( urlContext, relativeUrl );
+// }
+// return this.getSession().getRequestService().
+// createFullyQualifiedUrlAsString( relativeUrl );
+//}
+
+/**
+ * This method is used to fire an event in a standard manner.
+ * The ClientEvent encapsulates any extra info in the event. The eventValue
+ * should be something like "mco://myMco.do()" or "mypage.jsp".
+ * If the eventName is not registered on the element this method
+ * simply returns.
+ *
+ * @param eventName The name of the event, like onCommand
+ * @param eventValue The value of the event, like "mco://myMco.do()"
+ * @param eventElement The element the event is registered on
+ * @param clientEvent The ClientEvent that contains any extra information - may be null.
+ * @return TODO
+ */
+AbstractTagImpl.prototype.fireEvent = function( eventName, eventValue, eventElement,
+ clientEvent ) {
+ var session = this.getSession();
+
+ //if they didn't pass in an event element use our element
+ if ( eventElement == null ) {
+ eventElement = this.getElement();
+ }
+
+ //if they didn't pass in an event value
+ //use the value in the dom, if they have
+ //onCommand="myPage" use "myPage" as the event value
+ if ( eventValue == null ) {
+ eventValue = eventElement.getAttribute( eventName );
+ }
+
+ //if there was no event value we have noone listening
+ //for the event so just return
+ if ( eventValue == null ) {
+ return null;
+ }
+
+ if ( clientEvent == null ) {
+ clientEvent = new ClientEvent( eventElement, this.getSession());
+ }
+
+ clientEvent.id = eventElement.getAttribute( "id" );
+ clientEvent.event = eventName;
+
+ //addInvokerInfo(clientEvent,eventElement);
+ return session.getEventHandler().fireEvent( eventName, eventValue,
+ eventElement,clientEvent );
+}
+
+
+// /**
+// * If an event like onCommand takes place, it may take place on a menuItem
+// * that was inside a popupMenu, and you would like to know what the
+// * menu was currently attached to. This does that by
+// * adding the "invoker" field with the proper ID.
+// * @param event
+// * @param sourceComponent
+// */
+// private void addInvokerInfo(ClientEvent event, Element sourceElement){
+// AbstractTagImpl tag = getUiContentHandler().getHandlerForElement(sourceElement);
+// if (! (tag instanceof AwtComponentBridge)) return;
+// Component parent = ((AwtComponentBridge)tag).getUiComponent();
+//
+// for(;;){
+// if (parent==null) break;
+//
+// if (parent instanceof NPopup){
+//
+// //get the reference of the popup, if that doesn't work
+// //get the actual Component invoker.
+// Object reference = ((NPopup)parent).getReference();
+// if (reference==null) reference = ((NPopup)parent).getInvoker();
+//
+// //if we found something, see if it has a handler,
+// //and if so plug in that ID and name.
+// if (reference!=null){
+// Element referenceElement = null;
+//
+// //in the case of cell there is no mapping of peer
+// //to to bridge, so the reference is just to the cell
+// //element itself
+// if (reference instanceof Element){
+// referenceElement = (Element) reference;
+// }
+// else{
+//
+// //problem: we get the handler for the peer, but this
+// //could be either <valueComboBox> or the underlying
+// //<comboBox>. Right now we return than handler for
+// //comboBox itself. However, the NAME and ID
+// //of the <comboBox> should be the same as for
+// //<valueComboBox>
+// tag = getUiContentHandler().getHandlerForPeer(reference);
+// if (tag!=null){
+// referenceElement = tag.getElement();
+// }
+// }
+//
+// if (referenceElement!=null){
+// event.setParameter("invoker",referenceElement.getAttribute("id"));
+// String name = referenceElement.getAttribute("name");
+// if (name==null) name = "";
+// event.setParameter("invokerName",name);
+// }
+// }
+// }
+// if (parent instanceof NPanel){
+// parent = ((NPanel)parent).getLogicalParent();
+// }
+// else{
+// parent = parent.getParent();
+// }
+//
+// }
+// }
+//
+/**
+ * Returns the UiContentHandler. This handler can be used to
+ * look up a tag by element, or an element by tag, as well as to parse
+ * child elements.
+ *
+ * TODO this tag can exist in documents OTHER than the UI document,
+ * this is not a good way to do this, we should really have a generic
+ * getContentHandler() based on the document the element we manage
+ * belongs to.
+ *
+ * @return The UiContentHandler.
+ */
+AbstractTagImpl.prototype.getUiContentHandler = function() {
+ return this.getSession().getUiDocumentHandler();
+}
+//
+//
+// public void writeBackTextNode(int index, String value){
+// synchronized(getUiDocument().getDomSynchronizationObject()){
+// getElement().removeStructureChangeListener(this);
+// getElement().removeChildAt(index);
+// getElement().insertChildAt(index,value);
+// getElement().addStructureChangeListener(this);
+// }
+// }
+//
+//
+//
+ /**
+ * This method can be used to write values back into the document.
+ * For example, if a user enters text into a textField and we want the
+ * "text" attribute to reflect the text, we can call
+ * writeBackAttribute("text",getText()).
+ * <br><br>
+ * This will not signal the tag-handler that an attribute has changed. The assumption
+ * is that the tag-handler is what initiated the write back. Other AttributeChangeListeners
+ * will be called.
+ *
+ * @param name The name of the attribute to write.
+ * @param value The new value.
+ */
+
+AbstractTagImpl.prototype.writeBackAttribute = function(name, value) {
+ this.getElement().removeAttributeChangeListener(this);
+ this.getElement().setAttribute(name,value);
+ this.getElement().addAttributeChangeListener(this);
+}
+//
+// private void writeBackAttribute(Element e, String name, String value){
+// synchronized(getUiDocument().getDomSynchronizationObject()){
+// e.removeAttributeChangeListener(this);
+// e.setAttribute(name,value);
+// e.addAttributeChangeListener(this);
+// }
+// }
+//
+//
+// /**
+// * This method can be used to remove values the document.
+// * For example, if a user deletes all text from a textField and we want the
+// * "text" attribute to reflect the lack of text, we can call
+// * writeBackRemoveAttribute("text").
+// * <br><br>
+// * This will not signal the tag-handler that an attribute has been removed. The assumption
+// * is that the tag-handler is what initiated the write back. Other AttributeChangeListeners
+// * will be called.
+// *
+// * @param name The name of the attribute to remove.
+// */
+// public void writeBackRemoveAttribute(String name){
+// synchronized(getUiDocument().getDomSynchronizationObject()){
+// getElement().removeAttributeChangeListener(this);
+// getElement().removeAttribute(name);
+// getElement().addAttributeChangeListener(this);
+// }
+// }
+//
+//
+//
+//
+
+/**
+ * This method is called by onAttributeSet(), which catches any AttributeConversioExceptions
+ * that may have been produced and calls reportInvalidXmlException on them.
+ * Subclasses should typically override this method rather than onAttributeSet.
+ *
+ * @param event AttributeChangeEvent
+ * @throws AttributeConversionException
+ */
+AbstractTagImpl.prototype.attributeSet = function( event ) {
+ // NO-OP
+}
+
+/**
+ * This method is included to conform to the StructureChangeListener interface.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.beforeChildAdded = function( e ) {
+//
+// if (e.getType() == StructureChangeEvent.TEXT_NODE) {
+// ResolutionHandler resolverRegistry = getUiContentHandler().getResolverRegistry();
+// try{
+// String value = (String) e.getChange();
+//
+// if (resolverRegistry.needsResolving(value)){
+// String newValue = resolverRegistry.
+// resolveTextNode(getElement(),value,e.getIndex());
+// e.setChange(newValue);
+// }
+// else{
+//
+// //if the set us to ignore escaping the call to
+// //unescape string just returns the original value
+// e.setChange(resolverRegistry.unescapeString(value));
+// }
+// }
+// catch(ResolverException ex){
+// getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+// }
+// catch(EscapeSyntaxException ex){
+// getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+// }
+// }
+}
+
+/**
+ * This method is included to conform to the StructureChangeListener interface.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.beforeChildRemoved = function( e ) {}
+
+/**
+ * Subclasses should override this method to handle dynamic addition of children.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.onChildAdded = function( e ) {}
+
+/**
+ * Subclasses should override this method to handle dynamic removal of children.
+ * Subclasses must either call super.onChildRemoved() or invoke
+ * afterChildRemoved() directly.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.onChildRemoved = function( e ) {
+ if ( e.getType() == StructureChangeEvent.ELEMENT_NODE ) {
+ this.getUiContentHandler().deregister( e.getChange() );
+ }
+}
+
+/**
+ * This must be called when a child element is removed
+ * from it's parent. This will call getUiContentHandler().deregister()
+ * which will in turn de-register the child handler as an MCO and
+ * perform recursive cleanup.
+ *
+ * @param e The StructureChangeEvent with the element being removed.
+ */
+AbstractTagImpl.prototype.afterChildRemoved = function( e ) {
+ if ( e.getType() == StructureChangeEvent.ELEMENT_NODE ) {
+ this.getUiContentHandler().deregister( e.getChange() );
+ }
+}
+
+/**
+ * This method calls attributeSet(), catches any AttributeConversioExceptions
+ * that may have been produced and calls reportInvalidXmlException on them.
+ * Subclasses should typically override attributeSet rather than this method.
+ *
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.onAttributeSet = function( e ) {
+ try {
+ this.attributeSet( e );
+ } catch( ex ) {
+ this.reportInvalidXmlException( e.getName(), e.getNewValue(),
+ this.getElement(), ex );
+ }
+}
+
+/**
+ * Subclasses should override this method to handle dynamic removal of attributes.
+ * Removal of attributes should typically revert to a default behavior and act as though
+ * the attribute had never been set.
+ *
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.onAttributeRemoved = function( e ) {}
+
+/**
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.beforeAttributeRemoved = function( e ) {}
+
+/**
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.beforeAttributeSet = function( e ) {
+// ResolutionHandler resolverRegistry = getUiContentHandler().getResolverRegistry();
+// String attributeName = e.getName();
+// String attributeValue = e.getNewValue();
+//
+// try{
+// if (resolverRegistry.needsResolving(attributeValue)){
+// String newValue = resolverRegistry.resolveAttribute(getElement(),attributeName,attributeValue);
+// e.setNewValue(newValue);
+// }
+// else{
+// e.setNewValue(resolverRegistry.unescapeString(attributeValue));
+// }
+//
+// //now that we handled escaping also handle the fact that the thing
+// //can be a url that needs to be qualified
+// attributeValue = e.getNewValue();
+//
+// String newAttributeValue = qualifyToFullUrl(attributeName, attributeValue,this);
+// if ( newAttributeValue != null && !newAttributeValue.equals(attributeValue)){
+// e.setNewValue(newAttributeValue);
+// }
+// }
+// catch(ResolverException ex){
+// getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+// }
+// catch(EscapeSyntaxException ex){
+// getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+// }
+}
+
+// /**
+// * Generate a new full url string value if the attribute value
+// * can be properly qualified into an http, https, or classpath
+// * URL, otherwise returns null.
+// *
+// * @param attributeName The name of the attribute to qualify
+// * @param attributeValue The value of the attribute to qualify
+// * @return A qualified URL or null if it was not qualifiable
+// */
+// public static String qualifyToFullUrl( String attributeName, String attributeValue,
+// AbstractTagImpl tagHandler ) {
+//
+// //if it's an object event we shouldn't qualify it!
+// if ( ((ClientSessionImpl)tagHandler.getSession()).getEventHandler().
+// qualifyObjectUrl(attributeValue)!=null){
+// return null;
+// }
+//
+// if (attributeValue.startsWith(EventHandler.CLASSPATH_PREFIX)){
+// return null;
+// }
+//
+// // little optimization
+// if ( attributeName.equals(XmlTokens.ID) || attributeName.equals(XmlTokens.TEXT) ) return null;
+//
+// if ( UrlPathUtil.isFullyFormattedUrl(attributeValue)) return null;
+//
+// for ( int i = 0; i<XmlTokens.ON_EVENT_NAMES.length; i++){
+// if ( XmlTokens.ON_EVENT_NAMES[i].equals(attributeName) ){
+// try {
+// return tagHandler.createQualifiedUrlAsString(attributeValue);
+// } catch (MalformedURLException e) {
+// e.printStackTrace();
+// }
+// }
+// }
+//
+// for ( int i = 0; i<IMG_TAG_NAMES.length; i++){
+// if ( IMG_TAG_NAMES[i].equals(attributeName)){
+// try {
+// return tagHandler.createQualifiedUrlAsString(attributeValue);
+// } catch (MalformedURLException e) {
+// e.printStackTrace();
+// }
+// }
+// }
+//
+// return null;
+// }
+//
+
+//
+//
+// private void writeBackRemoveChild(int index){
+// synchronized(getUiDocument().getDomSynchronizationObject()){
+// getElement().removeStructureChangeListener(this);
+// getElement().removeChildAt(index);
+// getElement().addStructureChangeListener(this);
+// }
+// }
+//}
+
+/**
+ * This method is used to report problems in attribute parsing
+ * in a standardized manner. Subclasses should call this if they
+ * encounter an attribute that is not formatted correctly.
+ *
+ * @param attributeName The name of the attribute.
+ * @param attributeValue The (bad) value of the attribute.
+ * @param el The element the error occured on.
+ * @param ex The exception encapsulating the error, usually an
+ * AttributeConversionException.
+ */
+AbstractTagImpl.prototype.reportInvalidXmlException = function( attributeName,
+ attributeValue, el, ex ) {
+ var exception = this.constructInvalidXmlException(
+ attributeName, attributeValue, el, ex );
+ // exception.enableShortStackTrace();
+ this.getSession().handleException( exception );
+}
+
+/**
+ * Constructs an InvalidXmlException reporting
+ * a bad attribute value; the exception is created and returned
+ * without being reported.
+ *
+ * @param attributeName The name of the attribute.
+ * @param attributeValue The (bad) value of the attribute.
+ * @param e The element the error occured on.
+ * @param ex The exception encapsulating the error, usually an
+ * AttributeConversionException.
+ * @return InvalidXmlException object
+ */
+AbstractTagImpl.prototype.constructInvalidXmlException = function( attributeName,
+ attributeValue, e, ex ) {
+ var exception = new InvalidXmlException(
+ InvalidXmlException.BAD_ATTRIBUTE_WITH_ROOT_CAUSE,
+ new Array( attributeName, attributeValue, ex.getMessage(),
+ InvalidXmlException.toString( e ),
+ InvalidXmlException.toString( e.getParent() )),
+ ex );
+ return exception;
+}
+
+AbstractTagImpl.prototype.getSession = function() {
+ return this._clientSession;
+}
+
+/**
+ * Called during initialization process.
+ */
+AbstractTagImpl.prototype.setSession = function( session ) {
+ this._clientSession = session;
+}
Propchange: incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @fileoverview PluginDocumentHandler manages creating bridge classes
+ * for tags on a single document.
+ *
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+/**
+ * Creates a new PluginDocumentHandler for the given document and document name.
+ *
+ * @class PluginDocumentHandler manages creating bridge classes
+ * for tags on a single document. PluginDocumentHandler listens for structure
+ * change events on the document it manages. When items are added anywhere
+ * in the document this handler is signalled and goes through the logic
+ * of looking up the bridge class based on the tag and namespace
+ * for the given document, instantiating the bridge class and setting it up.
+ *
+ *
+ * @param {ClientSession} clientSession The session object
+ * @param {Document} doc The document to handle
+ * @param {String} documentName The logical name of the document to handle,
+ * the name the document is registered under.
+ */
+
+function PluginDocumentHandler( clientSession, doc, documentName ) {
+ // A map of XML elements to their bridge classes.
+ this._elementsToBridges = new Hashtable();
+ // Map from peer objects back to their bridge classes that drive them
+ this._peersToBridges = new Hashtable();
+ this._clientSession = clientSession;
+ this._documentName = documentName;
+ doc._addSystemStructureChangeListener( this );
+}
+
+/** @private */
+PluginDocumentHandler.s_log = LogFactory.getLog( "PluginDocumentHandler" );
+
+
+//-----------------------------------------------------------------------
+// StructureChangeListener Implementation.
+//-----------------------------------------------------------------------
+
+/**
+ * Implements the StructureChangeListener interface -
+ * when a child is added parseChild() is called on the added Element
+ * which begins the recursive task of creating all the bridge
+ * classes for the element tree that was added to the document.
+ *
+ * @param e StructureChangeEvent
+ */
+PluginDocumentHandler.prototype.onChildAdded = function ( e ) {
+ // Technically they can replace the root node:
+ // e.getType() == StructureChangeEvent.ROOT_NODE
+ // TODO - this might be good to account for in the
+ // future , for now we don't really care
+ if( e.getType() == StructureChangeEvent.TEXT_NODE ) {
+ return;
+ }
+ this.parseChild( e.getChange() );
+}
+
+/**
+ * No-op StructureChangeListener implementation.
+ * We might want to tie this in to the dergister logic?
+ */
+PluginDocumentHandler.prototype.onChildRemoved = function( e ) {}
+
+/**
+ * No-op StructureChangeListener implementation.
+ */
+PluginDocumentHandler.prototype.beforeChildAdded = function( event ) {}
+
+/**
+ * No-op StructureChangeListener implementation.
+ */
+PluginDocumentHandler.prototype.beforeChildRemoved = function( event ) {}
+
+
+/**
+ * Called from AbstractTagImpl afterChildRemoved() to recursively
+ * clean up the removed element tree. This will de-register
+ * all the handlers as MCOs and removes them from the
+ * 2 way element<->handler mapping.
+ *
+ * @param e The element being removed from the document.
+ */
+PluginDocumentHandler.prototype.deregister = function( el ) {
+ var handler = this.getHandlerForElement( el );
+ if ( handler != null ) {
+ this._elementsToBridges.remove( el );
+
+ //TODO all handlers should have some unload or some
+ //other lifecycle notification
+ if (handler.unload){
+ handler.unload();
+ }
+ el.removeAttributeChangeListener( handler );
+ el.removeStructureChangeListener( handler );
+ }
+
+ //recursively de-register all children
+ for ( var i = 0; i < el.childNodes.length; i++ ) {
+ var child = el.childNodes[i];
+ if ( child.nodeType == DOM_ELEMENT_NODE ) {
+ this.deregister( child );
+ }
+ }
+}
+
+/**
+ * Parses an XML Element and returns a new instance of the tag-handling
+ * bridge class that the tag name was mapped to. This is called whenever a
+ * new document fragment is added to the UI document, and from
+ * parseInitialChildren() in AbstractTagImpl.
+ *
+ * @param childElement The element to parse and create the tag<->tag-handler
+ * mapping for.
+ * @return A new instance of the tag-handling class or null if no mapping exists.
+ */
+PluginDocumentHandler.prototype.parseChild = function( childElement ) {
+ var handler = null;
+
+ var pluginRegistry = this._clientSession.getPluginRegistry();
+ try {
+ //step 1: Look up the class name for this tag name,
+ //then instantiate that class instance
+ var tagName = childElement.getLocalName();
+ var namespace = childElement.getNamespaceUri();
+ var bridgeClass = pluginRegistry.getTagMapping( tagName, namespace,
+ this._documentName );
+
+ //if the implementing class name is null do what we used to do
+ //and print out an error
+ if ( bridgeClass == null ) {
+ PluginDocumentHandler.s_log.debug( "No mapping for tag name [" +
+ tagName + "] with namespace [" +
+ namespace + "] on document [" + this._documentName + "]");
+ PluginDocumentHandler.s_log.error( "No mapping found for tag " +
+ tagName + ", namespace=" + namespace );
+ return null;
+ }
+ //if it's not a string this means it is a valid tag but
+ //not mapped to a class, so just return
+ //TODO this logic needs cleanup here, the idea is to let them register
+ //tags that don't map to anything but also aren't considered errors
+ else if (( typeof bridgeClass ) != "string" ) {
+ return null;
+ }
+ var handler = null;
+
+ //now that we have the name of the bridge class, make a
+ //new one
+ try {
+ handler = eval( "new " + bridgeClass + "()" );
+ }
+ catch( ex ) {
+ PluginDocumentHandler.s_log.exception( "Exception during eval:" +
+ ex.toString() );
+ }
+
+
+ //step 2: hook up the element and the bridge class in the various
+ //hashes. Do this early to avoid problems later.
+ this.setHandlerForElement( childElement, handler );
+
+ //when we call their code they can change some stuff
+ //step 3: inject the session into the tag handler
+ handler.setSession( this._clientSession );
+
+ //step 4: if it is a structure change listener and/or attribute change listener,
+ //automatically hook it up as a listener for the source element
+
+
+ //we had an opimization here before for cells that didn't add
+ //the structure change listener since cells can't have children,
+ //we should consider generalizing that and putting it back in
+ childElement.addStructureChangeListener( handler );
+ childElement.addAttributeChangeListener( handler );
+
+
+ //step 5: call setElement(), this is the signal that the bridge
+ handler.setElement( childElement );
+ handler.init();
+
+ //finally fire the "onCreate" event
+ handler.fireEvent( "onCreate" );
+ }
+ catch( ex ) {
+ this._clientSession.handleException( new XapException("blah",null, ex,"PluginDocumentHandler.parseChild" ));
+ }
+ return handler;
+}
+
+
+
+/**
+ * Returns the tag-handling class mapped to the given Element.
+ * @param e The Element to look up the tag-handler for.
+ * @return The tag-handling class.
+ */
+PluginDocumentHandler.prototype.getHandlerForElement = function( el ){
+ return this._elementsToBridges.get( el );
+}
+
+/**
+ * For internal use only.
+ */
+PluginDocumentHandler.prototype.setHandlerForElement = function( el, tagImpl ){
+ this._elementsToBridges.put( el, tagImpl );
+}
+
+/**
+ * Sets up a mapping between a bridge tag-handler
+ * and the component it controls. This can be used to look up
+ * the bridge from the peer. For example, given a JButton
+ * to look up the subclass of SwingBridge that controls that JButton
+ * instance.<br><br>
+ * This is called automatically by ContainerBridge
+ * in setUiComponent().
+ *
+ * @param peer The controlled object.
+ * @param bridge The bridge class that controls that object.
+ */
+PluginDocumentHandler.prototype.setHandlerForPeer = function( peer, tagImpl ) {
+ this._peersToBridges.put( peer, tagImpl );
+}
+
+/**
+ * Removes the mpping between the peer and the handler.
+ * This should be called in in the AbstractTagImpl
+ * deregister() to clean up any references.
+ * @param peer The peer object to remove the mapping for.
+ */
+PluginDocumentHandler.prototype.removeHandlerForPeer = function( peer ) {
+ this._peersToBridges.remove( peer );
+}
+
+/**
+ * Returns the bridge class that controls the given component.
+ * This can be used to look up
+ * the bridge from the peer. For example, given a JButton
+ * to look up the subclass of SwingBridge that controls that JButton
+ * instance.<br><br>
+ *
+ * Note that when using Composite Components it is possible for
+ * two handlers to map to the same peer object. For example if the developer
+ * creates a "myTable" component that wraps the standard "table",
+ * both the handler for "myTable" and the handler for "table"
+ * itself control the same table peer object.
+ * @param peer The controlled object to look up the bridge for.
+ */
+PluginDocumentHandler.prototype.getHandlerForPeer = function( peer ) {
+ return this._peersToBridges.get( peer );
+}
\ No newline at end of file
Propchange: incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @fileoverview PluginRegistry keeps track of all the tags
+ * for various documents and namespaces and what they map to.
+ *
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+/**
+ * Creates a new PluginRegistry.
+ *
+ * @class PluginRegistry keeps track of all the tags
+ * for various documents and namespaces and what they map to. Currently
+ * this class maps tags to bridge class names without any regard for
+ * namespace or document name. In the future it needs to allow the same
+ * tag name to have different meaning depending on namespace and the document
+ * the tag appears in. TODO
+ *
+ */
+function PluginRegistry() {
+
+ this._tagToBridgeClassName = new Hashtable();
+
+ //zimbra components
+ this._tagToBridgeClassName.put( "panel", "DwtCompositeBridge" );
+ this._tagToBridgeClassName.put( "label", "DwtLabelBridge" );
+ this._tagToBridgeClassName.put( "button", "DwtButtonBridge" );
+ this._tagToBridgeClassName.put( "tabPane", "DwtTabViewBridge" );
+ this._tagToBridgeClassName.put( "tab", "DwtTabBridge" );
+ this._tagToBridgeClassName.put( "splitPane", "DwtSplitterBridge" );
+ this._tagToBridgeClassName.put( "left", "DwtSplitChildBridge" );
+ this._tagToBridgeClassName.put( "right", "DwtSplitChildBridge" );
+ this._tagToBridgeClassName.put( "top", "DwtSplitChildBridge" );
+ this._tagToBridgeClassName.put( "bottom", "DwtSplitChildBridge" );
+ this._tagToBridgeClassName.put( "tree", "DwtTreeBridge" );
+ this._tagToBridgeClassName.put( "treeItem", "DwtTreeItemBridge" );
+ this._tagToBridgeClassName.put( "textField", "DwtTextFieldBridge" );
+ this._tagToBridgeClassName.put( "verticalLayoutPanel", "DwtVerticalLayoutPanelBridge" );
+ this._tagToBridgeClassName.put( "horizontalLayoutPanel", "DwtHorizontalLayoutPanelBridge" );
+
+ //basic components
+ this._tagToBridgeClassName.put( "textView", "TextViewBridge" );
+
+ //add custom tags here
+ this._tagToBridgeClassName.put( "gMap", "GoogleMapBridge" );
+ this._tagToBridgeClassName.put( "infoWindow", "GoogleInfoWindowBridge" );
+ this._tagToBridgeClassName.put( "marker", "GoogleMarkerBridge" );
+ this._tagToBridgeClassName.put( "markers", "GoogleMarkersBridge" );
+ this._tagToBridgeClassName.put( "icons", "GoogleIconsBridge" );
+ this._tagToBridgeClassName.put( "icon", "GoogleIconBridge" );
+}
+
+/**
+ * Given the tag name, namespace uri and the document name that tag appears in,
+ * return the bridge class name that the tag/namespace/document maps to,
+ * if any.
+ */
+PluginRegistry.prototype.getTagMapping = function( tagName, nameSpace, documentName ) {
+ return this._tagToBridgeClassName.get( tagName );
+}
Propchange: incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @fileoverview Work in progress.
+ *
+ * @author jmargaris
+ *
+ */
+
+
+/**
+ * A constructor.
+ *
+ * @class This is going to replace the functionality in PluginRegistry (perhaps
+ * with a rename). This class is responsible for parsing a plugin mapping file
+ * and setting up the proper mappings. A plugin mapping file defines
+ * tags that map to classes. Each entry applies to a single namespace
+ * and to a single document. For example, the <button> tag would apply
+ * to the UI namespace and the UI document. Using button without the UI namespace
+ * or outside of the UI document would have no effect.
+ *
+ * It is also possible to have a tag map to no class. That way we will not
+ * report the tag as unrecognized.
+ */
+
+
+
+function PluginRegistryImpl( session ){
+ this._pluginLifecycleObjects = new Array();
+ this._tagDefinitions = new Hashtable();
+ this._tagMappings = new Hashtable();
+ this._session = session;
+}
+
+PluginRegistryImpl.s_log = LogFactory.getLog( "PluginRegistryImpl" );
+
+PluginRegistryImpl.TAG_MAPPINGS_PATH = "/plugin/tag-mappings";
+
+PluginRegistryImpl.UNMAPPED_TAGS_PATH = "/plugin/unmapped-tags"
+
+PluginRegistryImpl.PLUGIN_LIFECYCLE_CLASS_PATH = "/plugin/@class";
+
+PluginRegistryImpl.NO_MAPPED_CLASS = new Object();
+
+
+//TODO would this whole thing make more sense as a generic namespace
+//handler?? Or instead of parsing XML just have js code do this directly?
+//is the overhead of XML configuration worth it? simpler?
+
+/**
+ * Adds a plug-in decription file.
+ *
+ * @param fileContents a String representing the actual content (NOT path)
+ * of the description file
+ */
+PluginRegistryImpl.prototype.addPluginDescription = function( fileContents ){
+
+ PluginRegistryImpl.s_log.debug("Add plugin description");
+ var parser = new SaxParser( new SaxContentHandler() );
+ var pluginDocument = null;
+
+ try{
+ pluginDocument = parser.parse( fileContents );
+ }
+ catch( exception ){
+ this._session.handleException( exception );
+ return;
+ }
+
+
+ //TODO this returs what an array of nodes?
+ var tagMappingSections =
+ xpathDomEval(PluginRegistryImpl.TAG_MAPPINGS_PATH , pluginDocument);
+ PluginRegistryImpl.s_log.debug(tagMappingSections.value.length + " mapped tags");
+ this._parseTagMappingElements(tagMappingSections.value,true);
+
+ PluginRegistryImpl.s_log.debug("Parse unmapped tags");
+ tagMappingSections =
+ xpathDomEval(PluginRegistryImpl.UNMAPPED_TAGS_PATH , pluginDocument);
+ PluginRegistryImpl.s_log.debug(tagMappingSections.value.length + " unmapped tags");
+ this._parseTagMappingElements(tagMappingSections.value,false);
+
+ //TODO this returns an array but we want a string, get the first element node value?
+ var lifecycleClassName =
+ xpathDomEval(PluginRegistryImpl.PLUGIN_LIFECYCLE_CLASS_PATH , pluginDocument).value[0];
+
+ PluginRegistryImpl.s_log.debug("lifecycle class = " + lifecycleClassName);
+
+ if (lifecycleClassName && lifecycleClassName.length >0){
+ try{
+ //TODO we need a generic "load this bean" type of method
+ var lifecycleObject = eval("new " + lifecycleClassName + "()");
+
+ //TODO maybe we should just have a container for lifecycle objects
+ //so that you can look them up and the notification is done via
+ //standard container mechanism? Allow them to assign IDs etc?
+ if (lifecycleObject.pluginLoaded){
+ lifcycleObject.pluginLoaded(this._session);
+ }
+
+ //TODO call unloaded when unloaded?
+ this._pluginLifecycleObjects.push(lifecycleObject);
+ }
+ catch( exception ){
+ this._session.handleException( exception );
+ }
+ }
+}
+
+/**
+ * Returns the original definition element that came from the tag-mapping/
+ * plugin file representing this tag/namespace combo
+ */
+PluginRegistryImpl.prototype.getPluginDefinition = function( tagName, nameSpace, documentName){
+ this._tagDefinitions.get(PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName));
+}
+
+
+/**
+ * This will return one of three things:
+ * 1: A string representing the class name
+ * 2: null, indicating unmapped
+ * 3: A non-string object, indicating unmapped purposely
+ */
+PluginRegistryImpl.prototype.getTagMapping = function(tagName, nameSpace, documentName){
+ return this._tagMappings.get(PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName));
+}
+
+
+
+/**
+ * Does the work of parsing the main tag-mapping blocks
+ * @param tagMappingSections The array of elements representing
+ * tag-mapping and unmapped-tags roots
+ * @param isMappedTag if true, each item should map to a class
+ */
+PluginRegistryImpl.prototype._parseTagMappingElements = function(tagMappingSections, isMappedTag){
+
+ //for each tag in the block
+ for (var section =0; section<tagMappingSections.length; section++){
+ var tagMappingRoot = tagMappingSections[section];
+
+ var documentName = tagMappingRoot.getAttribute("document");
+ if (documentName==null){
+ documentName = DocumentContainer.UI_DOCUMENT_NAME;
+ }
+ var nameSpace = tagMappingRoot.getAttribute("namespace");
+
+ //for each child of that tag in the block
+ for (var i = 0; i<tagMappingRoot.childNodes.length; i++){
+ var tagElement = tagMappingRoot.childNodes[i];
+
+ var className = null;
+ var tagName = null;
+
+ //v2 syntax:
+ //<mapping name="pieChart" class="piechart.PieChartBridge"/>
+ if (tagElement.getLocalName()=="mapping"){
+ tagName = tagElement.getAttribute("name");
+
+ if (tagName==null || tagName.length==0){
+ //TODO report exception
+ continue;
+ }
+
+ if (isMappedTag){
+ className = tagElement.getAttribute("class");
+ if (className==null || className.length==0){
+ //TODO report exception
+ continue;
+ }
+ }
+ //if we aren't supposed to be mapped to anything
+ //don't look for class
+ else{
+ className = PluginRegistryImpl.NO_MAPPED_CLASS
+ }
+ }
+ else{
+ //TODO report exception
+
+ }
+
+ PluginRegistryImpl.s_log.debug("Add tag mapping:" + tagName + ":" + className);
+ this._addTagMapping(tagName,className,nameSpace,documentName,tagElement);
+ }
+ }
+}
+
+
+PluginRegistryImpl.prototype.toString = function(){
+ return this._tagMappings.toString();
+}
+/**
+ * @param {String} tagName The name of the tag
+ * @param {Object} className The name of the class or the special NO_MAPPED_CLASS object
+ * @param {String} nameSpace The namespace URI.
+ * @param {String} documentName The name of the document the tag applies to
+ * @param {XapElement} originalDefinition The tag definition element
+ */
+PluginRegistryImpl.prototype._addTagMapping = function( tagName, className, nameSpace,
+ documentName, originalDefinition){
+
+ //error: duplicate tag name
+ if (this.getTagMapping(tagName,nameSpace,documentName)!=null){
+ //TODO report exception but overwrite
+ }
+
+ var hashKey = PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName);
+ this._tagMappings.put(hashKey,className);
+ this._tagDefinitions.put(hashKey,originalDefinition);
+}
+
+
+
+
+
+PluginRegistryImpl._createHashtableKey = function(tagName, nameSpace, documentName){
+//TODO we should consider no namespace the same as default?
+//if so make that work for stylsheets, xupdate, etc
+//if (nameSpace == null) {
+// nameSpace = "http://xal.org/xal";
+// }
+ return tagName + ":" + nameSpace + ":" + documentName;
+}
Propchange: incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/src/xap/taghandling/plugin.xml
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/plugin.xml?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/plugin.xml (added)
+++ incubator/xap/trunk/src/xap/taghandling/plugin.xml Thu Jun 22 15:59:35 2006
@@ -0,0 +1,31 @@
+<plugin>
+ <!-- mappings that apply to the document named "dataSources" -->
+ <tag-mappings namespace="http://www.openxal.org/xal" document="xal">
+ <mapping class="DwtCompositeBridge" name="panel"/>
+ <mapping class="DwtLabelBridge" name="label"/>
+ <mapping class="DwtButtonBridge" name="button"/>
+ <mapping class="DwtTabViewBridge" name="tabPane"/>
+ <mapping class="DwtTabBridge" name="tab"/>
+ <mapping class="DwtSplitterBridge" name="splitPane"/>
+ <mapping class="DwtSplitChildBridge" name="left"/>
+ <mapping class="DwtSplitChildBridge" name="right"/>
+ <mapping class="DwtSplitChildBridge" name="top"/>
+ <mapping class="DwtSplitChildBridge" name="bottom"/>
+ <mapping class="DwtTreeBridge" name="tree"/>
+ <mapping class="DwtTreeItemBridge" name="treeItem"/>
+ <mapping class="DwtTextFieldBridge" name="textField"/>
+ <mapping class="DwtVerticalLayoutPanelBridge" name="verticalLayoutPanel"/>
+ <mapping class="DwtHorizontalLayoutPanelBridge" name="horizontalLayoutPanel"/>
+
+ <mapping class="TextViewBridge" name="textView"/>
+ </tag-mappings>
+
+ <tag-mappings namespace="http://www.google.com" document="xal">
+ <mapping class="GoogleMapBridge" name="gMap"/>
+ <mapping class="GoogleInfoWindowBridge" name="infoWindow"/>
+ <mapping class="GoogleMarkerBridge" name="marker"/>
+ <mapping class="GoogleMarkersBridge" name="markers"/>
+ <mapping class="GoogleIconsBridge" name="icons"/>
+ <mapping class="GoogleIconBridge" name="icon"/>
+ </tag-mappings>
+</plugin>
Propchange: incubator/xap/trunk/src/xap/taghandling/plugin.xml
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/xap/trunk/testsrc/XapUnitTestSuite.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/XapUnitTestSuite.html?rev=416494&r1=416493&r2=416494&view=diff
==============================================================================
--- incubator/xap/trunk/testsrc/XapUnitTestSuite.html (original)
+++ incubator/xap/trunk/testsrc/XapUnitTestSuite.html Thu Jun 22 15:59:35 2006
@@ -44,12 +44,12 @@
return result;
}
- function tagsSuite( webappContext ) {
+ function taghandlingSuite( webappContext ) {
var result = new top.jsUnitTestSuite();
- result.addTestPage( webappContext + "/testsrc/xap/tags/_TestPluginRegistryImpl.html" );
- result.addTestPage( webappContext + "/testsrc/xap/tags/_TestAbstractTagImpl.html" );
- result.addTestPage( webappContext + "/testsrc/xap/tags/_TestPluginDocumentHandler.html" );
- // result.addTestPage( webappContext + "/testsrc/xap/tags/_TestUiDocumentHandler.html" );
+ result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestPluginRegistryImpl.html" );
+ result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestAbstractTagImpl.html" );
+ result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestPluginDocumentHandler.html" );
+ // result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestUiDocumentHandler.html" );
return result;
}
@@ -65,7 +65,7 @@
var webappContext = "/jsunit";
//suite.addTestSuite( testSuite( webappContext ));
- suite.addTestSuite( tagsSuite( webappContext ) );
+ suite.addTestSuite( taghandlingSuite( webappContext ) );
suite.addTestSuite( utilSuite( webappContext ) );
suite.addTestSuite( xmlSuite( webappContext ) );
suite.addTestSuite( mcoSuite( webappContext ) );
Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>ClientSession Unit Tests</title>
+ <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+ <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+ <script language="JavaScript" type="text/javascript">
+ Xap.bootstrap( "/jsunit" );
+ </script>
+</head>
+
+<body>
+ <script language="JavaScript" type="text/javascript">
+ function testAbstractTagImplMethods() {
+ var bridge = new AbstractTagImpl();
+ assertTrue( bridge != null );
+ assertTrue( bridge.setSession != null );
+ }
+ </script>
+</body>
+</html>
\ No newline at end of file
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>ClientSession Unit Tests</title>
+ <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+ <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+ <script language="JavaScript" type="text/javascript">
+ Xap.bootstrap( "/jsunit" );
+ </script>
+
+</head>
+
+<body>
+ <script language="JavaScript" type="text/javascript">
+ function testPluginDocumentHandlerMethods() {
+ DBG = new AjxDebug( AjxDebug.NONE, null, false );
+ var session = new ClientSession( "/xap" );
+ }
+ </script>
+</body>
+</html>
\ No newline at end of file
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Element Unit Tests</title>
+ <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+ <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+ <script language="JavaScript" type="text/javascript" src="_TestPluginRegistryImpl.js"></script>
+
+
+</head>
+
+<body>
+ <script language="JavaScript" type="text/javascript">
+ Xap.bootstrap( "/jsunit" );
+ </script>
+</body>
+</html>
\ No newline at end of file
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+function exposeTestFunctionNames() {
+ return ["testAddPluginDescription"];
+}
+
+
+function testAddPluginDescription() {
+ var pluginRegistry = new PluginRegistryImpl(null);
+ var pluginString = HttpUtils.get( "/jsunit/testsrc/xap/taghandling/plugin.xml").responseText;
+ pluginRegistry.addPluginDescription(pluginString);
+
+ var tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data", "dataSources");
+ assertTrue("tag mapping for objectDataSource is com.nexaweb.plugin.data.bridge.DocumentDataSourceBridge",
+ tagMapping=="com.nexaweb.plugin.data.bridge.ObjectDataSourceBridge");
+
+ tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data1", "dataSources");
+ assertTrue("tag mapping for objectDataSource with wrong namespace is null",
+ tagMapping==null);
+
+ tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data", "dataSources1");
+ assertTrue("tag mapping for objectDataSource with wrong document is null",
+ tagMapping==null);
+
+ tagMapping = pluginRegistry.getTagMapping("iteratorPlaceHolder",null,"xal");
+ assertTrue("tag mapping for iteratorPlaceHolder is special item",
+ tagMapping==PluginRegistryImpl.NO_MAPPED_CLASS);
+}
\ No newline at end of file
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>ClientSession Unit Tests</title>
+ <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+ <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+ <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+ <script language="JavaScript" type="text/javascript">
+ Xap.bootstrap( "/jsunit" );
+ </script>
+</head>
+
+<body>
+ <script language="JavaScript" type="text/javascript">
+ function testUiDocumentHandlerMethods() {
+ var session = new ClientSession( "/xap" );
+ }
+ </script>
+</body>
+</html>
\ No newline at end of file
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml Thu Jun 22 15:59:35 2006
@@ -0,0 +1,49 @@
+<plugin>
+ <!-- mappings that apply to the document named "dataSources" -->
+ <tag-mappings namespace="http://nexaweb.com/data" document="dataSources">
+ <mapping class="com.nexaweb.plugin.data.bridge.DocumentDataSourceBridge"
+ name="documentDataSource"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.ObjectDataSourceBridge"
+ name="objectDataSource"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.DataSourceBridge"
+ name="dataSource"/>
+ </tag-mappings>
+
+ <!-- mappings that apply to the document named "bindings" -->
+ <tag-mappings namespace="http://nexaweb.com/data" document="bindings">
+ <mapping class="com.nexaweb.plugin.data.bridge.BindingBridge"
+ name="binding"/>
+ </tag-mappings>
+
+ <!-- mappings that apply to the document named "formatters" -->
+ <tag-mappings namespace="http://nexaweb.com/data" document="formatters">
+ <mapping class="com.nexaweb.plugin.data.bridge.FormatterBridge"
+ name="formatter"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.MessageFormatterBridge"
+ name="messageFormatter"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.DecimalFormatterBridge"
+ name="decimalFormatter"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.CurrencyFormatterBridge"
+ name="currencyFormatter"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.DateFormatterBridge"
+ name="dateFormatter"/>
+ <mapping
+ class="com.nexaweb.plugin.data.bridge.StringToDateFormatterBridge"
+ name="stringToDateFormatter"/>
+ <mapping class="com.nexaweb.plugin.data.bridge.FormatterChainBridge"
+ name="formatterChain"/>
+ </tag-mappings>
+
+ <!-- mappings that apply to the ui document -->
+ <tag-mappings namespace="http://nexaweb.com/data">
+ <mapping class="com.nexaweb.plugin.data.bridge.IteratorBridge"
+ name="iterator"/>
+ </tag-mappings>
+
+ <!-- The iteratorPlaceHolder element is used to keep track of the spot
+ an iterator with an empty dataset will be contributing to. -->
+ <unmapped-tags>
+ <mapping name="iteratorPlaceHolder"/>
+ </unmapped-tags>
+
+</plugin>
Propchange: incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml
------------------------------------------------------------------------------
svn:eol-style = native