lsd_rails 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/Packages/Sheet.js/Source/SheetParser.Value.js +1 -1
  2. data/Packages/lsd/Source/Action/Clone.js +2 -12
  3. data/Packages/lsd/Source/Action/Delete.js +1 -7
  4. data/Packages/lsd/Source/Action/Display.js +7 -7
  5. data/Packages/lsd/Source/Action/Edit.js +2 -2
  6. data/Packages/lsd/Source/Action/Invoke.js +2 -2
  7. data/Packages/lsd/Source/Action/Submit.js +2 -0
  8. data/Packages/lsd/Source/Action/Toggle.js +4 -0
  9. data/Packages/lsd/Source/Action/Update.js +2 -1
  10. data/Packages/lsd/Source/Action.js +4 -5
  11. data/Packages/lsd/Source/Document.js +10 -7
  12. data/Packages/lsd/Source/LSD.js +22 -127
  13. data/Packages/lsd/Source/Layer.js +4 -4
  14. data/Packages/lsd/Source/Layout.js +1077 -259
  15. data/Packages/lsd/Source/Mixin/Animation.js +1 -1
  16. data/Packages/lsd/Source/Mixin/Choice.js +2 -2
  17. data/Packages/lsd/Source/Mixin/Command.js +26 -8
  18. data/Packages/lsd/Source/Mixin/ContentEditable.js +2 -1
  19. data/Packages/lsd/Source/{Trait → Mixin}/Date.js +21 -11
  20. data/Packages/lsd/Source/{Trait/Menu.js → Mixin/Details.js} +6 -1
  21. data/Packages/lsd/Source/Mixin/Draggable.js +1 -1
  22. data/Packages/lsd/Source/Mixin/Fieldset.js +51 -49
  23. data/Packages/lsd/Source/Mixin/Focusable.js +38 -39
  24. data/Packages/lsd/Source/Mixin/Invokable.js +13 -14
  25. data/Packages/lsd/Source/Mixin/List.js +9 -17
  26. data/Packages/lsd/Source/Mixin/Placeholder.js +2 -7
  27. data/Packages/lsd/Source/Mixin/Request.js +5 -3
  28. data/Packages/lsd/Source/Mixin/Resizable.js +3 -3
  29. data/Packages/lsd/Source/Mixin/Resource.js +1 -1
  30. data/Packages/lsd/Source/Mixin/Root.js +17 -1
  31. data/Packages/lsd/Source/Mixin/Scrollable.js +1 -1
  32. data/Packages/lsd/Source/{Trait → Mixin}/Slider.js +0 -0
  33. data/Packages/lsd/Source/Mixin/Sortable.js +2 -2
  34. data/Packages/lsd/Source/Mixin/Submittable.js +2 -1
  35. data/Packages/lsd/Source/Mixin/Target.js +11 -6
  36. data/Packages/lsd/Source/Mixin/Touchable.js +2 -2
  37. data/Packages/lsd/Source/Mixin/Unselectable.js +1 -1
  38. data/Packages/lsd/Source/Mixin/Uploader.js +11 -13
  39. data/Packages/lsd/Source/Mixin/Validity.js +35 -9
  40. data/Packages/lsd/Source/Mixin/Value.js +5 -3
  41. data/Packages/lsd/Source/Module/Accessories/Attributes.js +90 -89
  42. data/Packages/lsd/Source/Module/Accessories/Chain.js +40 -25
  43. data/Packages/lsd/Source/Module/Accessories/Element.js +59 -58
  44. data/Packages/lsd/Source/Module/Accessories/Events.js +25 -10
  45. data/Packages/lsd/Source/Module/Accessories/Options.js +11 -13
  46. data/Packages/lsd/Source/Module/Accessories/States.js +42 -5
  47. data/Packages/lsd/Source/Module/Accessories/Styles.js +1 -1
  48. data/Packages/lsd/Source/Module/Accessories/Tag.js +21 -7
  49. data/Packages/lsd/Source/Module/Ambient/Allocations.js +178 -64
  50. data/Packages/lsd/Source/Module/Ambient/DOM.js +98 -55
  51. data/Packages/lsd/Source/Module/Ambient/Expectations.js +57 -8
  52. data/Packages/lsd/Source/Module/Ambient/Interpolations.js +147 -0
  53. data/Packages/lsd/Source/Module/Ambient/Layout.js +52 -15
  54. data/Packages/lsd/Source/Module/Ambient/Proxies.js +44 -36
  55. data/Packages/lsd/Source/Module/Ambient/Relations.js +3 -1
  56. data/Packages/lsd/Source/Module/Ambient/Selectors.js +3 -3
  57. data/Packages/lsd/Source/Module/Ambient.js +2 -2
  58. data/Packages/lsd/Source/Module/Graphics/Layers.js +1 -1
  59. data/Packages/lsd/Source/Module/Graphics/Render.js +1 -1
  60. data/Packages/lsd/Source/Relation.js +19 -20
  61. data/Packages/lsd/Source/Sheet.js +4 -5
  62. data/Packages/lsd/Source/{Behavior.js → Tools/Behavior.js} +0 -0
  63. data/Packages/lsd/Source/Tools/Command.js +190 -0
  64. data/Packages/lsd/Source/Tools/Helpers.js +109 -0
  65. data/Packages/lsd/Source/Tools/Interpolation.js +351 -0
  66. data/Packages/lsd/Source/Tools/Microdata.js +75 -0
  67. data/Packages/lsd/Source/Tools/Object.js +192 -0
  68. data/Packages/lsd/Source/Tools/Position.js +208 -0
  69. data/Packages/lsd/Source/Tools/Require.js +76 -0
  70. data/Packages/lsd/Source/Type.js +2 -2
  71. data/Packages/lsd/package.yml +11 -7
  72. data/Packages/lsd-mobile/Source/Body/Dialog.js +2 -2
  73. data/Packages/lsd-mobile/Source/Input/Date.js +9 -84
  74. data/Packages/lsd-native/Source/Input/Checkbox.js +4 -4
  75. data/Packages/lsd-native/Source/Input/Date.js +46 -6
  76. data/Packages/lsd-native/Source/Input/Radio.js +1 -4
  77. data/Packages/lsd-native/Source/Input.js +5 -6
  78. data/Packages/lsd-widgets/Source/Body/Dialog.js +9 -6
  79. data/Packages/lsd-widgets/Source/Body/Page.js +1 -1
  80. data/Packages/lsd-widgets/Source/Body.js +1 -1
  81. data/Packages/lsd-widgets/Source/Button.js +1 -1
  82. data/Packages/lsd-widgets/Source/Form.js +1 -1
  83. data/Packages/lsd-widgets/Source/Input/Checkbox.js +2 -2
  84. data/Packages/lsd-widgets/Source/Input/Date.js +45 -16
  85. data/Packages/lsd-widgets/Source/Input/File.js +2 -2
  86. data/Packages/lsd-widgets/Source/Input/HTML.js +2 -2
  87. data/Packages/lsd-widgets/Source/Input/Radio.js +1 -1
  88. data/Packages/lsd-widgets/Source/Input/Range.js +2 -2
  89. data/Packages/lsd-widgets/Source/Input/Submit.js +1 -1
  90. data/Packages/lsd-widgets/Source/Input.js +2 -11
  91. data/Packages/lsd-widgets/Source/Label.js +4 -8
  92. data/Packages/lsd-widgets/Source/Menu/List.js +3 -3
  93. data/Packages/lsd-widgets/Source/Menu.js +2 -2
  94. data/Packages/lsd-widgets/Source/Progress.js +1 -1
  95. data/Packages/lsd-widgets/Source/Select.js +7 -6
  96. data/Packages/lsd-widgets/Source/Table/Calendar.js +41 -15
  97. data/Packages/lsd-widgets/Source/Table.js +7 -2
  98. data/Packages/mootools-ext/Source/Core/Class.Mixin.js +43 -38
  99. data/Packages/mootools-ext/Source/Core/Class.States.js +26 -22
  100. data/Packages/mootools-ext/Source/Element/Element.from.js +1 -1
  101. data/Packages/mootools-ext/Source/Element/Properties/Item.js +1 -2
  102. data/Packages/mootools-ext/Source/Request/Request.Statuses.js +9 -7
  103. data/Packages/mootools-ext/Source/Types/{FastArray.js → Object.Array.js} +8 -14
  104. data/Packages/mootools-ext/package.yml +1 -2
  105. data/lib/lsd.rake +28 -0
  106. metadata +15 -11
  107. data/Packages/lsd/Source/Command.js +0 -135
  108. data/Packages/lsd/Source/Interpolation.js +0 -103
  109. data/Packages/lsd/Source/Module/Ambient/Container.js +0 -56
  110. data/Packages/mootools-ext/Source/Element/Element.onDispose.js +0 -36
