[483] | 1 | define([ |
---|
| 2 | "dojo/_base/kernel", |
---|
| 3 | "dojo/_base/lang", |
---|
| 4 | "dojo/_base/connect", |
---|
| 5 | "dojo/dom-style", |
---|
| 6 | "dojo/dom-construct", |
---|
| 7 | "../_base", |
---|
| 8 | "../dom" |
---|
| 9 | ], function(kernel,lang,connect,domStyle,domConstruct,dd,dddom){ |
---|
| 10 | |
---|
| 11 | var ddch = lang.getObject("contrib.dom", true, dd); |
---|
| 12 | /*===== |
---|
| 13 | ddch = { |
---|
| 14 | // TODO: summary |
---|
| 15 | }; |
---|
| 16 | =====*/ |
---|
| 17 | |
---|
| 18 | var simple = {render: function(){ return this.contents; }}; |
---|
| 19 | |
---|
| 20 | ddch.StyleNode = lang.extend(function(styles){ |
---|
| 21 | this.contents = {}; |
---|
| 22 | this._current = {}; |
---|
| 23 | this._styles = styles; |
---|
| 24 | for(var key in styles){ |
---|
| 25 | if(styles[key].indexOf("{{") != -1){ |
---|
| 26 | var node = new dd.Template(styles[key]); |
---|
| 27 | }else{ |
---|
| 28 | var node = lang.delegate(simple); |
---|
| 29 | node.contents = styles[key]; |
---|
| 30 | } |
---|
| 31 | this.contents[key] = node; |
---|
| 32 | } |
---|
| 33 | }, |
---|
| 34 | { |
---|
| 35 | render: function(context, buffer){ |
---|
| 36 | for(var key in this.contents){ |
---|
| 37 | var value = this.contents[key].render(context); |
---|
| 38 | if(this._current[key] != value){ |
---|
| 39 | domStyle.set(buffer.getParent(), key, this._current[key] = value); |
---|
| 40 | } |
---|
| 41 | } |
---|
| 42 | return buffer; |
---|
| 43 | }, |
---|
| 44 | unrender: function(context, buffer){ |
---|
| 45 | this._current = {}; |
---|
| 46 | return buffer; |
---|
| 47 | }, |
---|
| 48 | clone: function(buffer){ |
---|
| 49 | return new this.constructor(this._styles); |
---|
| 50 | } |
---|
| 51 | }); |
---|
| 52 | |
---|
| 53 | ddch.BufferNode = lang.extend(function(nodelist, options){ |
---|
| 54 | this.nodelist = nodelist; |
---|
| 55 | this.options = options; |
---|
| 56 | }, |
---|
| 57 | { |
---|
| 58 | _swap: function(type, node){ |
---|
| 59 | if(!this.swapped && this.parent.parentNode){ |
---|
| 60 | if(type == "node"){ |
---|
| 61 | if((node.nodeType == 3 && !this.options.text) || (node.nodeType == 1 && !this.options.node)){ |
---|
| 62 | return; |
---|
| 63 | } |
---|
| 64 | }else if(type == "class"){ |
---|
| 65 | if(type != "class"){ |
---|
| 66 | return; |
---|
| 67 | } |
---|
| 68 | } |
---|
| 69 | |
---|
| 70 | this.onAddNode && connect.disconnect(this.onAddNode); |
---|
| 71 | this.onRemoveNode && connect.disconnect(this.onRemoveNode); |
---|
| 72 | this.onChangeAttribute && connect.disconnect(this.onChangeAttribute); |
---|
| 73 | this.onChangeData && connect.disconnect(this.onChangeData); |
---|
| 74 | |
---|
| 75 | this.swapped = this.parent.cloneNode(true); |
---|
| 76 | this.parent.parentNode.replaceChild(this.swapped, this.parent); |
---|
| 77 | } |
---|
| 78 | }, |
---|
| 79 | render: function(context, buffer){ |
---|
| 80 | this.parent = buffer.getParent(); |
---|
| 81 | if(this.options.node){ |
---|
| 82 | this.onAddNode = connect.connect(buffer, "onAddNode", lang.hitch(this, "_swap", "node")); |
---|
| 83 | this.onRemoveNode = connect.connect(buffer, "onRemoveNode", lang.hitch(this, "_swap", "node")); |
---|
| 84 | } |
---|
| 85 | if(this.options.text){ |
---|
| 86 | this.onChangeData = connect.connect(buffer, "onChangeData", lang.hitch(this, "_swap", "node")); |
---|
| 87 | } |
---|
| 88 | if(this.options["class"]){ |
---|
| 89 | this.onChangeAttribute = connect.connect(buffer, "onChangeAttribute", lang.hitch(this, "_swap", "class")); |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | buffer = this.nodelist.render(context, buffer); |
---|
| 93 | |
---|
| 94 | if(this.swapped){ |
---|
| 95 | this.swapped.parentNode.replaceChild(this.parent, this.swapped); |
---|
| 96 | domConstruct.destroy(this.swapped); |
---|
| 97 | }else{ |
---|
| 98 | this.onAddNode && connect.disconnect(this.onAddNode); |
---|
| 99 | this.onRemoveNode && connect.disconnect(this.onRemoveNode); |
---|
| 100 | this.onChangeAttribute && connect.disconnect(this.onChangeAttribute); |
---|
| 101 | this.onChangeData && connect.disconnect(this.onChangeData); |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | delete this.parent; |
---|
| 105 | delete this.swapped; |
---|
| 106 | return buffer; |
---|
| 107 | }, |
---|
| 108 | unrender: function(context, buffer){ |
---|
| 109 | return this.nodelist.unrender(context, buffer); |
---|
| 110 | }, |
---|
| 111 | clone: function(buffer){ |
---|
| 112 | return new this.constructor(this.nodelist.clone(buffer), this.options); |
---|
| 113 | } |
---|
| 114 | }); |
---|
| 115 | |
---|
| 116 | lang.mixin(ddch, { |
---|
| 117 | buffer: function(parser, token){ |
---|
| 118 | // summary: |
---|
| 119 | // Buffer large DOM manipulations during re-render. |
---|
| 120 | // description: |
---|
| 121 | // When using DomTemplate, wrap any content |
---|
| 122 | // that you expect to change often during |
---|
| 123 | // re-rendering. It will then remove its parent |
---|
| 124 | // from the main document while it re-renders that |
---|
| 125 | // section of code. It will only remove it from |
---|
| 126 | // the main document if a mainpulation of somes sort |
---|
| 127 | // happens. ie It won't swap out if it diesn't have to. |
---|
| 128 | // example: |
---|
| 129 | // By default, it considers only node addition/removal |
---|
| 130 | // to be "changing" |
---|
| 131 | // |
---|
| 132 | // | {% buffer %}{% for item in items %}<li>{{ item }}</li>{% endfor %}{% endbuffer %} |
---|
| 133 | // example: |
---|
| 134 | // You can explicitly declare options: |
---|
| 135 | // |
---|
| 136 | // - node: Watch node removal/addition |
---|
| 137 | // - class: Watch for a classname to be changed |
---|
| 138 | // - text: Watch for any text to be changed |
---|
| 139 | // |
---|
| 140 | // | {% buffer node class %}{% for item in items %}<li>{{ item }}</li>{% endfor %}{% endbuffer %} |
---|
| 141 | var parts = token.contents.split().slice(1); |
---|
| 142 | var options = {}; |
---|
| 143 | var found = false; |
---|
| 144 | for(var i = parts.length; i--;){ |
---|
| 145 | found = true; |
---|
| 146 | options[parts[i]] = true; |
---|
| 147 | } |
---|
| 148 | if(!found){ |
---|
| 149 | options.node = true; |
---|
| 150 | } |
---|
| 151 | var nodelist = parser.parse(["endbuffer"]); |
---|
| 152 | parser.next_token(); |
---|
| 153 | return new ddch.BufferNode(nodelist, options); |
---|
| 154 | }, |
---|
| 155 | html: function(parser, token){ |
---|
| 156 | kernel.deprecated("{% html someVariable %}", "Use {{ someVariable|safe }} instead"); |
---|
| 157 | return parser.create_variable_node(token.contents.slice(5) + "|safe"); |
---|
| 158 | }, |
---|
| 159 | style_: function(parser, token){ |
---|
| 160 | var styles = {}; |
---|
| 161 | token = token.contents.replace(/^style\s+/, ""); |
---|
| 162 | var rules = token.split(/\s*;\s*/g); |
---|
| 163 | for(var i = 0, rule; rule = rules[i]; i++){ |
---|
| 164 | var parts = rule.split(/\s*:\s*/g); |
---|
| 165 | var key = parts[0]; |
---|
| 166 | var value = lang.trim(parts[1]); |
---|
| 167 | if(value){ |
---|
| 168 | styles[key] = value; |
---|
| 169 | } |
---|
| 170 | } |
---|
| 171 | return new ddch.StyleNode(styles); |
---|
| 172 | } |
---|
| 173 | }); |
---|
| 174 | |
---|
| 175 | dd.register.tags("dojox.dtl.contrib", { |
---|
| 176 | "dom": ["html", "attr:style", "buffer"] |
---|
| 177 | }); |
---|
| 178 | |
---|
| 179 | return ddch; |
---|
| 180 | }); |
---|