emerson 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -20,4 +20,5 @@ tmp
20
20
  .rspec
21
21
  .rvmrc
22
22
  .import/
23
- .sublime*
23
+ .sublime*
24
+ .wiprc
@@ -1,3 +1,3 @@
1
1
  module Emerson
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -1,4 +1,4 @@
1
- // Emerson.js 0.0.6
1
+ // Emerson.js 0.0.7
2
2
  //
3
3
  // (c) 2012 Corey Innis
4
4
  // Emerson may be freely distributed under the MIT license.
@@ -21,7 +21,7 @@
21
21
  }
22
22
 
23
23
  // Current version of the library. Keep in sync with `package.json`.
24
- Emerson.VERSION = '0.0.6';
24
+ Emerson.VERSION = '0.0.7';
25
25
 
26
26
  // Reference the base lib (one of jQuery, Zepto or Ender) as $.
27
27
  var $ = Emerson.base = (root.jQuery || root.Zepto || root.ender);
@@ -79,12 +79,12 @@
79
79
  var as_trait = element.add(element.find(selectors.traits)).filter(selectors.traits);
80
80
 
81
81
  _.each(as_view, function(html) {
82
- var element = $(html);
82
+ var element = $(html); // why jQuery here, if $sub() in a moment?
83
83
  attach.call(element, views, [element.data(attrs.view)]);
84
84
  });
85
85
 
86
86
  _.each(as_trait, function(html) {
87
- var element = $(html);
87
+ var element = $(html); // why jQuery here, if $sub() in a moment?
88
88
  attach.call(element, traits, element.data(attrs.traits).split(/\s+/), true);
89
89
  });
90
90
  });
@@ -97,21 +97,68 @@
97
97
  // --------------------------------------------------------------------------
98
98
 
99
99
  // ### View constructor.
100
- //
101
100
  // View instances are "subclasses" of the base lib object, decorated with our
102
101
  // View.prototype and the provided definition.
103
102
  function View() {}
104
103
 
105
- // View instance setup definition.
104
+ // ### View setup definition.
106
105
  _.extend(View, {
107
106
  setup : {
108
107
  initialize : function() {},
108
+ connected : false,
109
109
  subscribe : {}
110
110
  }
111
111
  });
112
112
 
113
- // View instance prototype definition.
114
- _.extend(View.prototype, {});
113
+ // ### View prototype definition.
114
+ // **TODO**: Add specs for #connect & #outlet.
115
+ //
116
+ // * `connect` specifies which, if any, `outlets` should be registered as
117
+ // methods on the instance.
118
+ //
119
+ // false - do not connect any outlets (default)
120
+ // true - connect all outlets
121
+ // [outlet(s)] - connect the named outlets.
122
+ //
123
+ // * `outlet` returns descendent element(s) with matching a `data-outlet`
124
+ // attribute. This may be used for a given outlet whether or not it has
125
+ // been "connected". Outlets are useful as a means of allowing for View
126
+ // and Trait definitions with somewhat flexible DOM. Rather than using
127
+ // specific selectors (or polluting the `class` attribute), the DOM for
128
+ // a given instance indicates which nodes should match for the View.
129
+ _.extend(View.prototype, {
130
+ connect : function(config) {
131
+ var self = this;
132
+ var outlets = this.find('[data-outlet]');
133
+
134
+ if(config === true) {
135
+ _.each(outlets, function(subject) {
136
+ var outlet = $(subject);
137
+
138
+ self[outlet.data('outlet')] = function() {
139
+ return outlet;
140
+ };
141
+ });
142
+ }
143
+ else if($.isArray(config)) {
144
+ _.each(config, function(key) {
145
+ var outlet = self.find('[data-outlet="' + key + '"]');
146
+
147
+ if(outlet.length) {
148
+ self[key] = function() {
149
+ return outlet;
150
+ };
151
+ }
152
+ });
153
+ }
154
+
155
+ return this;
156
+ },
157
+
158
+ outlet : function(key) {
159
+ return this.find('[data-outlet="' + key + '"]');
160
+ }
161
+ });
115
162
 
116
163
 
117
164
  // Internal Implementation
@@ -195,7 +242,7 @@
195
242
  var id = eid(this[0]);
196
243
 
