]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/_TemplatedMixin.js.uncompressed.js
1 define ( "dijit/_TemplatedMixin" , [
2 "dojo/_base/lang" , // lang.getObject
5 "dojo/string" , // string.substitute string.trim
6 "dojo/cache" , // dojo.cache
7 "dojo/_base/array" , // array.forEach
8 "dojo/_base/declare" , // declare
9 "dojo/dom-construct" , // domConstruct.destroy, domConstruct.toDom
10 "dojo/_base/sniff" , // has("ie")
11 "dojo/_base/unload" , // unload.addOnWindowUnload
12 "dojo/_base/window" // win.doc
13 ], function ( lang
, touch
, _WidgetBase
, string
, cache
, array
, declare
, domConstruct
, has
, unload
, win
) {
16 var _WidgetBase = dijit._WidgetBase;
20 // dijit/_TemplatedMixin
22 // Mixin for widgets that are instantiated from a template
24 var _TemplatedMixin
= declare ( "dijit._TemplatedMixin" , null , {
26 // Mixin for widgets that are instantiated from a template
28 // templateString: [protected] String
29 // A string that represents the widget template.
30 // Use in conjunction with dojo.cache() to load from a file.
33 // templatePath: [protected deprecated] String
34 // Path to template (HTML file) for this widget relative to dojo.baseUrl.
35 // Deprecated: use templateString with require([... "dojo/text!..."], ...) instead
38 // skipNodeCache: [protected] Boolean
39 // If using a cached widget template nodes poses issues for a
40 // particular widget class, it can set this property to ensure
41 // that its template is always re-built from a string
42 _skipNodeCache
: false ,
44 // _earlyTemplatedStartup: Boolean
45 // A fallback to preserve the 1.0 - 1.3 behavior of children in
46 // templates having their startup called before the parent widget
47 // fires postCreate. Defaults to 'false', causing child widgets to
48 // have their .startup() called immediately before a parent widget
49 // .startup(), but always after the parent .postCreate(). Set to
50 // 'true' to re-enable to previous, arguably broken, behavior.
51 _earlyTemplatedStartup
: false ,
54 // _attachPoints: [private] String[]
55 // List of widget attribute names associated with data-dojo-attach-point=... in the
56 // template, ex: ["containerNode", "labelNode"]
61 // _attachEvents: [private] Handle[]
62 // List of connections associated with data-dojo-attach-event=... in the
67 constructor : function (){
68 this . _attachPoints
= [];
69 this . _attachEvents
= [];
72 _stringRepl : function ( tmpl
){
74 // Does substitution of ${foo} type properties in template string
77 var className
= this . declaredClass
, _this
= this ;
78 // Cache contains a string because we need to do property replacement
79 // do the property replacement
80 return string
. substitute ( tmpl
, this , function ( value
, key
){
81 if ( key
. charAt ( 0 ) == '!' ){ value
= lang
. getObject ( key
. substr ( 1 ), false , _this
); }
82 if ( typeof value
== "undefined" ){ throw new Error ( className
+ " template:" + key
); } // a debugging aide
83 if ( value
== null ){ return "" ; }
85 // Substitution keys beginning with ! will skip the transform step,
86 // in case a user wishes to insert unescaped markup, e.g. ${!foo}
87 return key
. charAt ( 0 ) == "!" ? value
:
88 // Safer substitution, see heading "Attribute values" in
89 // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
90 value
. toString (). replace ( /"/g,"""); / / TODO
: add
& amp
? use encodeXML method
?
94 buildRendering : function (){
96 // Construct the UI for this widget from a template, setting this.domNode.
100 if (! this . templateString
){
101 this . templateString
= cache ( this . templatePath
, { sanitize
: true });
104 // Lookup cached version of template, and download to cache if it
105 // isn't there already. Returns either a DomNode or a string, depending on
106 // whether or not the template contains ${foo} replacement parameters.
107 var cached
= _TemplatedMixin
. getCachedTemplate ( this . templateString
, this . _skipNodeCache
);
110 if ( lang
. isString ( cached
)){
111 node
= domConstruct
. toDom ( this . _stringRepl ( cached
));
112 if ( node
. nodeType
!= 1 ){
113 // Flag common problems such as templates with multiple top level nodes (nodeType == 11)
114 throw new Error ( "Invalid template: " + cached
);
117 // if it's a node, all we have to do is clone it
118 node
= cached
. cloneNode ( true );
123 // Call down to _Widget.buildRendering() to get base classes assigned
124 // TODO: change the baseClass assignment to _setBaseClassAttr
125 this . inherited ( arguments
);
127 // recurse through the node, looking for, and attaching to, our
128 // attachment points and events, which should be defined on the template node.
129 this . _attachTemplateNodes ( node
, function ( n
, p
){ return n
. getAttribute ( p
); });
131 this . _beforeFillContent (); // hook for _WidgetsInTemplateMixin
133 this . _fillContent ( this . srcNodeRef
);
136 _beforeFillContent : function (){
139 _fillContent : function ( /*DomNode*/ source
){
141 // Relocate source contents to templated container node.
142 // this.containerNode must be able to receive children, or exceptions will be thrown.
145 var dest
= this . containerNode
;
147 while ( source
. hasChildNodes ()){
148 dest
. appendChild ( source
. firstChild
);
153 _attachTemplateNodes : function ( rootNode
, getAttrFunc
){
155 // Iterate through the template and attach functions and nodes accordingly.
156 // Alternately, if rootNode is an array of widgets, then will process data-dojo-attach-point
157 // etc. for those widgets.
159 // Map widget properties and functions to the handlers specified in
160 // the dom node and it's descendants. This function iterates over all
161 // nodes and looks for these properties:
162 // * dojoAttachPoint/data-dojo-attach-point
163 // * dojoAttachEvent/data-dojo-attach-event
164 // rootNode: DomNode|Widget[]
165 // the node to search for properties. All children will be searched.
166 // getAttrFunc: Function
167 // a function which will be used to obtain property for a given
172 var nodes
= lang
. isArray ( rootNode
) ? rootNode
: ( rootNode
. all
|| rootNode
. getElementsByTagName ( "*" ));
173 var x
= lang
. isArray ( rootNode
) ? 0 : - 1 ;
174 for (; x
< nodes
. length
; x
++){
175 var baseNode
= ( x
== - 1 ) ? rootNode
: nodes
[ x
];
176 if ( this . widgetsInTemplate
&& ( getAttrFunc ( baseNode
, "dojoType" ) || getAttrFunc ( baseNode
, "data-dojo-type" ))){
179 // Process data-dojo-attach-point
180 var attachPoint
= getAttrFunc ( baseNode
, "dojoAttachPoint" ) || getAttrFunc ( baseNode
, "data-dojo-attach-point" );
182 var point
, points
= attachPoint
. split ( /\s*,\s*/ );
183 while (( point
= points
. shift ())){
184 if ( lang
. isArray ( this [ point
])){
185 this [ point
]. push ( baseNode
);
187 this [ point
]= baseNode
;
189 this . _attachPoints
. push ( point
);
193 // Process data-dojo-attach-event
194 var attachEvent
= getAttrFunc ( baseNode
, "dojoAttachEvent" ) || getAttrFunc ( baseNode
, "data-dojo-attach-event" );
196 // NOTE: we want to support attributes that have the form
197 // "domEvent: nativeEvent; ..."
198 var event
, events
= attachEvent
. split ( /\s*,\s*/ );
199 var trim
= lang
. trim
;
200 while (( event
= events
. shift ())){
203 if ( event
. indexOf ( ":" ) != - 1 ){
204 // oh, if only JS had tuple assignment
205 var funcNameArr
= event
. split ( ":" );
206 event
= trim ( funcNameArr
[ 0 ]);
207 thisFunc
= trim ( funcNameArr
[ 1 ]);
214 // Map "press", "move" and "release" to keys.touch, keys.move, keys.release
215 this . _attachEvents
. push ( this . connect ( baseNode
, touch
[ event
] || event
, thisFunc
));
222 destroyRendering : function (){
223 // Delete all attach points to prevent IE6 memory leaks.
224 array
. forEach ( this . _attachPoints
, function ( point
){
227 this . _attachPoints
= [];
229 // And same for event handlers
230 array
. forEach ( this . _attachEvents
, this . disconnect
, this );
231 this . _attachEvents
= [];
233 this . inherited ( arguments
);
237 // key is templateString; object is either string or DOM tree
238 _TemplatedMixin
. _templateCache
= {};
240 _TemplatedMixin
. getCachedTemplate = function ( templateString
, alwaysUseString
){
242 // Static method to get a template based on the templatePath or
243 // templateString key
244 // templateString: String
246 // alwaysUseString: Boolean
247 // Don't cache the DOM tree for this template, even if it doesn't have any variables
249 // Either string (if there are ${} variables that need to be replaced) or just
250 // a DOM tree (if the node can be cloned directly)
252 // is it already cached?
253 var tmplts
= _TemplatedMixin
. _templateCache
;
254 var key
= templateString
;
255 var cached
= tmplts
[ key
];
258 // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
259 if (! cached
. ownerDocument
|| cached
. ownerDocument
== win
. doc
){
260 // string or node of the same document
263 } catch ( e
){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
264 domConstruct
. destroy ( cached
);
267 templateString
= string
. trim ( templateString
);
269 if ( alwaysUseString
|| templateString
. match ( /\$\{([^\}]+)\}/g )){
270 // there are variables in the template so all we can do is cache the string
271 return ( tmplts
[ key
] = templateString
); //String
273 // there are no variables in the template so we can cache the DOM tree
274 var node
= domConstruct
. toDom ( templateString
);
275 if ( node
. nodeType
!= 1 ){
276 throw new Error ( "Invalid template: " + templateString
);
278 return ( tmplts
[ key
] = node
); //Node
283 unload
. addOnWindowUnload ( function (){
284 var cache
= _TemplatedMixin
. _templateCache
;
285 for ( var key
in cache
){
286 var value
= cache
[ key
];
287 if ( typeof value
== "object" ){ // value is either a string or a DOM node template
288 domConstruct
. destroy ( value
);
295 // These arguments can be specified for widgets which are used in templates.
296 // Since any widget can be specified as sub widgets in template, mix it
297 // into the base widget class. (This is a hack, but it's effective.)
298 lang
. extend ( _WidgetBase
,{
303 return _TemplatedMixin
;