bowline 0.6.3 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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);