Changeset 204

Show
Ignore:
Timestamp:
12/27/09 07:26:39 (8 months ago)
Author:
scott
Message:

Basic functioning features in XMVC

  • Dispatch, attachment, etc. all "work" in firefox.
  • Cleaned up debugging code.
  • Fixed numerous bugs which come from writing lots of code without ever running the program.

IE Portability for Joice:

  • Removed all use of namespaces.
  • Removed reliance on Node.
  • Dropped String.prototype.format in favor of String.prototype.sprintf (temporarily, there is an apparent bug in String.prototype.format)
  • Added call-once handler to JoiceLoader?.
  • Fixed small big in HttpJavaScriptLoader?.
Location:
xmvc/branches/remove-namespaces
Files:
1 added
11 modified

Legend:

Unmodified
Added
Removed
  • xmvc/branches/remove-namespaces/example.html

    r201 r204  
    22  <head> 
    33    <title>A Joice Example</title> 
     4    <!-- 
    45    <script type="text/javascript" src="everything.js"></script> 
    5     <!-- 
     6    --> 
    67    <script type="text/javascript" src="src/main/javascript/compat/jdc-1.0.3.js"></script> 
    78    <script type="text/javascript" src="src/main/javascript/compat/javeline_xpath.js"></script> 
    89    <script type="text/javascript" src="src/main/javascript/compat/javeline_xslt.js"></script> 
    910    <script type="text/javascript" src="src/main/javascript/compat/sarissa.js"></script> 
     11    <script type="text/javascript" src="src/main/javascript/compat/sarissa_ieemu_xpath.js"></script> 
     12    <script type="text/javascript" src="src/main/javascript/compat/nodetypes.js"></script> 
    1013    <script type="text/javascript" src="src/main/javascript/contrib/jitloader.js"></script> 
    1114    <script type="text/javascript" src="src/main/javascript/string/format.js"></script> 
     15    <script type="text/javascript" src="src/main/javascript/string/sprintf.js"></script> 
    1216    <script type="text/javascript" src="src/main/javascript/array/each.js"></script> 
    1317    <script type="text/javascript" src="src/main/javascript/util/HttpClient.js"></script> 
     
    2125    <script type="text/javascript" src="src/main/javascript/joice/Loader.js"></script> 
    2226    <script type="text/javascript" src="src/main/javascript/joice/Bootstrap.js"></script> 
    23     --> 
    2427 
    2528    <!-- 
  • xmvc/branches/remove-namespaces/example.js

    r201 r204  
    1414 
    1515    this.feature = function () { 
    16         window.alert("And you can also: \f".format("click")) 
     16        window.alert("And you can also: %s".sprintf(this.test)) 
    1717    } 
    1818} 
     
    2828} 
    2929 
     30/* 
    3031var hello = document.getElementById("hello") 
    3132 
     
    4142    baz.print() 
    4243} 
     44*/ 
    4345 
    4446function Greeter () { 
  • xmvc/branches/remove-namespaces/example.xml

    r201 r204  
    44  <!-- text/javascript;debug runs the IE-incompatible jit loader which keeps 
    55  track of the actual source location... --> 
    6   <script type="text/javascript" src="src/main/javascript/xmvc/ControllerScope.js"/> 
    7   <script type="text/javascript" src="src/main/javascript/xmvc/Transformer.js"/> 
    8   <script type="text/javascript" src="src/main/javascript/xmvc/Configuration.js"/> 
     6  <script type="text/javascript;debug" src="src/main/javascript/xmvc/ControllerScope.js"/> 
     7  <script type="text/javascript;debug" src="src/main/javascript/xmvc/Transformer.js"/> 
     8  <script type="text/javascript;debug" src="src/main/javascript/xmvc/Configuration.js"/> 
    99 
    1010  <script type="text/javascript;debug" src="example.js"/> 
     
    3434  </object> 
    3535 
    36   <object id="controller" constructor="Controller" initialization="eager"> 
     36  <object id="controller" constructor="XMLController" initialization="eager"> 
    3737    <argument> 
    3838      <xml> 
    3939        <controller> 
     40          <node id="hello"> 
     41            <action type="click" object="foo" method="hello"/> 
     42          </node> 
     43 
     44          <node id="list"> 
     45            <action type="click" object="baz" method="print"/> 
     46          </node> 
     47 
     48          <!-- 
    4049          <node id="ping"> 
    4150            <action type="click" object="greeter" handler="hello"> 
    42               <transformer type="xslt" path="//body" behavior="append" 
     51              <transform type="xslt" path="//body" behavior="append" 
    4352                  src="example.xsl"> 
    4453                <param name="message" value="Hello, world"/> 
     
    5059            <action type="click" object="greeter" handler="goodbye"/> 
    5160          </node> 
     61          --> 
    5262        </controller> 
    5363      </xml> 
  • xmvc/branches/remove-namespaces/src/main/javascript/compat/sarissa_ieemu_xpath.js

    r94 r204  
    135135    * @throws An error if no namespace URI is found for the given prefix. 
    136136    */ 
     137    HTMLDocument.prototype.selectNodes = 
    137138    XMLDocument.prototype.selectNodes = function(sExpr, contextNode, returnSingle){ 
    138139        var nsDoc = this; 
     
    181182    *             available to XML Elements. 
    182183    */ 
     184    HTMLElement.prototype.selectNodes = 
    183185    Element.prototype.selectNodes = function(sExpr){ 
    184186        var doc = this.ownerDocument; 
     
    197199    * @returns the result of the XPath search as an (Sarissa)NodeList 
    198200    */ 
     201    HTMLDocument.prototype.selectSingleNode = 
    199202    XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode){ 
    200203        var ctx = contextNode?contextNode:null; 
     
    208211    *             available to XML Elements. 
    209212    */ 
     213    HTMLElement.prototype.selectSingleNode = 
    210214    Element.prototype.selectSingleNode = function(sExpr){ 
    211215        var doc = this.ownerDocument; 
  • xmvc/branches/remove-namespaces/src/main/javascript/joice/Context.js

    r201 r204  
    109109 
    110110    for (var i = 0; i < argumentCount; i++) { 
    111         params.push("arguments[\f]".format(i)) 
    112     } 
    113  
    114     var code = "return new \f(\f)".format(methodName, params.join(",")) 
     111        params.push("arguments[%d]".sprintf(i)) 
     112    } 
     113 
     114    var code = "return new %s(%s)".sprintf(methodName, params.join(",")) 
    115115 
    116116    try { 
     
    301301            var specificationCount = specifications.length 
    302302 
    303             window.alert("Specifications: " + specificationCount) 
    304  
    305303            for (var i = 0; i < specificationCount; i++) { 
    306304                var specification = specifications[i] 
     
    312310                 * someone finds a reason to try that. */ 
    313311                if (specification.init == "eager") { 
    314                     window.alert("Initting: " + specification.id) 
    315312                    this.getObject(specification.id) 
    316313                } 
  • xmvc/branches/remove-namespaces/src/main/javascript/joice/ContextConfiguration.js

    r201 r204  
    139139    var specs       = {} 
    140140    var loaders     = { 
    141         "text/javascript": new DocumentWriteScriptLoader(semaphore), 
     141        "text/javascript": new HttpJavaScriptLoader(semaphore), 
    142142        "text/javascript;debug": new JITLoader(semaphore) 
    143143    } 
     
    202202         */ 
    203203        var doc = element.ownerDocument 
    204         var arrayObject = doc.createElementNS(JOICENS, JOICENS_OBJECT) 
     204        var arrayObject = doc.createElement(JOICENS_OBJECT) 
    205205 
    206206        arrayObject.setAttribute("constructor", "Array") 
     
    214214             * bunch of elements that only have text nodes in them.  Another 
    215215             * way to do this would be to check the node type. ;-) */ 
    216             if (child.namespaceURI == JOICENS) { 
    217                 var argument = doc.createElementNS(JOICENS, JOICENS_ARGUMENT) 
     216            if (child.nodeType == ELEMENT_NODE) { 
     217                var argument = doc.createElement(JOICENS_ARGUMENT) 
    218218 
    219219                if (hasAttribute(child, "object")) { 
     
    235235 
    236236    function Context_parseProperty (element) { 
    237         if (hasAttribute(element, "value")) { 
    238             return new PropertySpecification("value", 
    239                 element.getAttribute("value")) 
    240         } 
    241         else if (hasAttribute(element, "object")) { 
    242             return new PropertySpecification("object", 
    243                 vivifyObject(element.getAttribute("object"))) 
     237        var value  = element.getAttribute("value") 
     238        var object = element.getAttribute("object") 
     239 
     240        if (value != undefined) { 
     241            return new PropertySpecification("value", value) 
     242        } 
     243        else if (object != undefined) { 
     244            return new PropertySpecification("object", vivifyObject(object)) 
    244245        } 
    245246        else if (element.hasChildNodes()) { 
     
    251252                var child = children[i] 
    252253 
    253                 if (child.namespaceURI == JOICENS) switch (child.tagName) { 
     254                if (child.nodeType == ELEMENT_NODE) switch (child.tagName) { 
    254255                    case JOICENS_OBJECT: 
    255256                        /* {} is just new Object(), I'm assuming that's true on 
     
    280281                    case JOICENS_XML: 
    281282                        matches++ 
     283 
     284                        /* Select the first child element node as the root. */ 
     285                        if (child.hasChildNodes()) { 
     286FIRST_CHILD:                for (var node = child.firstChild; 
     287                                     node != null; 
     288                                     node = node.nextSibling) 
     289                            { 
     290                                if (node.nodeValue == ELEMENT_NODE) { 
     291                                    child = node 
     292                                    break FIRST_CHILD 
     293                                } 
     294                            } 
     295                        } 
     296 
    282297                        result = new PropertySpecification("value", 
    283298                                child) 
     
    377392    this.parseConfig = function (config) { 
    378393        var possibleObjects = config.childNodes 
    379         var elements = [] 
    380394 
    381395        for (var i = 0; i < possibleObjects.length; i++) { 
    382396            var possibleObject = possibleObjects[i] 
    383397 
    384             if (possibleObject.namespaceURI == JOICENS && 
     398            if (possibleObject.nodeType == ELEMENT_NODE && 
    385399                    possibleObject.tagName == JOICENS_SCRIPT) { 
    386400                Context_parseScript(possibleObject) 
    387401            } 
    388402 
    389             if (possibleObject.namespaceURI == JOICENS && 
     403            if (possibleObject.nodeType == ELEMENT_NODE && 
    390404                    possibleObject.tagName == JOICENS_OBJECT) { 
    391405                Context_parseObject(possibleObject) 
    392406            } 
    393  
    394             elements.push("Not possible object {" + 
    395                     possibleObject.namespaceURI 
    396                     +"}"+ 
    397                     possibleObject.localName 
    398                     + " IE sucks " + 
    399                     possibleObject.tagName) 
    400         } 
    401  
    402         window.alert(elements.join("\n")) 
     407        } 
    403408 
    404409        for (var key in specs) { 
  • xmvc/branches/remove-namespaces/src/main/javascript/joice/Loader.js

    r201 r204  
    3232        request.send(null) 
    3333 
     34        var dispatch = true 
     35 
    3436        request.onreadystatechange = function () { 
    3537            /* TODO: Fix this is done in too many places, consolidate */ 
     
    4446                    case 200: 
    4547                    case 0: 
    46                         window.alert("Fetched configuration") 
    47                         callback(request.responseXML, request.responseText) 
     48                        /* Only dispatch the callback once */ 
     49                        if (dispatch) { 
     50                            callback(request.responseXML, request.responseText) 
     51                            dispatch = false 
     52                        } 
    4853                } 
    4954            } 
  • xmvc/branches/remove-namespaces/src/main/javascript/string/format.js

    r123 r204  
    33 */ 
    44 
     5/* There is a bug in IE here for some reason, the string values never get 
     6 * substituted and the original string (less escaped characters) is returned.. 
     7 */ 
    58String.prototype.format = function () { 
    69    if (!arguments.length) return this.toString() 
  • xmvc/branches/remove-namespaces/src/main/javascript/util/ScriptLoader.js

    r201 r204  
    4646 
    4747                var source = request.responseText 
    48                 var code   = null 
    4948 
    5049                try { 
    51                     global.eval(source) 
     50                    window.eval(source) 
    5251                } 
    5352                catch (error) { 
     
    103102 
    104103            script.onreadystatechange = function () { 
    105                 if (this.readyState == "complete") { 
     104                window.alert("ready state: " + this.readyState) 
     105                if (/complete|loaded/.test(this.readyState)) { 
     106                    semaphore.release() 
     107 
    106108                    loader.onload() 
    107109                } 
    108110            } 
    109111 
     112            script.onload = function () { 
     113                semaphore.release() 
     114 
     115                loader.onload() 
     116            } 
     117 
     118            document.body.appendChild(script) 
     119/* 
    110120            this.onload() 
    111  
    112             semaphore.release() 
     121            */ 
    113122        } 
    114123    } 
  • xmvc/branches/remove-namespaces/src/main/javascript/xmvc/Configuration.js

    r201 r204  
     1 
     2function XMLController (configuration) { 
     3    var controller   = new Controller(window.document) 
     4    var configparser = new XMVCConfigParser(controller) 
     5 
     6    configparser.parse(configuration) 
     7} 
    18 
    29function XMVCConfigParser (controller) { 
     
    4956    } 
    5057 
    51     this._buildAction = function (observer) { 
     58    this._buildAction = function (action, observer) { 
    5259        return controller.createAction( 
    5360            action.getAttribute("object"), 
     
    6269        /* TODO: I think this is all out of date... */ 
    6370        if (node.hasAttribute("id")) { 
    64             window.alert("ID node") 
    6571            locateType = "id" 
    6672            locatePath = node.getAttribute("id") 
    6773        } 
    68         else if (node.hasAttribute("context")) { 
    69             window.alert("context node") 
     74        else if (node.hasAttribute("path")) { 
    7075            locateType = "xpath" 
    71             locatePath = node.getAttribute("context") 
     76            locatePath = node.getAttribute("path") 
    7277        } 
    7378        else if (node.hasAttribute("type")) { 
    74             window.alert("type node") 
    75             locateType = node.getAttribute("locator") 
    76             locatePath = node.getAttribute("path") 
     79            locateType = node.getAttribute("type") 
     80            locatePath = node.getAttribute("expression") 
     81        } 
     82        else { 
     83            throw new Error("Invalid node expression, must have both " + 
     84                    "type and expression attributes") 
    7785        } 
    7886 
     
    8290    this._buildSelection = function (node) { 
    8391        var locator   = this._buildLocator(node) 
     92 
    8493        var selection = controller.createSelection(locator) 
    8594 
     
    9099            if (child.tagName == "action") { 
    91100                /* TODO: Support multiple transform observers through the 
    92                  * listable transform interface. */ 
     101                 * listable transform interocument) 
     102    context.addScope("document", documentScoface. */ 
    93103                var transform = this._nextTransformNode(child) 
    94104                var observer  = null 
     
    118128             node = node.nextSibling) 
    119129        { 
    120             if (node.type == Node.ELEMENT_NODE) { 
     130            if (node.nodeType == ELEMENT_NODE) { 
    121131                if (node.tagName == "node") { 
    122132                    selections.push(this._buildSelection(node)) 
     
    128138    } 
    129139 
    130     this.parse = function (element) { 
    131         if (element.type == Node.DOCUMENT_NODE) { 
    132             element = element.documentElement 
     140    /** 
     141     * Parse a document (or fragment) 
     142     * 
     143     * <p>This expects a DOM node which is either the <em>document</em> element 
     144     * of a controller specification, or an element which contains a controller 
     145     * specification.  It configures the controller this XMVCConfigParser 
     146     * wraps.</p> 
     147     */ 
     148    this.parse = function (node) { 
     149        var selections = [] 
     150 
     151        for (var node = node.firstChild; 
     152                 node != null; 
     153                 node = node.nextSibling) 
     154        { 
     155            if (node.nodeType == ELEMENT_NODE) { 
     156                if (node.tagName == "controller") { 
     157                    selections = this._parseNodes(node) 
     158                } 
     159            } 
    133160        } 
    134161 
    135         var selections = this._parseNodes(element) 
     162        for (var i = 0; i < selections.length; i++) { 
     163            controller.addSelection(selections[i]) 
     164        } 
    136165    } 
    137166} 
  • xmvc/branches/remove-namespaces/src/main/javascript/xmvc/Transformer.js

    r201 r204  
    2222 
    2323function Controller (document) { 
    24     window.alert("I think this is what's all messed up...") 
    2524    if (typeof document == "undefined") { 
    2625        document = globalDocument 
    27         window.alert("YO!") 
    28     } 
    29  
    30     window.alert(document) 
     26    } 
     27 
     28    this.document = document 
    3129 
    3230    var selections    = [] 
    3331    var mustWalk      = false 
    3432    var walkObservers = [] 
     33 
     34    /* TODO I think the static id/xpath initialization is temporary */ 
     35    var locators      = { 
     36        "id": FastIdLocator, 
     37        "xpath": XPathLocator 
     38    } 
    3539 
    3640    /* TODO: Debug document scope... 
     
    6771    } 
    6872 
    69     var handleProcessing = function (element) { 
     73    var handleProcessing = function (node) { 
    7074        /* Walk the node if we have stuff to do... */ 
    7175        if (walkObservers.length) { 
    72             this.walk(element) 
     76            this.walk(node) 
    7377        } 
    7478 
    7579        selections.each(function (selection) { 
    76             selection.attach(element) 
     80            selection.attach(node) 
    7781        }) 
    7882    } 
    7983 
    8084    /** 
    81      * Process a given element (and it's descendants). 
    82      */ 
    83     this.process = function (element) { 
     85     * Process a given node (and it's descendants). 
     86     */ 
     87    this.process = function (node) { 
    8488        var controller = this 
    8589         
     
    9094         * or something (like joice). */ 
    9195        window.setTimeout(function () { 
    92             handleProcessing.call(controller, element) 
     96            handleProcessing.call(controller, node) 
    9397        }, 1) 
     98    } 
     99 
     100    /** 
     101     * Add a new locator. 
     102     * 
     103     * <p>Given a type and a constructor, register the given constructor as a 
     104     * factory for locators of the given type.  Constructors are expected to 
     105     * accept the arguments <code>({@link Controller} controller, 
     106     * {@link String} expression)</code>, whereas the controller will be the 
     107     * instance of the controller which has factoried the object and the 
     108     * expression a string representing the path to the node using the given 
     109     * constructor.</p> 
     110     * 
     111     * @param type The name of the type for the locator. 
     112     * @param constructor The constructor of the locator. 
     113     */ 
     114    this.addLocator = function (type, constructor) { 
     115        if (locators[type] == undefined) { 
     116            locators[type] = constructor 
     117        } 
     118        else { 
     119            throw new Error("Unable to add locator, " + 
     120                    "type \"%s\" already defined".sprintf(type)) 
     121        } 
     122    } 
     123 
     124    this.createLocator = function (type, expression) { 
     125        if (locators[type] != undefined) { 
     126            return new locators[type](this, expression) 
     127        } 
     128        else { 
     129            throw new Error("Locator type \"%s\" not available".sprintf(type)) 
     130        } 
    94131    } 
    95132 
     
    98135 
    99136        this.addSelection(selection) 
     137 
     138        return selection 
    100139    } 
    101140 
     
    162201         *  controller.createAction("objectName", "methodName", 
    163202         *      new NoopObserver())) 
     203         * 
     204         * controller.createSelection( 
     205         *  controller.createLocator("id", "elementid") 
     206         * ).addAction("click", function () { 
     207         *     window.alert("hello, world!") 
     208         * }) 
    164209         *   
    165210         */ 
     
    183228             
    184229            for (var type in actions) { 
    185                 actions[type].each(callback) 
     230                actions[type].each(function (action) { 
     231                    callback(type, action, node) 
     232                }) 
    186233            } 
    187234        } 
     
    201248     */ 
    202249    this.attach = function (element) { 
    203         return allActions(element, function (action) { 
    204                 node.addEventListener(type, action.handle) 
     250        return allActions(element, function (type, action, node) { 
     251                node.addEventListener(type, action.handle, false) 
    205252                }) 
    206253    } 
     
    257304        /* If the method returned a value, simulate a notification with it. */ 
    258305        try { 
    259             var result = object[method](observer,  
     306            var result = object[methodName](observer,  
    260307                { element: this, event: event, extra: e, scope: scope }) 
    261308        } 
     
    273320        return result 
    274321    } 
     322 
     323    this.toString = function () { 
     324        return "[action (%s.%s), observer: %s]".sprintf( 
     325                objectName, methodName, observer 
     326                ); 
     327    } 
    275328} 
    276329 
     
    309362 * @param expression The xpath expression. 
    310363 */ 
    311 function XPathLocator (expression) { 
     364function XPathLocator (controller, expression) { 
    312365    this.locate = function (context) { 
    313366        if (context == null || typeof context == "undefined") { 
    314             context = document 
     367            context = controller.document 
    315368        } 
    316369         
     
    320373    this.list = function (context) { 
    321374        if (context == null) { 
    322             context = document 
     375            context = controller.document 
    323376        } 
    324377         
    325378        return context.selectNodes(expression) 
    326379    } 
    327 } 
    328  
    329 function FastIdLocator (id) { 
     380 
     381    this.toString = function () { 
     382        return "xpath://%s/".sprintf(expression) 
     383    } 
     384} 
     385 
     386function FastIdLocator (controller, id) { 
    330387    this.locate = function (context) { 
    331         var element = document.getElementById(id) 
     388        var element = controller.document.getElementById(id) 
    332389 
    333390        if (context == null || typeof context == "undefined") { 
     
    351408        return element != null ? [ element ] : [] 
    352409    } 
     410 
     411    this.toString = function () { 
     412        return "node://#%s".sprintf(id) 
     413    } 
    353414} 
    354415