@@ -12,6 +12,7 @@ authors: Yaroslaff Fedin
12
12
  requires:
13
13
  - LSD.Module
14
14
  - LSD.Module.Events
15
+ - LSD.Position
15
16
 
16
17
  provides:
17
18
  - LSD.Module.Allocations
@@ -26,31 +27,90 @@ LSD.Module.Allocations = new Class({
26
27
  }
27
28
  },
28
29
 
29
- allocate: function() {
30
- var args = Array.prototype.slice.call(arguments);
31
- var last = args[args.length - 1];
32
- if (last == args[0] && last.type) args = [last.type, last.kind, (last = last.options)];
33
- if (last && !last.indexOf && !last.push) var options = args.pop();
34
- var type = args[0], kind = args[1];
30
+ allocate: function(type, kind, options) {
31
+ options = arguments[arguments.length - 1];
32
+ if (options.type) {
33
+ type = options.type;
34
+ if (options.kind) kind = options.kind;
35
+ options = options.options || {};
36
+ }
35
37
  var allocation = LSD.Allocations[type];
36
- if (!allocation) return;
37
- var allocations = this.allocations, object;
38
+ if (!allocation) throw "Dont know how to allocate " + type;
39
+ var group = this.allocations[type];
40
+ if (allocation.multiple && kind == null) {
41
+ if (!group.length) group.length = 0;
42
+ kind = group.length++;
43
+ }
44
+ if (group) {
45
+ if (kind && group[kind]) return group[kind];
46
+ else return group;
47
+ } else if (allocation.multiple) {
48
+ group = this.allocations[type] = {};
49
+ }
50
+ var id = (kind == null) ? type : kind;
51
+ var options = this.preallocate.apply(this, arguments);
52
+ var parent = options.parent;
53
+ delete options.parent;
54
+ var object = this.buildLayout(options.source || options.tag, parent, {options: options});
55
+ var stored = options.stored;
56
+ if (stored && object.store) {
57
+ for (var name in stored) stored[name].apply(this, object);
58
+ object.store('allocation', stored);
59
+ delete options.stored;
60
+ }
61
+ if (id == null) id = type;
62
+ (group || this.allocations)[id] = object;
63
+ return object;
64
+ },
65
+
66
+ release: function(type, kind, options) {
67
+ options = arguments[arguments.length - 1];
68
+ if (options.type) {
69
+ type = options.type;
70
+ if (options.kind) kind = options.kind;
71
+ options = options.options || {};
72
+ }
73
+ var allocation = LSD.Allocations[type];
74
+ if (!allocation) throw "Dont know how to release " + type;
75
+ var group = this.allocations, object = group[type];
76
+ if (allocation.multiple) {
77
+ var index = name || group.length++ - 1;
78
+ group = object;
79
+ object = group[index];
80
+ }
81
+ if (!object) throw "Cant release " + type + " because it was not allocated";
82
+ if (object && object.retrieve) {
83
+ var options = object.retrieve('allocation');
84
+ if (options) for (var name in options) if (options[name]) {
85
+ var result = handler.call(this, object, options[name], true, value);
86
+ if (options[name] != null) object.eliminate(key, options[name]);
87
+ }
88
+ object.parentNode.removeChild(object);
89
+ delete group[index || type];
90
+ }
91
+ },
92
+
93
+ preallocate: function(type, kind, options) {
94
+ options = arguments[arguments.length - 1];
95
+ if (options.type) {
96
+ type = options.type;
97
+ if (options.kind) kind = options.kind;
98
+ options = options.options || {};
99
+ }
100
+ var allocation = LSD.Allocations[type];
101
+ if (!allocation) throw "Dont know how to preallocate " + type;
38
102
  var opts = this.options.allocations && this.options.allocations[type];
39
103
  if (allocation.multiple) {
40
- var group = allocations[type] || (allocations[type] = {});
41
- if (kind) {
42
- var index = type + '-' + kind;
43
- var customized = LSD.Allocations[index];
44
- if (group[kind]) return group[kind];
45
- } else {
46
- for (var id = kind; allocations[++id];);
104
+ if (kind == null) {
105
+ if (!group.length) group.length = 0;
106
+ kind = group.length++;
47
107
  }
48
- } else {
49
- if (allocations[type]) return allocations[type];
108
+ var customized = LSD.Allocations[type + '-' + kind];
109
+ if (opts) opts = opts[kind];
50
110
  }
51
111
  if (allocation.call) {
52
- allocation = allocation.apply(this, [options].concat(args));
53
- if (allocation.nodeType) object = allocation;
112
+ allocation = allocation.apply(this, arguments);
113
+ if (allocation.nodeType) var object = allocation;
54
114
  } else {
55
115
  if (allocation.options)
56
116
  var generated = allocation.options.call ? allocation.options.call(this, options, kind) : allocation.options;
@@ -60,25 +120,34 @@ LSD.Module.Allocations = new Class({
60
120
  delete options.multiple;
61
121
  delete options.options;
62
122
  if (options.source && options.source.call) options.source = options.source.call(this, kind, options);
63
- options.invoker = this;
64
- var parent = options.parent ? (options.parent.call ? options.parent.call(this) : option.parent) : this;
65
- delete options.parent;
123
+ var parent = options.parent ? (options.parent.call ? options.parent.call(this) : options.parent) : this;
124
+ //switch (parent) {
125
+ // case "parent":
126
+ // parent = this.parentNode;
127
+ // break;
128
+ // case "root":
129
+ // parent = this.root;
130
+ // break;
131
+ // case "document":
132
+ // parent = document.body;
133
+ //}
66
134
  if (!parent.lsd) parent = [this, parent];
67
- object = this.buildLayout(options.source || options.tag, parent, options);
135
+ options.parent = parent.push ? [].concat(parent) : parent;
136
+ var callbacks;
137
+ for (var name in options) if (options[name]) {
138
+ var handler = LSD.Module.Allocations.Options[name];
139
+ if (handler) {
140
+ var result = handler.call(this, options[name], true);
141
+ if (result != null) {
142
+ if (!callbacks) callbacks = {};
143
+ callbacks[name] = result;
144
+ delete options[name];
145
+ }
146
+ }
147
+ }
148
+ if (callbacks) options.stored = callbacks;
68
149
  };
69
- (group || allocations)[kind || id] = object;
70
- return object;
71
- },
72
-
73
- release: function(type, name, widget) {
74
- var allocations = this.allocations, group = allocations[type];
75
- if (group) {
76
- if (!name) name = 1;
77
- if (group[name]) {
78
- group[name].dispose();
79
- delete group[name];
80
- }
81
- }
150
+ return options;
82
151
  }
83
152
 
84
153
  });
@@ -86,13 +155,51 @@ LSD.Module.Allocations = new Class({
86
155
  LSD.Module.Events.addEvents.call(LSD.Module.Allocations.prototype, {
87
156
  getRelated: function(type, id, classes, attributes, pseudos) {
88
157
  if (!LSD.Allocations[type]) return;
89
- var allocation = LSD.Module.Allocations.prepare(type, {}, classes, attributes, pseudos);
90
- return this.allocate(allocation);
158
+ return this.allocate(LSD.Module.Allocations.compile(type, classes, attributes, pseudos));
91
159
  }
92
160
  });
93
161
 
94
- LSD.Module.Allocations.prepare = function(type, options, classes, attributes, pseudos) {
95
- var name, kind;
162
+ LSD.Module.Allocations.Options = {
163
+ position: function(position, state, memo) {
164
+ if (state) {
165
+ if (position.match || position.push) position = {attachment: position};
166
+ if (!position.anchor && position.anchor !== false) position.anchor = this;
167
+ if (!position.boundaries && position.boundaries !== false) position.boundaries = true;
168
+ var callback = function(object) {
169
+ callback.position = new LSD.Position(object, position);
170
+ }
171
+ return callback;
172
+ } else {
173
+ if (memo.position) memo.position.detach();
174
+ }
175
+ },
176
+
177
+ proxy: function(proxy, state, memo) {
178
+ if (state) {
179
+ if (proxy === true || !proxy) proxy = {};
180
+ proxy.container = false;
181
+ this.addProxy('allocated', proxy);
182
+ var callback = function(object) {
183
+ if (object.lsd) var element = object.element || object.toElement(), widget = object;
184
+ else var element = object, widget = this;
185
+ if (proxy.queued)
186
+ for (var i = 0, child; child = proxy.queued[i++];)
187
+ this.layout.appendChild(child.lsd ? widget : element, child, null, child.lsd ? element : null);
188
+ proxy.container = object;
189
+ }.bind(this);
190
+ callback.proxy = proxy;
191
+ return callback;
192
+ } else {
193
+ this.removeProxy('allocated', memo.proxy);
194
+ }
195
+ }
196
+ }
197
+
198
+ LSD.Module.Allocations.compile = function(type, classes, attributes, pseudos) {
199
+ var name, kind, options = {}
200
+ if (classes)
201
+ for (var i = 0, klass; klass = classes[i++];)
202
+ (options.classes || (options.classes = {}))[klass.name] = true;
96
203
  if (attributes)
97
204
  for (var i = 0, attribute; attribute = attributes[i++];)
98
205
  (options.attributes || (options.attributes = {}))[attribute.name] = attribute.value;
@@ -114,45 +221,52 @@ LSD.Module.Allocations.prepare = function(type, options, classes, attributes, ps
114
221
  LSD.Allocations = {
115
222
 
116
223
  lightbox: {
117
- source: 'body-lightbox',
118
- parent: function() {
119
- return document.body;
120
- }
224
+ source: 'body[type=lightbox]'
121
225
  },
122
226
 
123
227
  dialog: {
124
228
  multiple: true,
229
+ source: 'body[type=dialog]',
125
230
  options: function(options, kind) {
126
- return Object.merge(
127
- {
128
- tag: 'body',
129
- attributes: {
130
- type: 'dialog'
131
- }
132
- },
133
- kind ? {attributes: {kind: kind}} : null,
134
- options
135
- )
136
- },
137
- parent: function() {
138
- return document.body;
231
+ if (kind) return {attributes: {kind: kind}}
139
232
  }
140
233
  },
141
234
 
142
235
  menu: {
143
- source: 'menu-context'
236
+ source: 'menu[type=context]'
144
237
  },
145
238
 
146
239
  scrollbar: {
147
240
  source: 'scrollbar'
148
241
  },
149
242
 
150
- editor: function(options, type, name) {
151
- return Object.merge(
152
- {source: type == 'area' ? 'textarea' : ('input' + (type ? '-' + type : ''))},
153
- name ? {attributes: {name: name}} : null,
154
- options
155
- );
243
+ container: {
244
+ source: '.container',
245
+ proxy: {
246
+ mutation: true,
247
+ priority: -1,
248
+ rewrite: false
249
+ }
250
+ },
251
+
252
+ message: {
253
+ source: 'p.message',
254
+ parent: 'document',
255
+ options: function(options, message, type) {
256
+ var opts = {}
257
+ opts.content = message;
258
+ if (type) opts.classes = Object.array(type);
259
+ return opts;
260
+ }
261
+ },
262
+
263
+ editor: {
264
+ options: function(options, type, name) {
265
+ return Object.merge(
266
+ {source: type == 'area' ? 'textarea' : ('input' + (type ? '[type=' + type : ']'))},
267
+ name ? {attributes: {name: name}} : null
268
+ )
269
+ }
156
270
  },
157
271
 
158
272
  input: function(options, type, name) {
@@ -24,7 +24,7 @@ provides:
24
24
 
25
25
  LSD.Module.DOM = new Class({
26
26
  options: {
27
- nodeType: 1,
27
+ nodeType: 1
28
28
  },
29
29
 
30
30
  constructors: {
@@ -73,7 +73,7 @@ LSD.Module.DOM = new Class({
73
73
  var previous = this.previousSibling;
74
74
  var start = previous ? (previous.sourceLastIndex || previous.sourceIndex) : widget.sourceIndex || (widget.sourceIndex = 1);
75
75
  var sourceIndex = start;
76
- LSD.Module.DOM.walk(this, function(node) {
76
+ LSD.Module.DOM.each(this, function(node) {
77
77
  node.sourceIndex = ++sourceIndex;
78
78
  if (node.sourceLastIndex) node.sourceLastIndex += start;
79
79
  for (var parent = widget; parent; parent = parent.parentNode) {
@@ -89,24 +89,35 @@ LSD.Module.DOM = new Class({
89
89
 
90
90
  unsetParent: function(widget, index) {
91
91
  if (!widget) widget = this.parentNode;
92
- LSD.Module.DOM.walk(this, function(node) {
92
+ LSD.Module.DOM.each(this, function(node) {
93
93
  widget.dispatchEvent('nodeRemoved', node);
94
94
  });
95
95
  this.fireEvent('unregister', ['parent', widget]);
96
+ this.fireEvent('unsetParent', [widget, widget.document])
96
97
  this.removed = true;
97
98
  unset.call(this, widget, index);
98
99
  delete this.parentNode;
99
100
  delete this.removed;
100
101
  },
101
102
 
102
- appendChild: function(widget, override) {
103
- widget.parentNode = this;
104
- if (!widget.quiet && (override !== false) && this.toElement()) (override || function() {
105
- this.element.appendChild(widget.toElement());
106
- }).apply(this, arguments);
107
- delete widget.parentNode;
108
- widget.setParent(this, this.childNodes.push(widget) - 1);
109
- delete widget.quiet;
103
+ appendChild: function(child, override) {
104
+ // set parent first, so when child is possibly built via toElement call, it notifies parents
105
+ child.parentNode = this;
106
+ var result = this.captureEvent('appendChild', arguments);
107
+ if (result === false) return false;
108
+ if (!child.quiet && override !== false) {
109
+ var element = this.toElement();
110
+ if (child.getParentElement) element = child.getParentElement(this.element, this);
111
+ if (override && override.call) {
112
+ override = override(element, child.toElement());
113
+ if (override == null) override = false;
114
+ }
115
+ if (override !== false) (override || element).appendChild(child.toElement());
116
+ }
117
+ delete child.parentNode;
118
+ // set parent 'for real' and do callbacks
119
+ child.setParent(this, this.childNodes.push(child) - 1);
120
+ delete child.quiet;
110
121
  return true;
111
122
  },
112
123
 
@@ -149,20 +160,14 @@ LSD.Module.DOM = new Class({
149
160
  return clone;
150
161
  },
151
162
 
152
- setDocument: function(document, revert) {
153
- LSD.Module.DOM.walk(this, function(child) {
154
- if (revert) {
155
- delete child.ownerDocument;
156
- delete child.document;
157
- } else child.ownerDocument = child.document = document;
158
- child.fireEvent(revert ? 'unregister' : 'register', ['document', document]);
159
- child.fireEvent(revert ? 'unsetDocument' : 'setDocument', document);
160
- });
163
+ setDocument: function(document) {
164
+ LSD.Module.DOM.setDocument(this, document);
161
165
  return this;
162
166
  },
163
167
 
164
168
  unsetDocument: function(document) {
165
- return this.setDocument(document, true);
169
+ LSD.Module.DOM.setDocument(this, document, true);
170
+ return this;
166
171
  },
167
172
 
168
173
  inject: function(widget, where, quiet) {
@@ -202,8 +207,8 @@ LSD.Module.DOM = new Class({
202
207
  var wrapper = this.getWrapper();
203
208
  if (hard && this.written) for (var node; node = this.written.shift();) Element.dispose(node);
204
209
  var fragment = document.createFragment(content);
205
- var written = Array.prototype.slice.call(fragment.childNodes, 0);
206
- if (!hard) this.written.push.apply(this.written, written);
210
+ var written = LSD.slice(fragment.childNodes);
211
+ if (!hard && this.written) this.written.push.apply(this.written, written);
207
212
  else this.written = written;
208
213
  wrapper.appendChild(fragment);
209
214
  this.fireEvent('write', [written, hard])
@@ -225,10 +230,6 @@ LSD.Module.DOM = new Class({
225
230
  unwatchInjection: function(callback) {
226
231
  this.removeEvent('setDocument', callback);
227
232
  },
228
-
229
- onElementDispose: function() {
230
- if (this.parentNode) this.dispose();
231
- },
232
233
 
233
234
  dispose: function() {
234
235
  var parent = this.parentNode;
@@ -272,8 +273,16 @@ var unset = function(widget, index) {
272
273
  if (parent.lastChild == this) parent.lastChild = previous;
273
274
  };
274
275
 
275
- var inserters = {
276
+ /*
277
+ `inject` and `grab` methods accept optional argument that defines
278
+ the position where the element should be placed.
279
+
280
+ These are the unedited duplicate of mootools element inserters.
281
+ All of the manipilations boil down to either `insertBefore` or
282
+ `appendChild`.
283
+ */
276
284
 
285
+ var inserters = {
277
286
  before: function(context, element){
278
287
  var parent = element.parentNode;
279
288
  if (parent) return parent.insertBefore(context, element);
@@ -291,32 +300,58 @@ var inserters = {
291
300
  top: function(context, element){
292
301
  return element.insertBefore(context, element.firstChild);
293
302
  }
294
-
295
303
  };
296
304
 
297
- LSD.Module.Events.addEvents.call(LSD.Module.DOM.prototype, {
298
- destroy: function() {
299
- if (this.parentNode) this.dispose();
305
+ Object.append(LSD.Module.DOM, {
306
+ dispose: function(target) {
307
+
300
308
  },
301
309
 
302
- element: {
303
- /*
304
- When dispose event comes from the element,
305
- it is is already removed from dom
306
- */
307
- dispose: 'onElementDispose'
308
- }
309
- });
310
-
311
- Object.append(LSD.Module.DOM, {
312
- walk: function(element, callback, bind, memo) {
313
- var widget = element.lsd ? element : LSD.Module.DOM.find(element, true);
310
+ destroy: function(target) {
311
+ var node = LSD.Module.DOM.identify(target);
312
+ LSD.Module.DOM.walk(node.element, function(element) {
313
+ var widget = element.uid && LSD.Module.DOM.find(element, true);
314
+ if (widget) widget.destroy(true);
315
+ });
316
+ Element.destroy(node.element);
317
+ },
318
+
319
+ clone: function(target, parent, before) {
320
+ var node = LSD.Module.DOM.identify(target);
321
+ parent = (parent === true) ? [node.parent, node.element.parentNode] : parent || false;
322
+ before = before === true ? node.element : before || node.element.nextSibling;
323
+ return node.parent.layout.render(node.element, parent, {clone: true}, {before: before});
324
+ },
325
+
326
+ setDocument: function(node, document, revert) {
327
+ LSD.Module.DOM.each(node, function(child) {
328
+ if (revert) {
329
+ delete child.ownerDocument;
330
+ delete child.document;
331
+ } else child.ownerDocument = child.document = document;
332
+ child.fireEvent(revert ? 'unregister' : 'register', ['document', document]);
333
+ child.fireEvent(revert ? 'unsetDocument' : 'setDocument', document);
334
+ });
335
+ },
336
+
337
+ walk: function(target, callback, bind, memo) {
338
+ if (target.lsd) target = target.element || target.toElement();
339
+ var result = callback.call(bind || this, target, memo);
340
+ if (result !== false)
341
+ for (var nodes = target.childNodes, node, i = 0; node = nodes[i]; i++)
342
+ if (node.nodeType == 1) LSD.Module.DOM.walk(node, callback, bind, memo);
343
+ return memo;
344
+ },
345
+
346
+ each: function(target, callback, bind, memo) {
347
+ var widget = target.lsd ? target : LSD.Module.DOM.find(target, true);
314
348
  if (widget) {
315
349
  var result = callback.call(bind || this, widget, memo);
350
+ if (result === false) return memo;
316
351
  if (result) (memo || (memo = [])).push(widget);
317
352
  }
318
- for (var nodes = element.childNodes, node, i = 0; node = nodes[i]; i++)
319
- if (node.nodeType == 1) LSD.Module.DOM.walk(node, callback, bind, memo);
353
+ for (var nodes = target.childNodes, node, i = 0; node = nodes[i]; i++)
354
+ if (node.nodeType == 1) LSD.Module.DOM.each(node, callback, bind, memo);
320
355
  return memo;
321
356
  },
322
357
 
@@ -324,6 +359,22 @@ Object.append(LSD.Module.DOM, {
324
359
  return target.lsd ? target : ((!lazy || target.uid) && Element[lazy ? 'retrieve' : 'get'](target, 'widget'));
325
360
  },
326
361
 
362
+ identify: function(target) {
363
+ var widget = LSD.Module.DOM.find(target);
364
+ if ((target.lsd ? widget : widget && widget.element) == target)
365
+ return {element: widget.element, widget: widget, parent: widget.parentNode};
366
+ else
367
+ return {element: target, parent: widget};
368
+ },
369
+
370
+ getID: function(target) {
371
+ if (target.lsd) {
372
+ return target.attributes.itemid;
373
+ } else {
374
+ return target.getAttribute('itemid');
375
+ }
376
+ },
377
+
327
378
  findNext: function(target) {
328
379
  var widget = target;
329
380
  if (widget && !widget.lsd)
@@ -336,14 +387,6 @@ Object.append(LSD.Module.DOM, {
336
387
  else stack.push(item.parentNode);
337
388
  }
338
389
  return widget;
339
- },
340
-
341
- getID: function(target) {
342
- if (target.lsd) {
343
- return target.attributes.itemid;
344
- } else {
345
- return target.getAttribute('itemid');
346
- }
347
390
  }
348
391
  });
349
392
 
@@ -352,4 +395,4 @@ Object.append(LSD.Module.DOM, {
352
395
  LSD.Options.document = {
353
396
  add: 'setDocument',
354
397
  remove: 'unsetDocument'
355
- }
398
+ };
@@ -55,8 +55,15 @@ var Expectations = LSD.Module.Expectations = new Class({
55
55
  if (selector.indexOf) selector = Slick.parse(selector);
56
56
  if (selector.expressions) selector = selector.expressions[0][0];
57
57
  if (!this.expectations) this.expectations = {};
58
- var id = selector.id;
59
- var index = self ? 'self' : (selector.combinator == ' ' && id) ? 'id' : selector.combinator || 'self';
58
+ var id = selector.id, combinator = selector.combinator;
59
+ switch (combinator) {
60
+ case '&':
61
+ self = true;
62
+ break;
63
+ case '&&':
64
+ return Expectations.setRootExpectation.call(this, selector, callback, true);
65
+ }
66
+ var index = self ? 'self' : (combinator == ' ' && id) ? 'id' : combinator || 'self';
60
67
  var expectations = this.expectations[index];
61
68
  if (!expectations) expectations = this.expectations[index] = {};
62
69
  if (selector.combinator && !self) {
@@ -104,14 +111,30 @@ var Expectations = LSD.Module.Expectations = new Class({
104
111
  if (iterator === true) iterator = function(widget) {
105
112
  if (widget.match(selector)) callback(widget, false);
106
113
  };
107
- if (selector.combinator && !self) {
114
+
115
+ var id = selector.id, combinator = selector.combinator;
116
+ switch (combinator) {
117
+ case '&':
118
+ self = true;
119
+ break;
120
+ case '&&':
121
+ return Expectations.setRootExpectation.call(this, selector, callback, false);
122
+ }
123
+ if (combinator && !self) {
108
124
  var id = selector.id;
109
- var index = (selector.combinator == ' ' && id) ? 'id' : selector.combinator;
125
+ var index = (combinator == ' ' && id) ? 'id' : combinator;
110
126
  remove(this.expectations[index][index == 'id' ? id : selector.tag], callback);
111
- if (this.document) this.getElements(selector.structure).each(function(widget) {
112
- if (selector.state) widget.unexpect(selector.state, callback);
113
- if (iterator) iterator(widget)
114
- });
127
+ if (this.document) {
128
+ if (!selector.structure) {
129
+ var separated = separate(selector);
130
+ selector.structure = { Slick: true, expressions: [[separated.structure]] }
131
+ if (separated.state) selector.state = separated.state;
132
+ }
133
+ this.getElements(selector.structure).each(function(widget) {
134
+ if (selector.state) widget.unexpect(selector.state, callback);
135
+ if (iterator) iterator(widget)
136
+ });
137
+ }
115
138
  } else {
116
139
  if (iterator) iterator(this);
117
140
  for (var types = ['pseudos', 'classes', 'attributes'], type, i = 0; type = types[i++];) {
@@ -171,6 +194,32 @@ var Expectations = LSD.Module.Expectations = new Class({
171
194
  }
172
195
  });
173
196
 
197
+ Expectations.setRootExpectation = function(exp, callback, state) {
198
+ if (state) {
199
+ var finder = function(widget, state) {
200
+ Expectations.advanceRootExpectation(exp, widget, callback, state);
201
+ };
202
+ finder.callback = callback;
203
+ return this.expect('::root', finder);
204
+ } else {
205
+ return this.unexpect('::root', callback, null, function(widget) {
206
+ Expectations.advanceRootExpectation(exp, widget, callback, false);
207
+ });
208
+ }
209
+ };
210
+
211
+ Expectations.advanceRootExpectation = function(exp, widget, callback, state) {
212
+ if (exp.tag == '*' && !exp.classes && !exp.attributes && !exp.id) {
213
+ if (state) widget.expect({combinator: ' ', pseudos: exp.pseudos}, callback, true);
214
+ else widget.unexpect({combinator: ' ', pseudos: exp.pseudos}, callback, true, function(widget) {
215
+ callback(widget, false);
216
+ })
217
+ } else {
218
+ var expression = {combinator: ' ', tag: exp.tag, classes: exp.classes, pseudos: exp.pseudos, attributes: exp.attributes, id: exp.id};
219
+ widget[state ? 'expect' : 'unexpect'](expression, callback, null, callback);
220
+ }
221
+ }
222
+
174
223
  var check = function(type, value, state, target) {
175
224
  var expectations = this.expectations
176
225
  if (!target) {