197
244
  _.each(_.flatten(keys), function(key) {
198
- var mode, match, built, init, events, set;
245
+ var mode, match, built, init, events, set, setup;
199
246
 
200
247
  if(mode_p && (match = /^([^(]+)\((.+)\)/.exec(key))) {
201
248
  key = match[1];
@@ -208,17 +255,17 @@
208
255
  return; // do not re-apply.
209
256
  }
210
257
 
211
- // Build an instance, attach event handlers, initialize and record.
258
+ // Build an instance, connect outlets, bind events, init and record.
212
259
  if(def = library[key]) {
213
- built = def(self, self.context);
214
- init = def.setup.initialize;
215
- events = def.setup.subscribe;
260
+ setup = def.setup;
261
+ built = def(self, self.context);
262
+ built.connect(setup.connected);
216
263
 
217
- _.each(events, function(handler, key) {
264
+ _.each(setup.subscribe, function(handler, key) {
218
265
  bind(built, key, handler);
219
266
  });
220
267
 
221
- init.call(built, mode);
268
+ setup.initialize.call(built, mode);
222
269
  set.push(id);
223
270
  }
224
271
  });
@@ -231,17 +278,20 @@
231
278
  //
232
279
  // Emerson.view(key, {
233
280
  // subscribe : {
234
- // 'click' : handler, // simple
235
- // 'click focus' : handler, // multiple event types
236
- // 'selector' : { // specific child target
281
+ // 'click' : handler, // simple
282
+ // 'click focus' : handler, // multiple event types
283
+ // 'selector' : { // specific child target
237
284
  // 'click' : handler,
238
285
  // 'focus' : handler
239
286
  // },
240
- // document : { // bind document, for events
241
- // 'click' : handler // fired outside of the view
242
- // 'selector' : { // TODO
287
+ // document : { // bind document, for events
288
+ // 'click' : handler // fired outside of the view
289
+ // 'selector' : {
243
290
  // 'click' : handler
244
- // }
291
+ // }
292
+ // },
293
+ // 'outlet:name' : { // a custom key to specify a
294
+ // 'click' : handler // defined outlet as the scope
245
295
  // }
246
296
  // }
247
297
  // });
@@ -251,31 +301,38 @@
251
301
  // event argument is unadultered, allowing access to the full set of targets
252
302
  // as defined by the baselib (e.g., jQuery).
253
303
  //
254
- // Note that, in the document-binding case, an event like `click` would be a
255
- // bad idea. A more useful (and less costly) use case would be a form of
256
- // pub/sub.
304
+ // **Special notes regarding document-bound handlers**:
305
+ //
306
+ // Binding an event like `click` (without selector scope) to the document
307
+ // would likely be a bad idea. A more useful (and less costly) use case
308
+ // would be a sort of pub/sub. For example, view "A" could trigger an event
309
+ // indicating that it has rendered a new instance, to which "B" (elsewhere)
310
+ // would listen in order to update, say, a count of instances of "A".
257
311
  //
258
- // For example, view "A" could trigger an event indicating that it has
259
- // rendered a new instance, to which "B" (elsewhere) would listen in order
260
- // to update, say, a count of instances of "A".
261
- function bind(instance, key, handler, selector) {
312
+ // Additionally, event handlers bound to the document will not be cleaned
313
+ // up when the associated view instance is removed.
314
+ function bind(instance, key, handler, selector, binder) {
262
315
  if($.isPlainObject(handler)) {
263
- _.each(handler, function(subhandler, subkey) {
264
- bind(instance, subkey, subhandler, key);
265
- });
266
- }
267
- else {
268
- if(selector === 'document') {
269
- $(document).on(key, function() {
270
- return handler.apply(instance, arguments);
316
+ if(key === 'document') {
317
+ _.each(handler, function(subhandler, subkey) {
318
+ bind(instance, subkey, subhandler, undefined, $(document));
271
319
  });
272
320
  }
273
321
  else {
274
- instance.on(key, selector, function() {
275
- return handler.apply(instance, arguments);
322
+ _.each(handler, function(subhandler, subkey) {
323
+ bind(instance, subkey, subhandler, key, binder);
276
324
  });
277
325
  }
278
326
  }
327
+ else {
328
+ if(/^outlet/.test(selector)) {
329
+ selector = '[data-outlet="' + selector.split(':')[1] + '"]';
330
+ }
331
+
332
+ (binder || instance).on(key, selector, function() { // selector may be undefined
333
+ return handler.apply(instance, arguments);
334
+ });
335
+ }
279
336
  }
280
337
 
281
338
  // ### $sub
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emerson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-13 00:00:00.000000000 Z
12
+ date: 2012-05-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: transcendent views
15
15
  email: