bowline 0.6.3 → 0.9.1

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/README.txt CHANGED
@@ -83,6 +83,7 @@ App console:
83
83
  >> script/console
84
84
 
85
85
  Run application:
86
+ >> bundle package
86
87
  >> script/run
87
88
 
88
89
  Build package for distribution:
@@ -102,7 +103,7 @@ Which will generate code a bit like this:
102
103
 
103
104
  Now, in the view you can bind HTML to this collection, by
104
105
  using the following javascript:
105
- $('#users').bowlineBind('UsersBinder');
106
+ $('#users').bowlineChain('UsersBinder');
106
107
 
107
108
  You should probably become familiar with Chain.js (which bowline uses for binding): http://wiki.github.com/raid-ox/chain.js/
108
109
 
@@ -219,7 +220,7 @@ Usage for a collection (of users):
219
220
  jQuery(function($){
220
221
  $.bowline.ready(function(){
221
222
  // Bind the element users to UserBinder
222
- var users = $('#users').bowlineBind('UsersBinder', function(){
223
+ var users = $('#users').bowlineChain('UsersBinder', function(){
223
224
  var self = $(this);
224
225
  self.find('.destroy').click(function(){
225
226
  self.invoke('destroy');
@@ -273,8 +274,11 @@ Usage for a collection (of users):
273
274
  Install the Twitter gem:
274
275
  >> sudo gem install twitter
275
276
 
276
- Add the Twitter gem to config/environment.rb:
277
- config.gem "twitter"
277
+ Add the Twitter gem to Gemfile:
278
+ gem "twitter"
279
+
280
+ Bundle gems:
281
+ >> gem bundle
278
282
 
279
283
  run:
280
284
  >> script/run
data/Rakefile CHANGED
@@ -10,7 +10,8 @@ begin
10
10
  gemspec.add_dependency('templater', '>= 0.3.2')
11
11
  gemspec.add_dependency('activesupport', '>= 3.0.0.beta')
12
12
  gemspec.add_dependency('rubyzip2', '>= 2.0.1')
13
- gemspec.add_dependency('supermodel')
13
+ gemspec.add_dependency('bundler08', '>= 0.8.5')
14
+ gemspec.add_dependency('supermodel', '>= 0.1.3')
14
15
 
15
16
  gemspec.post_install_message = <<-POST_INSTALL_MESSAGE
16
17
  #{'*'*50}
@@ -24,7 +25,7 @@ begin
24
25
  POST_INSTALL_MESSAGE
25
26
  end
26
27
  rescue LoadError
27
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
28
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
28
29
  end
29
30
 
30
31
  task :write_version do
data/TODO CHANGED
@@ -18,10 +18,7 @@ Tutorials:
18
18
  CSS search box & placeholder
19
19
 
20
20
  - Don't run initializers during rake tasks
21
- - Add first-run initializers
22
- - Add some sort of production mode
23
- - Generate correct shebang on script files
24
- - Use App.root rather than APP_ROOT
21
+ - Fix permissions on script files
25
22
 
26
23
  - strip exe (to make smaller)
27
24
  - remove framework headers
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.3
1
+ 0.9.1
File without changes
@@ -0,0 +1,87 @@
1
+ if (typeof Bowline == "undefined") throw 'Bowline required';
2
+
3
+ // Usage:
4
+ // var chain = new Bowline.Chain(element);
5
+ // chain.bind("AssetBinder");
6
+
7
+ (function($){
8
+
9
+ Bowline.Chain = new SuperClass();
10
+ Bowline.Chain.include({
11
+ init: function(element, options){
12
+ this.options = options || {};
13
+ this.singleton = this.options.singleton || false;
14
+
15
+ this.element = $(element);
16
+ this.select = function(){ return true };
17
+
18
+ this.element.chain(options);
19
+ },
20
+
21
+ bind: function(binderName, options){
22
+ return Bowline.bind(binderName, this, options);
23
+ },
24
+
25
+ replace: function(value){
26
+ if (this.singleton) {
27
+ this.element.item("replace", value);
28
+ } else {
29
+ this.element.items("replace", value);
30
+ }
31
+ },
32
+
33
+ create: function(item){
34
+ if ( !item.id ) return;
35
+ if (this.singleton) {
36
+ var data = this.element.item();
37
+ // Different item has been created
38
+ if ( !data || data.id != item.id ) return;
39
+ this.element.item(item);
40
+ } else {
41
+ if ( !this.select(item) ) return;
42
+ this.element.items("add", item);
43
+ }
44
+ },
45
+
46
+ update: function(id, item){
47
+ if (this.singleton) {
48
+ var data = this.element.item();
49
+ if ( !data || data.id != item.id ) return;
50
+ this.element.item(item);
51
+ } else {
52
+ if ( !this.select(item) ) return;
53
+ var element = this.element.findItem({id:id});
54
+ if ( element ) element.item(item);
55
+ this.element.update();
56
+ }
57
+ },
58
+
59
+ destroy: function(id){
60
+ if (this.singleton) {
61
+ this.element.item("replace", {});
62
+ } else {
63
+ if ( !this.select(item) ) return;
64
+ var element = this.element.findItem({id:id});
65
+ if ( element ) element.item("remove");
66
+ this.element.update();
67
+ }
68
+ }
69
+ });
70
+
71
+ $.fn.findItem = function(item){
72
+ var result = $.grep(
73
+ this.items(true),
74
+ function(el){
75
+ return($(el).item().id == item.id);
76
+ }
77
+ );
78
+ return $(result);
79
+ };
80
+
81
+ $.fn.bowlineChain = function(){
82
+ var chain = new Bowline.Chain(this);
83
+ chain.bind.apply(chain, arguments);
84
+ return this;
85
+ };
86
+
87
+ })(jQuery);
@@ -1,351 +1,185 @@
1
- /*
2
- Bowline JavaScript API
3
-
4
- This library lets you call Ruby methods, and bind up elements.
5
- It requires jQuery, Chain.js and json2:
6
- http://jquery.com
7
- http://github.com/raid-ox/chain.js
8
- http://www.JSON.org/json2.js
9
-
10
- = Functions
11
-
12
- invoke(klass, method, *args)
13
- Invoke a class method on a particular class. Usually
14
- used to invoke methods on a binder. The class needs to
15
- be exposed to JS (using the Bowline::Desktop::Bridge#js_expose).
16
- Usage:
17
- Bowline.invoke('MyClass', 'my_method');
18
-
19
- instanceInvoke(klass, id, method, *args)
20
- Invoke an instance method an a binder.
21
- Usually called via the jQuery helper functions.
22
- Usage:
23
- Bowline.instanceInvoke('UsersBinder', 1, 'charge!');
24
-
25
- windowInvoke(method, *args)
26
- Invoke class method on this window's class.
27
- Usage:
28
- Bowline.windowInvoke('close');
29
-
30
- helper(method, *args)
31
- Invoke a method defined in any helper.
32
-
33
- bind(element, klass, options = {})
34
- Bind a element to a Bowline binder.
35
- Usually called via the jQuery helper functions.
36
- Usage:
37
- Bowline.bind('#users', 'UsersBinder');
38
-
39
- The options can either be a template hash:
40
- {
41
- '.name .first': {
42
- style: 'color: blue;',
43
- content: 'First Name: {first}'
44
- },
45
- '.name .last': 'Family Name: {last}',
46
- '.address': function(data, el){
47
- if(!data.address)
48
- el.hide();
49
- return data.address;
50
- },
51
- builder: function(){
52
- var data = this.item();
53
- this.find('.name').click(function(){alert(data.name)});
54
- }
55
- }
56
-
57
- Or the options can be a builder function:
58
- (function(){
59
- this.bind('click', function(){
60
- var data = this.item();
61
- alert(data);
62
- })
63
-
64
- For more documentation, look at the Chain.js library:
65
- http://wiki.github.com/raid-ox/chain.js/elementchain
66
-
67
- = Filtering items
68
-
69
- $('#users').items('filter', 'value');
70
-
71
- = Sorting items
72
-
73
- $('#users').items('sort', 'first_name');
74
-
75
- = Update events
76
-
77
- $('#users').update(function(){
78
- //...
79
- });
80
-
81
- = JQuery functions
82
-
83
- These are how you usually bind elements, or invoke a binders class/instance methods.
84
-
85
- $.fn.bowlineBind(klass, options)
86
- Associate an an element with a Bowline binder.
87
- Example:
88
- $("#users").bowlineBind('UsersBinder');
89
-
90
- $.fn.bowlineUnbind(klass)
91
- Opposite of bowlineBind.
92
- Example:
93
- $("#users").bowlineUnbind('UsersBinder');
94
-
95
- $.fn.invoke(method, *args)
96
- Invoke a class/instance method on a Bowline binder.
97
-
98
- If called on the bound element, in this example the #users div, then a class method
99
- will be called on the binder.
100
- Example:
101
- $("#users").invoke("my_class_method", "arg1");
102
-
103
- If called on a item inside a bound element, an instance method will be called.
104
- Example:
105
- $("#users").items(10).invoke("my_instance_method");
106
-
107
- = Debugging
108
-
109
- Turn on Bowline.trace to show debugging information:
110
- Bowline.trace = true
111
-
112
- = Using other libraries (e.g. Prototype)
113
-
114
- Although this library requires jQuery, its API is not jQuery
115
- specific. It's perfectly feasible to rewrite to use Prototype instead.
116
- Additionally, jQuery plays nicely with other libraries using it's noConflict() method.
117
- So you're still free to use other JavaScript libraries without fear of conflicts.
1
+ var Bowline = new SuperClass();
118
2
 
119
- */
120
-
121
- var BowlineBound = function(klass){
122
- this.klass = klass;
123
- this.options = {};
124
- this.elements = jQuery();
125
- };
126
-
127
- BowlineBound.fn = BowlineBound.prototype;
128
-
129
- BowlineBound.fn.updateOptions = function(opts){
130
- this.options = jQuery.extend({}, this.options, opts);
131
- this.singleton = this.options.singleton;
132
- }
133
-
134
- BowlineBound.fn.push = function(element){
135
- this.elements = this.elements.add(element);
136
- this.setup();
137
- }
138
-
139
- BowlineBound.fn.replace = function(items){
140
- if(this.singleton) {
141
- this.elements.item("replace", items);
142
- } else {
143
- this.elements.items("replace", items);
144
- }
145
- }
146
-
147
- BowlineBound.fn.create = function(id, item){
148
- if(this.singleton) {
149
- this.elements.item(item);
150
- } else {
151
- this.elements.items("add", item);
152
- }
153
- }
154
-
155
- BowlineBound.fn.update = function(id, item){
156
- if(!item.id) item.id = id;
157
- if(this.singleton){
158
- this.elements.item(item);
159
- } else {
160
- this.findElement(id).item(item);
161
- }
162
- }
163
-
164
- BowlineBound.fn.remove = function(id){
165
- if(this.singleton) {
166
- this.elements.item("replace", {});
167
- } else {
168
- this.findElement(id).item("remove");
169
- }
170
- }
171
-
172
- BowlineBound.fn.invoke = function(){
173
- var args = $.makeArray(arguments);
174
- args.unshift(this.klass);
175
- Bowline.invoke.apply(Bowline, args);
176
- }
177
-
178
- BowlineBound.fn.findElement = function(id){
179
- // TODO - increase efficiency
180
- var element = jQuery();
181
- jQuery.each(this.elements.items(true), function(){
182
- var sameItem = $(this).item().id == id;
183
- if(sameItem) element = element.add(this);
184
- });
185
- return element;
186
- }
187
-
188
- BowlineBound.fn.setup = function(){
189
- if (this.hasSetup) return;
190
- this.hasSetup = true;
191
- var self = this;
192
- jQuery(function(){
193
- Bowline.invoke(self.klass, "setup", function(opts){
194
- self.updateOptions(opts);
195
- });
196
- });
197
- }
198
-
199
- var Bowline = {
3
+ Bowline.extend({
200
4
  callbacks: {},
201
5
  uuid: 0,
202
6
  bounds: {},
203
7
  trace: false,
204
- // _app is a function defined in Objective C
8
+ updating: false,
9
+ // _app is a function defined in bowline-desktop
205
10
  enabled: typeof(_app) != "undefined",
206
11
 
207
12
  id: function(){
208
- return ++Bowline.uuid;
13
+ return ++this.uuid;
209
14
  },
210
15
 
211
16
  // Usage: invoke(klass, method, *args)
212
17
  invoke: function(){
18
+ if( this.updating ) return;
213
19
  var args = jQuery.makeArray(arguments);
214
20
  var klass = args.shift();
215
21
  var method = args.shift();
216
22
  var id = -1;
217
-
23
+
218
24
  var callback = args.pop();
219
25
  if(typeof(callback) == "function"){
220
- id = Bowline.id();
221
- Bowline.callbacks[id] = callback;
26
+ id = this.id();
27
+ this.callbacks[id] = callback;
222
28
  } else if(callback) {
223
29
  args.push(callback);
224
- }
30
+ }
225
31
 
226
32
  var msg = {
227
33
  klass: klass,
228
34
  method: method,
229
35
  args: args,
230
36
  id: id,
231
- };
37
+ };
232
38
 
233
- Bowline.log("New message:", msg);
39
+ this.log("New message:", msg);
234
40
 
235
- if(Bowline.enabled)
236
- _app.call(JSON.stringify(msg));
41
+ // Support for SuperModel instances
42
+ var serializer = function(key, value){
43
+ if (value == null) return value;
44
+ if (typeof value == "object" &&
45
+ typeof value.attributes == "function"){
46
+ return value.attributes();
47
+ } else {
48
+ return value;
49
+ }
50
+ };
51
+
52
+ if(this.enabled)
53
+ _app.call(JSON.stringify(msg, serializer));
237
54
  },
238
55
 
239
56
  // Usage: instanceInvoke(klass, id, method, *args)
240
57
  instanceInvoke: function(){
241
58
  var args = jQuery.makeArray(arguments);
242
59
  args.splice(1, 0, "instance_invoke");
243
- Bowline.invoke.apply(this, args);
60
+ this.invoke.apply(this, args);
244
61
  },
245
62
 
246
63
  // Usage: windowInvoke(method, *args)
247
64
  windowInvoke: function(){
248
65
  var args = jQuery.makeArray(arguments);
249
66
  args.unshift("_window");
250
- Bowline.invoke.apply(this, args);
67
+ this.invoke.apply(this, args);
251
68
  },
252
69
 
253
70
  helper: function(){
254
71
  var args = jQuery.makeArray(arguments);
255
72
  args.unshift("Bowline::Helpers");
256
- Bowline.invoke.apply(this, args);
257
- },
258
-
259
- bind: function(el, klass, options){
260
- el = jQuery(el);
261
-
262
- el.data("bowline", klass);
263
- el.chain(options);
264
-
265
- if(!Bowline.bounds[klass])
266
- Bowline.bounds[klass] = new BowlineBound(klass);
267
-
268
- Bowline.bounds[klass].push(el);
269
-
270
- // Shortcut
271
- Bowline[klass] = Bowline.bounds[klass];
272
- },
273
-
274
- unbind: function(el, klass){
275
- // TODO
276
- // var array = Bowline.bounds[klass];
277
- // if(!array) return;
278
- // array = jQuery.grep(array,
279
- // function(n){ return n.el != el }
280
- // );
281
- // Bowline.bounds[klass] = array;
73
+ this.invoke.apply(this, args);
282
74
  },
283
75
 
284
76
  openInspector: function(){
285
- if(Bowline.enabled)
77
+ if(this.enabled)
286
78
  _app.openInspector();
287
79
  },
288
80
 
81
+ bind: function(klass, object, options){
82
+ if ( !this.bounds[klass] ) {
83
+ this.bounds[klass] = [];
84
+ this.bounds[klass].push(object);
85
+ this.invoke(klass, "setup");
86
+ } else {
87
+ this.bounds[klass].push(object);
88
+ }
89
+ if (object.isModel)
90
+ this.extendModel(klass, object, options);
91
+ },
92
+
289
93
  // Bowline functions
290
94
 
291
95
  invokeJS: function(str){
292
- Bowline.log("Invoking:", str);
96
+ this.log("Invoking:", str);
97
+ this.updating = true;
98
+ var value;
293
99
  try {
294
- return JSON.stringify(eval(str));
100
+ value = JSON.stringify(eval(str));
295
101
  } catch(e) {
296
- Bowline.warn(e);
102
+ this.warn("Error at: " + e.sourceURL + ":" + e.line);
103
+ this.warn(str);
104
+ this.error(e);
297
105
  }
106
+ this.updating = false;
107
+ return value;
298
108
  },
299
109
 
300
110
  invokeCallback: function(id, res){
301
- Bowline.log("Callback:", id, res);
302
- if(!Bowline.callbacks[id]) return;
111
+ this.log("Callback:", id, res);
112
+ if(!this.callbacks[id]) return;
303
113
  try {
304
- Bowline.callbacks[id](JSON.parse(res));
305
- delete Bowline.callbacks[id];
114
+ this.callbacks[id](JSON.parse(res));
115
+ delete this.callbacks[id];
306
116
  } catch(e) {
307
- Bowline.warn(e)
117
+ this.warn("Error at: " + e.sourceURL + ":" + e.line);
118
+ this.error(e);
308
119
  }
309
120
  },
310
121
 
311
122
  replace: function(klass, items){
312
- if(!Bowline.bounds[klass]) return;
313
- Bowline.bounds[klass].replace(items);
123
+ if(!this.bounds[klass]) return;
124
+ this.eachBound(klass, function(object){
125
+ object.replace(items);
126
+ });
314
127
  },
315
128
 
316
129
  created: function(klass, id, item){
317
- if(!Bowline.bounds[klass]) return;
318
- Bowline.bounds[klass].create(id, item);
130
+ if(!this.bounds[klass]) return;
131
+ this.eachBound(klass, function(object){
132
+ object.create(item);
133
+ });
319
134
  },
320
135
 
321
136
  updated: function(klass, id, item){
322
- if(!Bowline.bounds[klass]) return;
323
- Bowline.bounds[klass].update(id, item);
137
+ if(!this.bounds[klass]) return;
138
+ this.eachBound(klass, function(object){
139
+ object.update(id, item);
140
+ });
324
141
  },
325
142
 
326
- removed: function(klass, id){
327
- if(!Bowline.bounds[klass]) return;
328
- Bowline.bounds[klass].remove(id);
143
+ destroyed: function(klass, id){
144
+ if(!this.bounds[klass]) return;
145
+ this.eachBound(klass, function(object){
146
+ object.destroy(id);
147
+ });
329
148
  },
330
149
 
331
- trigger: function(klass, event, data){
332
- if(!Bowline.bounds[klass]) return;
333
- Bowline.bounds[klass].elements.trigger(event, data);
334
- },
150
+ // System functions
335
151
 
336
- element: function(klass, id){
337
- if(!Bowline.bounds[klass]) return;
338
- return Bowline.bounds[klass].findElement(id);
152
+ eachBound: function(klass, callback){
153
+ for(var i in this.bounds[klass]){
154
+ callback(this.bounds[klass][i]);
155
+ }
339
156
  },
340
157
 
341
- // System functions
342
-
343
158
  loaded: function(){
344
- Bowline.windowInvoke("loaded!");
159
+ this.windowInvoke("loaded!");
160
+ },
161
+
162
+ extendModel: function(klass, object, options){
163
+ var self = this;
164
+ if ( !options ) options = {};
165
+
166
+ if (options.duplex) {
167
+ object.afterCreate(function(item){
168
+ object.invoke("create", item);
169
+ });
170
+
171
+ object.afterUpdate(function(item){
172
+ item.invoke("update", item);
173
+ });
174
+
175
+ object.afterDestroy(function(item){
176
+ item.invoke("destroy");
177
+ });
178
+ }
345
179
  },
346
180
 
347
181
  log: function(){
348
- if( !Bowline.trace ) return;
182
+ if( !this.trace ) return;
349
183
  var args = jQuery.makeArray(arguments);
350
184
  args.unshift("(Bowline)");
351
185
  console.log.apply(console, args);
@@ -355,42 +189,52 @@ var Bowline = {
355
189
  var args = jQuery.makeArray(arguments);
356
190
  args.unshift("(Bowline)");
357
191
  console.warn.apply(console, args);
192
+ },
193
+
194
+ error: function(){
195
+ var args = jQuery.makeArray(arguments);
196
+ args.unshift("(Bowline)");
197
+ console.error.apply(console, args);
358
198
  }
359
- };
199
+ });
360
200
 
361
201
  (function($){
362
- $.fn.invoke = function(){
363
- if($(this).chain("active")){
364
- var args = $.makeArray(arguments);
365
- var element = $(this).item("root");
366
- var klass = element.data("bowline");
367
- if(!klass) throw "Unknown class: " + klass;
202
+ if (typeof SuperModel != "undefined") {
203
+ SuperModel.extend({
204
+ bind: function(klass, options){
205
+ this.boundKlass = klass;
206
+ Bowline.bind(this.boundKlass, this, options);
207
+ },
368
208
 
369
- if(Bowline[klass].singleton){
370
- var id = element.item().id;
371
- args.unshift(id);
372
- args.unshift(klass);
373
- Bowline.instanceInvoke.apply(Bowline, args);
374
- } else {
375
- args.unshift(klass);
376
- Bowline.invoke.apply(Bowline, args);
209
+ delegateInvoke: function(){
210
+ var calls = jQuery.makeArray(arguments);
211
+ var self = this;
212
+ jQuery.each(calls, function(i, item){
213
+ self[item] = function(){
214
+ var args = jQuery.makeArray(arguments);
215
+ args.unshift(item);
216
+ this.invoke.apply(this, args);
217
+ }
218
+ });
219
+ },
220
+
221
+ invoke: function(){
222
+ var args = jQuery.makeArray(arguments);
223
+ args.unshift(this.boundKlass);
224
+ Bowline.invoke.apply(Bowline, args);
377
225
  }
378
- } else {
379
- throw 'Chain not active';
380
- }
381
- };
226
+ });
382
227
 
383
- $.fn.bowlineBind = function(){
384
- var args = $.makeArray(arguments);
385
- args.unshift(this);
386
- Bowline.bind.apply(Bowline, args);
387
- };
388
-
389
- $.fn.bowlineUnbind = function(){
390
- var args = $.makeArray(arguments);
391
- args.unshift(this);
392
- Bowline.unbind.apply(Bowline, args);
393
- };
228
+ SuperModel.fn.delegateInvoke = SuperModel.delegateInvoke;
229
+ SuperModel.include({
230
+ invoke: function(){
231
+ var args = jQuery.makeArray(arguments);
232
+ args.unshift(this.id);
233
+ args.unshift(this._class.boundKlass);
234
+ Bowline.instanceInvoke.apply(Bowline, args);
235
+ }
236
+ });
237
+ }
394
238
 
395
239
  $.fn.bowlineSerialize = function(){
396
240
  var array = $(this).serializeArray();
@@ -400,8 +244,8 @@ var Bowline = {
400
244
  });
401
245
  return object;
402
246
  };
403
- })(jQuery);
404
-
405
- jQuery(function($){
406
- Bowline.loaded();
407
- })
247
+
248
+ $(function(){
249
+ Bowline.loaded();
250
+ });
251
+ })(jQuery);