Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Templated"] = true;
dojo.provide("dijit._Templated");

dojo.require("dijit._Widget");

dojo.require("dojo.string");
dojo.require("dojo.parser");

dojo.declare("dijit._Templated",
        null,
        {
                // summary:
                //              mixin for widgets that are instantiated from a template

                // templateNode: DomNode
                //              a node that represents the widget template. Pre-empts both templateString and templatePath.
                templateNode: null,

                // templateString String:
                //              a string that represents the widget template. Pre-empts the
                //              templatePath. In builds that have their strings "interned", the
                //              templatePath is converted to an inline templateString, thereby
                //              preventing a synchronous network call.
                templateString: null,

                // templatePath: String
                //      Path to template (HTML file) for this widget
                templatePath: null,

                // widgetsInTemplate Boolean:
                //              should we parse the template to find widgets that might be
                //              declared in markup inside it? false by default.
                widgetsInTemplate: false,

                // containerNode DomNode:
                //              holds child elements. "containerNode" is generally set via a
                //              dojoAttachPoint assignment and it designates where children of
                //              the src dom node will be placed
                containerNode: null,

                // skipNodeCache Boolean:
                //              if using a cached widget template node poses issues for a
                //              particular widget class, it can set this property to ensure
                //              that its template is always re-built from a string
                _skipNodeCache: false,

                // method over-ride
                buildRendering: function(){
                        // summary:
                        //              Construct the UI for this widget from a template, setting this.domNode.

                        // Lookup cached version of template, and download to cache if it
                        // isn't there already.  Returns either a DomNode or a string, depending on
                        // whether or not the template contains ${foo} replacement parameters.
                        var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);

                        var node;
                        if(dojo.isString(cached)){
                                var className = this.declaredClass, _this = this;
                                // Cache contains a string because we need to do property replacement
                                // do the property replacement
                                var tstr = dojo.string.substitute(cached, this, function(value, key){
                                        if(key.charAt(0) == '!'){ value = _this[key.substr(1)]; }
                                        if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
                                        if(!value){ return ""; }

                                        // Substitution keys beginning with ! will skip the transform step,
                                        // in case a user wishes to insert unescaped markup, e.g. ${!foo}
                                        return key.charAt(0) == "!" ? value :
                                                // Safer substitution, see heading "Attribute values" in
                                                // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
                                                value.toString().replace(/"/g,"""); //TODO: add &amp? use encodeXML method?
                                }, this);

                                node = dijit._Templated._createNodesFromText(tstr)[0];
                        }else{
                                // if it's a node, all we have to do is clone it
                                node = cached.cloneNode(true);
                        }

                        // recurse through the node, looking for, and attaching to, our
                        // attachment points which should be defined on the template node.
                        this._attachTemplateNodes(node);

                        var source = this.srcNodeRef;
                        if(source && source.parentNode){
                                source.parentNode.replaceChild(node, source);
                        }

                        this.domNode = node;
                        if(this.widgetsInTemplate){
                                var childWidgets = dojo.parser.parse(node);
                                this._attachTemplateNodes(childWidgets, function(n,p){
                                        return n[p];
                                });
                        }

                        this._fillContent(source);
                },

                _fillContent: function(/*DomNode*/ source){
                        // summary:
                        //              relocate source contents to templated container node
                        //              this.containerNode must be able to receive children, or exceptions will be thrown
                        var dest = this.containerNode;
                        if(source && dest){
                                while(source.hasChildNodes()){
                                        dest.appendChild(source.firstChild);
                                }
                        }
                },

                _attachTemplateNodes: function(rootNode, getAttrFunc){
                        // summary:
                        //              map widget properties and functions to the handlers specified in
                        //              the dom node and it's descendants. This function iterates over all
                        //              nodes and looks for these properties:
                        //                      * dojoAttachPoint
                        //                      * dojoAttachEvent       
                        //                      * waiRole
                        //                      * waiState
                        // rootNode: DomNode|Array[Widgets]
                        //              the node to search for properties. All children will be searched.
                        // getAttrFunc: function?
                        //              a function which will be used to obtain property for a given
                        //              DomNode/Widget

                        getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };

                        var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
                        var x=dojo.isArray(rootNode)?0:-1;
                        for(; x<nodes.length; x++){
                                var baseNode = (x == -1) ? rootNode : nodes[x];
                                if(this.widgetsInTemplate && getAttrFunc(baseNode,'dojoType')){
                                        continue;
                                }
                                // Process dojoAttachPoint
                                var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
                                if(attachPoint){
                                        var point, points = attachPoint.split(/\s*,\s*/);
                                        while(point=points.shift()){
                                                if(dojo.isArray(this[point])){
                                                        this[point].push(baseNode);
                                                }else{
                                                        this[point]=baseNode;
                                                }
                                        }
                                }

                                // Process dojoAttachEvent
                                var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
                                if(attachEvent){
                                        // NOTE: we want to support attributes that have the form
                                        // "domEvent: nativeEvent; ..."
                                        var event, events = attachEvent.split(/\s*,\s*/);
                                        var trim = dojo.trim;
                                        while(event=events.shift()){
                                                if(event){
                                                        var thisFunc = null;
                                                        if(event.indexOf(":") != -1){
                                                                // oh, if only JS had tuple assignment
                                                                var funcNameArr = event.split(":");
                                                                event = trim(funcNameArr[0]);
                                                                thisFunc = trim(funcNameArr[1]);
                                                        }else{
                                                                event = trim(event);
                                                        }
                                                        if(!thisFunc){
                                                                thisFunc = event;
                                                        }
                                                        this.connect(baseNode, event, thisFunc);
                                                }
                                        }
                                }

                                // waiRole, waiState
                                var role = getAttrFunc(baseNode, "waiRole");
                                if(role){
                                        dijit.setWaiRole(baseNode, role);
                                }
                                var values = getAttrFunc(baseNode, "waiState");
                                if(values){
                                        dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
                                                if(stateValue.indexOf('-') != -1){
                                                        var pair = stateValue.split('-');
                                                        dijit.setWaiState(baseNode, pair[0], pair[1]);
                                                }
                                        });
                                }

                        }
                }
        }
);

// key is either templatePath or templateString; object is either string or DOM tree
dijit._Templated._templateCache = {};

dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
        // summary:
        //              static method to get a template based on the templatePath or
        //              templateString key
        // templatePath: String
        //              the URL to get the template from. dojo.uri.Uri is often passed as well.
        // templateString: String?
        //              a string to use in lieu of fetching the template from a URL
        // Returns:
        //      Either string (if there are ${} variables that need to be replaced) or just
        //      a DOM tree (if the node can be cloned directly)

        // is it already cached?
        var tmplts = dijit._Templated._templateCache;
        var key = templateString || templatePath;
        var cached = tmplts[key];
        if(cached){
                return cached;
        }

        // If necessary, load template string from template path
        if(!templateString){
                templateString = dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath));
        }

        templateString = dojo.string.trim(templateString);

        if(templateString.match(/\$\{([^\}]+)\}/g) || alwaysUseString){
                // there are variables in the template so all we can do is cache the string
                return (tmplts[key] = templateString); //String
        }else{
                // there are no variables in the template so we can cache the DOM tree
                return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]); //Node
        }
};

dijit._Templated._sanitizeTemplateString = function(/*String*/tString){
        // summary: 
        //              Strips <?xml ...?> declarations so that external SVG and XML
        //              documents can be added to a document without worry. Also, if the string
        //              is an HTML document, only the part inside the body tag is returned.
        if(tString){
                tString = tString.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
                var matches = tString.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
                if(matches){
                        tString = matches[1];
                }
        }else{
                tString = "";
        }
        return tString; //String
};


if(dojo.isIE){
        dojo.addOnUnload(function(){
                var cache = dijit._Templated._templateCache;
                for(var key in cache){
                        var value = cache[key];
                        if(!isNaN(value.nodeType)){ // isNode equivalent
                                dojo._destroyElement(value);
                        }
                        delete cache[key];
                }
        });
}

(function(){
        var tagMap = {
                cell: {re: /^<t[dh][\s\r\n>]/i, pre: "<table><tbody><tr>", post: "</tr></tbody></table>"},
                row: {re: /^<tr[\s\r\n>]/i, pre: "<table><tbody>", post: "</tbody></table>"},
                section: {re: /^<(thead|tbody|tfoot)[\s\r\n>]/i, pre: "<table>", post: "</table>"}
        };

        // dummy container node used temporarily to hold nodes being created
        var tn;

        dijit._Templated._createNodesFromText = function(/*String*/text){
                // summary:
                //      Attempts to create a set of nodes based on the structure of the passed text.

                if(!tn){
                        tn = dojo.doc.createElement("div");
                        tn.style.display="none";
                        dojo.body().appendChild(tn);
                }
                var tableType = "none";
                var rtext = text.replace(/^\s+/, "");
                for(var type in tagMap){
                        var map = tagMap[type];
                        if(map.re.test(rtext)){
                                tableType = type;
                                text = map.pre + text + map.post;
                                break;
                        }
                }

                tn.innerHTML = text;
                if(tn.normalize){
                        tn.normalize();
                }

                var tag = { cell: "tr", row: "tbody", section: "table" }[tableType];
                var _parent = (typeof tag != "undefined") ?
                                                tn.getElementsByTagName(tag)[0] :
                                                tn;

                var nodes = [];
                while(_parent.firstChild){
                        nodes.push(_parent.removeChild(_parent.firstChild));
                }
                tn.innerHTML="";
                return nodes;   //      Array
        }
})();

// These arguments can be specified for widgets which are used in templates.
// Since any widget can be specified as sub widgets in template, mix it
// into the base widget class.  (This is a hack, but it's effective.)
dojo.extend(dijit._Widget,{
        dojoAttachEvent: "",
        dojoAttachPoint: "",
        waiRole: "",
        waiState:""
})

}