bowline 0.5.6 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -99,7 +99,7 @@ Which will generate code a bit like this:
99
99
 
100
100
  Now, in the view you can bind HTML to this collection, by
101
101
  using the following javascript:
102
- $('#users').bindto('users');
102
+ $('#users').bowlineBind('UsersBinder');
103
103
 
104
104
  You should probably become familiar with Chain.js (which bowline uses for binding): http://wiki.github.com/raid-ox/chain.js/
105
105
 
@@ -222,7 +222,7 @@ Usage for a collection (of users):
222
222
  jQuery(function($){
223
223
  $.bowline.ready(function(){
224
224
  // Bind the element users to UserBinder
225
- var users = $('#users').bindto('users', function(){
225
+ var users = $('#users').bowlineBind('UsersBinder', function(){
226
226
  var self = $(this);
227
227
  self.find('.destroy').click(function(){
228
228
  self.invoke('destroy');
data/TODO CHANGED
@@ -3,7 +3,7 @@ Use new Rails gem packaging system
3
3
  Ideas:
4
4
  * bowline-notification gem (Growl)
5
5
 
6
- Investigate thread safety
6
+ Investigate thread safety (for Bowline::Desktop::JS)
7
7
 
8
8
  Load all required JS through Bowline (so you only have to require one JS file)
9
9
 
@@ -20,4 +20,11 @@ Tutorials:
20
20
  CSS webkit-box (layouts)
21
21
  CSS search box & placeholder
22
22
 
23
- Don't run initializers during rake tasks
23
+ - Don't run initializers during rake tasks
24
+ - Find out why build is taking so long
25
+ - Add first-run initializers
26
+ - Add reload keyboard shortcut
27
+ - Add some sort of production mode
28
+
29
+ - strip exe (to make smaller)
30
+ - remove framework headers
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.6
1
+ 0.5.7
@@ -0,0 +1,92 @@
1
+ .drag {
2
+ -webkit-user-drag: element;
3
+ -webkit-user-select: none;
4
+ }
5
+
6
+ .in, .out {
7
+ -webkit-animation-timing-function: ease-in-out;
8
+ -webkit-animation-duration: 350ms;
9
+ }
10
+
11
+ .slideup.in {
12
+ -webkit-animation-name: slideupbottom;
13
+ z-index: 10;
14
+ }
15
+
16
+ .slideup.out {
17
+ -webkit-animation-name: slideuptop;
18
+ z-index: 0;
19
+ }
20
+
21
+ .slidedown.in {
22
+ -webkit-animation-name: slidedowntop;
23
+ z-index: 10;
24
+ }
25
+
26
+ .slidedown.out {
27
+ -webkit-animation-name: slidedownbottom;
28
+ z-index: 0;
29
+ }
30
+
31
+ @-webkit-keyframes dontmove {
32
+ from { opacity: 1; }
33
+ to { opacity: 1; }
34
+ }
35
+
36
+ @-webkit-keyframes slideuptop {
37
+ from { -webkit-transform: translateY(0); }
38
+ to { -webkit-transform: translateY(-100%); }
39
+ }
40
+
41
+ @-webkit-keyframes slideupbottom {
42
+ from { -webkit-transform: translateY(100%); }
43
+ to { -webkit-transform: translateY(0); }
44
+ }
45
+
46
+ @-webkit-keyframes slidedowntop {
47
+ from { -webkit-transform: translateY(-100%); }
48
+ to { -webkit-transform: translateY(0); }
49
+ }
50
+
51
+ @-webkit-keyframes slidedownbottom {
52
+ from { -webkit-transform: translateY(0); }
53
+ to { -webkit-transform: translateY(100%); }
54
+ }
55
+
56
+ .explode.in {
57
+ -webkit-animation-name: explodein;
58
+ }
59
+
60
+ .explode.out {
61
+ -webkit-animation-name: explodeout;
62
+ }
63
+
64
+ @-webkit-keyframes explodein {
65
+ from { -webkit-transform: scale(1.3); opacity: 0; }
66
+ to { -webkit-transform: scale(1); opacity: 1; }
67
+ }
68
+
69
+ @-webkit-keyframes explodeout {
70
+ from { -webkit-transform: scale(1); opacity: 1; }
71
+ to { -webkit-transform: scale(1.3); opacity: 0; }
72
+ }
73
+
74
+ .fade.in {
75
+ z-index: 10;
76
+ -webkit-animation-name: fadein;
77
+ }
78
+
79
+ .fade.out {
80
+ z-index: 0;
81
+ -webkit-animation-name: fadeout;
82
+ }
83
+
84
+ @-webkit-keyframes fadein {
85
+ from { opacity: 0; }
86
+ to { opacity: 1; }
87
+ }
88
+
89
+ @-webkit-keyframes fadeout {
90
+ from { opacity: 1; }
91
+ to { opacity: 0; }
92
+ }
data/assets/bowline.js CHANGED
@@ -30,11 +30,11 @@
30
30
  helper(method, *args)
31
31
  Invoke a method defined in any helper.
32
32
 
33
- bindto(element, klass, options = {})
33
+ bind(element, klass, options = {})
34
34
  Bind a element to a Bowline binder.
35
35
  Usually called via the jQuery helper functions.
36
36
  Usage:
37
- Bowline.bindto('#users', 'UsersBinder');
37
+ Bowline.bind('#users', 'UsersBinder');
38
38
 
39
39
  The options can either be a template hash:
40
40
  {
@@ -82,11 +82,16 @@
82
82
 
83
83
  These are how you usually bind elements, or invoke a binders class/instance methods.
84
84
 
85
- $.fn.bindto(klass, options)
85
+ $.fn.bowlineBind(klass, options)
86
86
  Associate an an element with a Bowline binder.
87
87
  Example:
88
- $("#users").bindto('UsersBinder');
89
-
88
+ $("#users").bowlineBind('UsersBinder');
89
+
90
+ $.fn.bowlineUnbind(klass)
91
+ Opposite of bowlineBind.
92
+ Example:
93
+ $("#users").bowlineUnbind('UsersBinder');
94
+
90
95
  $.fn.invoke(method, *args)
91
96
  Invoke a class/instance method on a Bowline binder.
92
97
 
@@ -118,6 +123,8 @@ var Bowline = {
118
123
  uuid: 0,
119
124
  bounds: {},
120
125
  trace: false,
126
+ // _app is a function defined in Objective C
127
+ enabled: typeof(_app) != "undefined",
121
128
 
122
129
  id: function(){
123
130
  return ++Bowline.uuid;
@@ -125,53 +132,53 @@ var Bowline = {
125
132
 
126
133
  // Usage: invoke(klass, method, *args)
127
134
  invoke: function(){
128
- var args = $.makeArray(arguments);
135
+ var args = jQuery.makeArray(arguments);
129
136
  var klass = args.shift();
130
137
  var method = args.shift();
131
- var id = Bowline.id();
138
+ var id = -1;
132
139
 
133
140
  var callback = args.pop();
134
141
  if(typeof(callback) == "function"){
142
+ id = Bowline.id();
135
143
  Bowline.callbacks[id] = callback;
136
144
  } else if(callback) {
137
145
  args.push(callback);
138
146
  }
147
+
139
148
  var msg = {
140
- klass:klass,
141
- method:method,
142
- args:args,
143
- id:id
149
+ klass: klass,
150
+ method: method,
151
+ args: args,
152
+ id: id,
144
153
  };
145
154
 
146
- Bowline.log("New message:")
147
- Bowline.log(msg);
155
+ Bowline.log("New message:", msg);
148
156
 
149
- // wx is a function defined in Objective C
150
- if(typeof(wx) != undefined)
151
- wx.call(JSON.stringify(msg));
157
+ if(Bowline.enabled)
158
+ _app.call(JSON.stringify(msg));
152
159
  },
153
160
 
154
161
  // Usage: instanceInvoke(klass, id, method, *args)
155
162
  instanceInvoke: function(){
156
- var args = $.makeArray(arguments);
163
+ var args = jQuery.makeArray(arguments);
157
164
  args.splice(1, 0, "instance_invoke");
158
165
  Bowline.invoke.apply(this, args);
159
166
  },
160
167
 
161
168
  // Usage: windowInvoke(method, *args)
162
169
  windowInvoke: function(){
163
- var args = $.makeArray(arguments);
170
+ var args = jQuery.makeArray(arguments);
164
171
  args.unshift("_window");
165
172
  Bowline.invoke.apply(this, args);
166
173
  },
167
174
 
168
175
  helper: function(){
169
- var args = $.makeArray(arguments);
176
+ var args = jQuery.makeArray(arguments);
170
177
  args.unshift("Helper");
171
- Bowline.invoke(args);
178
+ Bowline.invoke.apply(this, args);
172
179
  },
173
180
 
174
- bindto: function(el, klass, options){
181
+ bind: function(el, klass, options){
175
182
  el = jQuery(el);
176
183
  el.chain(options);
177
184
  el.data('bowline', klass);
@@ -179,22 +186,37 @@ var Bowline = {
179
186
  Bowline.bounds[klass] = [];
180
187
  Bowline.bounds[klass].push(el);
181
188
  jQuery(function(){
182
- Bowline.invoke(klass, "setup");
189
+ Bowline.invoke(klass, "setup", function(res){
190
+ Bowline.populate(klass, res);
191
+ });
183
192
  });
184
193
  },
185
194
 
195
+ unbind: function(el, klass){
196
+ var array = Bowline.bounds[klass]
197
+ if(!array) return;
198
+ array = jQuery.grep(array,
199
+ function(n){ return n != el }
200
+ );
201
+ Bowline.bounds[klass] = array;
202
+ },
203
+
186
204
  // Bowline functions
187
205
 
188
206
  invokeJS: function(str){
189
- Bowline.log("Invoking: " + str);
207
+ Bowline.log("Invoking:", str);
190
208
  return JSON.stringify(eval(str));
191
209
  },
192
210
 
193
211
  invokeCallback: function(id, res){
194
- Bowline.log("Callback: " + id);
212
+ Bowline.log("Callback:", id, res);
195
213
  if(!Bowline.callbacks[id]) return true;
196
- Bowline.callbacks[id](JSON.parse(res));
197
- delete Bowline.callbacks[id];
214
+ try {
215
+ Bowline.callbacks[id](JSON.parse(res));
216
+ delete Bowline.callbacks[id];
217
+ } catch(e) {
218
+ Bowline.log(e)
219
+ }
198
220
  return true;
199
221
  },
200
222
 
@@ -256,18 +278,22 @@ var Bowline = {
256
278
 
257
279
  findItem: function(el, id){
258
280
  var items = jQuery.grep(el.items(true), function(n, i){
259
- return $(n).item().id == id;
281
+ return jQuery(n).item().id == id;
260
282
  });
261
- return($(items[0]));
283
+ return(jQuery(items[0]));
262
284
  },
263
285
 
264
- log: function(msg){
265
- if(Bowline.trace)
266
- console.log(msg);
286
+ log: function(){
287
+ if( !Bowline.trace ) return;
288
+ var args = jQuery.makeArray(arguments);
289
+ args.unshift("(Bowline)");
290
+ console.log.apply(console, args);
267
291
  },
268
292
 
269
- warn: function(msg){
270
- console.warn(msg);
293
+ warn: function(){
294
+ var args = jQuery.makeArray(arguments);
295
+ args.unshift("(Bowline)");
296
+ console.warn.apply(console, args);
271
297
  }
272
298
  };
273
299
 
@@ -279,25 +305,31 @@ var Bowline = {
279
305
  // Class method
280
306
  var klass = $(this).data('bowline');
281
307
  args.unshift(klass);
282
- Bowline.invoke.apply(this, args);
308
+ Bowline.invoke.apply(Bowline, args);
283
309
  } else {
284
310
  // Instance method
285
311
  var klass = $(this).item('root').data('bowline');
286
312
  var id = $(this).item().id;
287
313
  args.unshift(id);
288
314
  args.unshift(klass);
289
- Bowline.instanceInvoke.apply(this, args);
315
+ Bowline.instanceInvoke.apply(Bowline, args);
290
316
  }
291
317
  } else {
292
318
  throw 'Chain not active';
293
319
  }
294
320
  };
295
-
296
- $.fn.bindto = function(){
321
+
322
+ $.fn.bowlineBind = function(){
297
323
  var args = $.makeArray(arguments);
298
324
  args.unshift(this);
299
- Bowline.bindto.apply(this, args);
325
+ Bowline.bind.apply(Bowline, args);
300
326
  };
327
+
328
+ $.fn.bowlineUnbind = function(){
329
+ var args = $.makeArray(arguments);
330
+ args.unshift(this);
331
+ Bowline.unbind.apply(Bowline, args);
332
+ }
301
333
  })(jQuery);
302
334
 
303
335
  jQuery(function($){
@@ -0,0 +1,81 @@
1
+ var BowlineMenu = function(element, options){
2
+ var defaults = {childSelector: "li", trace: false};
3
+ this.options = jQuery.extend({}, defaults, options);
4
+
5
+ this.element = jQuery(element);
6
+
7
+ if(this.options.current) this.change(this.options.current);
8
+
9
+ var self = this;
10
+ this.elements().click(function(){
11
+ var view = self.viewName(this);
12
+ self.change(view);
13
+ });
14
+ };
15
+
16
+ BowlineMenu.fn = BowlineMenu.prototype;
17
+
18
+ BowlineMenu.fn.log = function(){
19
+ if( !this.options.trace ) return;
20
+ var args = jQuery.makeArray(arguments);
21
+ args.unshift("(BowlineMenu)");
22
+ console.log.apply(console, args);
23
+ };
24
+
25
+ BowlineMenu.fn.onChange = function(func){
26
+ this.element.bind("change.bowline", func);
27
+ };
28
+
29
+ BowlineMenu.fn.triggerChange = function(data){
30
+ this.element.trigger("change.bowline", data);
31
+ };
32
+
33
+ BowlineMenu.fn.viewName = function(element){
34
+ return jQuery(element).dataset("view");
35
+ };
36
+
37
+ BowlineMenu.fn.currentName = function(){
38
+ return this.viewName(this.current);
39
+ };
40
+
41
+ BowlineMenu.fn.elements = function(){
42
+ return this.element.find(this.options.childSelector);
43
+ };
44
+
45
+ BowlineMenu.fn.elementFor = function(name){
46
+ return this.element.find(
47
+ "[data-view='" + name + "']:first"
48
+ );
49
+ };
50
+
51
+ BowlineMenu.fn.items = function(){
52
+ var self = this;
53
+ return jQuery.map(this.elements(), function(n){
54
+ return self.viewName(n);
55
+ });
56
+ };
57
+
58
+ BowlineMenu.fn.change = function(name){
59
+ if(name != false && jQuery.inArray(name, this.items()) == -1) return false;
60
+
61
+ var fromView = this.current;
62
+ var fromViewName = this.viewName(fromView);
63
+
64
+ var toView = this.elementFor(name);
65
+ var toViewName = name;
66
+
67
+ this.log("changing:", fromViewName, toViewName);
68
+
69
+ this.elements().removeClass("current");
70
+ if(toView) {
71
+ this.current = toView;
72
+ toView.addClass("current");
73
+ }
74
+
75
+ this.triggerChange({
76
+ toView: toView,
77
+ toViewName: toViewName,
78
+ fromView: fromView,
79
+ fromViewName: fromViewName
80
+ });
81
+ };
@@ -0,0 +1,66 @@
1
+ function BowlineState(opts){
2
+ this.options = opts || {};
3
+ this.states = {}
4
+ this.events = {}
5
+ this.current = this.options.initial;
6
+ }
7
+
8
+ BowlineState.fn = BowlineState.prototype;
9
+
10
+ BowlineState.fn.log = function(){
11
+ if( !this.options.trace ) return;
12
+ var args = jQuery.makeArray(arguments);
13
+ args.unshift("(BowlineState)");
14
+ console.log.apply(console, args);
15
+ };
16
+
17
+ BowlineState.fn.newEvent = function(name, opts){
18
+ if(!name) throw "Must supply name";
19
+ // Defaults to the same named state
20
+ if(!opts) opts = {};
21
+ if(!opts.to) opts.to = name;
22
+ this.events[name] = opts;
23
+ }
24
+
25
+ BowlineState.fn.newState = function(name, callbacks){
26
+ if(!name) throw "Must supply name";
27
+ this.states[name] = callbacks || {};
28
+ }
29
+
30
+ BowlineState.fn.change = function(){
31
+ var args = $.makeArray(arguments);
32
+ var name = args.shift();
33
+
34
+ var event = this.events[name]
35
+ if(!event) throw "Unknown event: " + name;
36
+ // TODO support arrays in event.from
37
+ if(event.from &&
38
+ event.from != "all" &&
39
+ this.current &&
40
+ event.from != this.current) {
41
+ this.log("Not changing state to:", event.to);
42
+ return;
43
+ }
44
+
45
+ if(!this.states.hasOwnProperty(event.to)) {
46
+ throw "Unknown state: " + event.to;
47
+ }
48
+
49
+ // Already at state
50
+ if(event.to == this.current) return;
51
+
52
+ var oldState = this.current;
53
+ var oldStateCB = this.states[oldState];
54
+ var newState = event.to;
55
+ var newStateCB = this.states[newState];
56
+
57
+ this.log("changing:", oldState, newState);
58
+
59
+ if(oldStateCB && oldStateCB.beforeExit) oldStateCB.beforeExit();
60
+ if(newStateCB.beforeEnter) newStateCB.beforeEnter.apply(this, args);
61
+
62
+ this.current = newState;
63
+
64
+ if(oldStateCB && oldStateCB.afterExit) oldStateCB.afterExit();
65
+ if(newStateCB.afterEnter) newStateCB.afterEnter();
66
+ }
@@ -0,0 +1,108 @@
1
+ // #view > *:not(.current) {
2
+ // display: none;
3
+ // }
4
+
5
+ jQuery.support.WebKitAnimationEvent = (typeof WebKitTransitionEvent == "object");
6
+
7
+ var BowlineView = function(element, options){
8
+ var defaults = {trace:false};
9
+ this.options = jQuery.extend({}, defaults, options);
10
+
11
+ if (this.options.preloadImages) {
12
+ jQuery.each(this.options.preloadImages, function(e){
13
+ (new Image()).src = e;
14
+ });
15
+ }
16
+
17
+ this.element = jQuery(element);
18
+
19
+ if(this.options.current){
20
+ this.current = jQuery(this.options.current);
21
+ this.current.addClass("current");
22
+ }
23
+ };
24
+
25
+ BowlineView.fn = BowlineView.prototype;
26
+
27
+ BowlineView.fn.log = function(){
28
+ if( !this.options.trace ) return;
29
+ var args = jQuery.makeArray(arguments);
30
+ args.unshift("(BowlineView)");
31
+ console.log.apply(console, args);
32
+ };
33
+
34
+ BowlineView.fn.onChange = function(func){
35
+ this.element.bind("change.bowline", func);
36
+ };
37
+
38
+ BowlineView.fn.triggerChange = function(data){
39
+ this.element.trigger("change.bowline", data);
40
+ };
41
+
42
+ BowlineView.fn.elements = function(){
43
+ return this.element.find(">*");
44
+ }
45
+
46
+ BowlineView.fn.findView = function(name){
47
+ return this.element.find("[data-view='" + name + "']:first");
48
+ };
49
+
50
+ BowlineView.fn.viewName = function(element){
51
+ return jQuery(element).dataset("view");
52
+ };
53
+
54
+ BowlineView.fn.change = function(name){
55
+ var fromView = this.current;
56
+ var fromViewName = this.viewName(fromView);
57
+ var toView = this.findView(name);
58
+ var toViewName = name;
59
+
60
+ this.log("changing:", fromViewName, toViewName);
61
+
62
+ if(toView.length == 0) throw 'Unknown view: ' + toViewName;
63
+
64
+ if(fromViewName == toViewName) return;
65
+
66
+ var animation = null;
67
+ if(this.options.animationCallback){
68
+ animation = this.options.animationCallback(
69
+ fromViewName, toViewName
70
+ );
71
+ } else {
72
+ // Could be blank - doesn't matter.
73
+ animation = this.current.dataset("animation");
74
+ }
75
+
76
+ if(!fromView) {
77
+ animation = null;
78
+ }
79
+
80
+ var self = this;
81
+ var callback = function(){
82
+ if (animation){
83
+ toView.removeClass("in " + animation);
84
+ if(fromView) {
85
+ fromView.removeClass("current out " + animation);
86
+ }
87
+ } else {
88
+ if(fromView) fromView.removeClass("current");
89
+ }
90
+ self.current = toView;
91
+ self.triggerChange({
92
+ fromView: fromView,
93
+ fromViewName: fromViewName,
94
+ toView: toView,
95
+ toViewName: toViewName
96
+ });
97
+ }
98
+
99
+ if(jQuery.support.WebKitAnimationEvent && animation){
100
+ toView.one("webkitAnimationEnd", callback);
101
+ this.log("using animation:", animation, toViewName);
102
+ toView.addClass(animation + " in current");
103
+ if(fromView) fromView.addClass(animation + " out");
104
+ } else {
105
+ toView.addClass("current");
106
+ callback();
107
+ }
108
+ };
@@ -0,0 +1,167 @@
1
+ /// jquery.dataset v0.1.0 -- HTML5 dataset jQuery plugin
2
+ /// http://orangesoda.net/jquery.dataset.html
3
+
4
+ /// Copyright (c) 2009, Ben Weaver. All rights reserved.
5
+ /// This software is issued "as is" under a BSD license
6
+ /// <http://orangesoda.net/license.html>. All warrenties disclaimed.
7
+
8
+ /// The HTML5 specification allows elements to have custom data
9
+ /// attributes that are prefixed with `data-'. They may be
10
+ /// conveniently accessed through an element's `dataset' property.
11
+ /// This plugin provides similar functionality.
12
+ ///
13
+ /// The methods in the plugin are designed to be similar to the
14
+ /// built-in `attr' and `data' methods. All names are without the
15
+ /// `data-' prefix.
16
+ //
17
+ /// These methods are defined:
18
+ ///
19
+ /// dataset()
20
+ /// Return an object with all custom attribute (name, value) items.
21
+ ///
22
+ /// dataset(name)
23
+ /// Return the value of the attribute `data-NAME'.
24
+ ///
25
+ /// dataset(name, value)
26
+ /// Set the value of attribtue `data-NAME' to VALUE.
27
+ ///
28
+ /// dataset({...})
29
+ /// Set many custom attributes at once.
30
+ ///
31
+ /// removeDataset(name)
32
+ /// Remove the attribute `data-NAME'.
33
+ ///
34
+ /// removeDataset([n1, n2, ...])
35
+ /// Remove the attributes `data-N1', `data-N2', ...
36
+
37
+ (function($) {
38
+ var PREFIX = 'data-',
39
+ PATTERN = /^data\-(.*)$/;
40
+
41
+ function dataset(name, value) {
42
+ if (value !== undefined) {
43
+ // dataset(name, value): set the NAME attribute to VALUE.
44
+ return this.attr(PREFIX + name, value);
45
+ }
46
+
47
+ switch (typeof name) {
48
+ case 'string':
49
+ // dataset(name): get the value of the NAME attribute.
50
+ return this.attr(PREFIX + name);
51
+
52
+ case 'object':
53
+ // dataset(items): set the values of all (name, value) items.
54
+ return set_items.call(this, name);
55
+
56
+ case 'undefined':
57
+ // dataset(): return a mapping of (name, value) items for the
58
+ // first element.
59
+ return get_items.call(this);
60
+
61
+ default:
62
+ throw 'dataset: invalid argument ' + name;
63
+ }
64
+ }
65
+
66
+ function get_items() {
67
+ return this.foldAttr(function(index, attr, result) {
68
+ var match = PATTERN.exec(this.name);
69
+ if (match) result[match[1]] = this.value;
70
+ });
71
+ }
72
+
73
+ function set_items(items) {
74
+ for (var key in items) {
75
+ this.attr(PREFIX + key, items[key]);
76
+ }
77
+ return this;
78
+ }
79
+
80
+ function remove(name) {
81
+ if (typeof name == 'string') {
82
+ // Remove a single attribute;
83
+ return this.removeAttr(PREFIX + name);
84
+ }
85
+ return remove_names(name);
86
+ }
87
+
88
+ function remove_names(obj) {
89
+ var idx, length = obj && obj.length;
90
+
91
+ // For any object, remove attributes named by the keys.
92
+ if (length === undefined) {
93
+ for (idx in obj) {
94
+ this.removeAttr(PREFIX + idx);
95
+ }
96
+ }
97
+ // For an array, remove attributes named by the values.
98
+ else {
99
+ for (idx = 0; idx < length; idx++) {
100
+ this.removeAttr(PREFIX + obj[idx]);
101
+ }
102
+ }
103
+
104
+ return this;
105
+ }
106
+
107
+ $.fn.dataset = dataset;
108
+ $.fn.removeDataset = remove_names;
109
+
110
+ })(jQuery);
111
+
112
+ (function($) {
113
+
114
+ function each_attr(proc) {
115
+ if (this.length > 0) {
116
+ $.each(this[0].attributes, proc);
117
+ }
118
+ return this;
119
+ }
120
+
121
+ function fold_attr(proc, acc) {
122
+ return fold((this.length > 0) && this[0].attributes, proc, acc);
123
+ }
124
+
125
+ /*
126
+ * A left-fold operator. The behavior is the same as $.each(),
127
+ * but the callback is called with the accumulator as the third
128
+ * argument. The default accumulator is an empty object.
129
+ */
130
+ function fold(object, proc, acc) {
131
+ var length = object && object.length;
132
+
133
+ // The default accumulator is an empty object.
134
+ if (acc === undefined) acc = {};
135
+
136
+ // Returning an empty accumulator when OBJECT is "false"
137
+ // makes FOLD more composable.
138
+ if (!object) return acc;
139
+
140
+ // Check to see if OBJECT is an array.
141
+ if (length !== undefined) {
142
+ for (var i = 0, value = object[i];
143
+ (i < length) && (proc.call(value, i, value, acc) !== false);
144
+ value = object[++i])
145
+ { }
146
+ }
147
+ // Object is a map of (name, value) items.
148
+ else {
149
+ for (var name in object) {
150
+ if (proc.call(object[name], name, object[name], acc) === false) break;
151
+ }
152
+ }
153
+
154
+ return acc;
155
+ }
156
+
157
+ function fold_jquery(proc, acc) {
158
+ if (acc === undefined) acc = [];
159
+ return fold(this, proc, acc);
160
+ }
161
+
162
+ $.fn.eachAttr = each_attr;
163
+ $.fn.foldAttr = fold_attr;
164
+ $.fn.fold = fold_jquery;
165
+ $.fold = fold;
166
+
167
+ })(jQuery);
data/bowline.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bowline}
8
- s.version = "0.5.6"
8
+ s.version = "0.5.7"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Alex MacCaw"]
12
- s.date = %q{2009-12-27}
12
+ s.date = %q{2010-01-19}
13
13
  s.default_executable = %q{bowline-gen}
14
14
  s.description = %q{Ruby/JS GUI framework}
15
15
  s.email = %q{alex@leadthinking.com}
@@ -26,8 +26,13 @@ Gem::Specification.new do |s|
26
26
  "Rakefile",
27
27
  "TODO",
28
28
  "VERSION",
29
+ "assets/animations.css",
29
30
  "assets/bowline.js",
31
+ "assets/bowline.menu.js",
32
+ "assets/bowline.state.js",
33
+ "assets/bowline.view.js",
30
34
  "assets/jquery.chain.js",
35
+ "assets/jquery.dataset.js",
31
36
  "assets/jquery.js",
32
37
  "assets/json2.js",
33
38
  "assets/osx/Info.plist.erb",
data/examples/example.js CHANGED
@@ -1,4 +1,4 @@
1
- $('#users').bindto('UsersBinder');
1
+ $('#users').bowlineBind('UsersBinder');
2
2
 
3
3
  // invoke collection method
4
4
  // This will invoke UserBinder.admins and fill #users with admins
@@ -11,7 +11,7 @@
11
11
  <script src="javascripts/application.js" type="text/javascript" charset="utf-8"></script>
12
12
  <script type="text/javascript" charset="utf-8">
13
13
  jQuery(function($){
14
- var tweets = $('#tweets').bindto('tweets');
14
+ var tweets = $('#tweets').bowlineBind('TweetsBinder');
15
15
 
16
16
  $('#updateSubmit').click(function(){
17
17
  tweets.invoke('update', $('#updateText').val());
@@ -68,10 +68,8 @@ module Bowline
68
68
 
69
69
  def setup(window) #:nodoc:
70
70
  self.windows << window
71
- window.bowline.populate(
72
- name, initial.to_js
73
- ).call
74
- true
71
+ items = initial
72
+ items.try(:to_js) || []
75
73
  end
76
74
 
77
75
  # Called by a window's JavaScript whenever that window is bound to this Binder.
@@ -41,12 +41,16 @@ module Bowline
41
41
  attr_reader :window, :id, :klass, :method, :args
42
42
 
43
43
  def initialize(window, atts)
44
- @window = window
45
- atts = atts.with_indifferent_access
46
- @id = atts[:id]
47
- @klass = atts[:klass]
48
- @method = atts[:method].to_sym
49
- @args = atts[:args] || []
44
+ @window = window
45
+ atts = atts.with_indifferent_access
46
+ @id = atts[:id]
47
+ @klass = atts[:klass]
48
+ @method = atts[:method].to_sym
49
+ @args = atts[:args] || []
50
+ end
51
+
52
+ def callback?
53
+ @id != -1
50
54
  end
51
55
 
52
56
  def invoke
@@ -59,9 +63,11 @@ module Bowline
59
63
  trace "JS invoking: #{klass}.#{method}(#{args.join(',')})"
60
64
  if object.respond_to?(:js_exposed?) && object.js_exposed?
61
65
  result = object.js_invoke(window, method, *args)
62
- proxy = Proxy.new(window)
63
- proxy.Bowline.invokeCallback(id, result)
64
- window.run_script(proxy.to_s)
66
+ if callback?
67
+ proxy = Proxy.new(window)
68
+ proxy.Bowline.invokeCallback(id, result.to_js.to_json)
69
+ window.run_script(proxy.to_s)
70
+ end
65
71
  else
66
72
  raise "Method not allowed"
67
73
  end
@@ -49,7 +49,11 @@ module Bowline
49
49
  # window.file = :about
50
50
  # Passing a symbol will load the corrosponding HTML file
51
51
  # in the public directory. In this case, it'll load about.html
52
-
52
+
53
+ ##
54
+ # :singleton-method: url=(address)
55
+ # Navigate to a HTTP address.
56
+
53
57
  ##
54
58
  # :singleton-method: id
55
59
  # Internal ID for the window.
@@ -148,6 +152,10 @@ module Bowline
148
152
  ##
149
153
  # :singleton-method: shown?
150
154
  # Is this window currently shown?
155
+
156
+ ##
157
+ # :singleton-method: show_inspector(console = false)
158
+ # Show WebInspector
151
159
  end
152
160
 
153
161
  class MainWindow #:nodoc:
@@ -63,9 +63,12 @@ module Bowline
63
63
  else
64
64
  @window = Window.new
65
65
  end
66
- @window.script_callback = Proc.new {|str|
66
+ # Has to be an instance variable since
67
+ # it is getting GCed (even if I mark it).
68
+ @script_callback = Proc.new {|str|
67
69
  Bowline::Desktop::Bridge.call(self, str)
68
70
  }
71
+ @window.script_callback = @script_callback;
69
72
  end
70
73
 
71
74
  # Evaluate JavaScript in this window. Pass
@@ -1,3 +1,5 @@
1
+ require "net/http"
2
+
1
3
  module Bowline
2
4
  module Desktop
3
5
  module WindowMethods #:nodoc:
@@ -26,6 +28,13 @@ module Bowline
26
28
  end
27
29
  alias :load_file :file=
28
30
 
31
+ def url=(address)
32
+ unless address.is_a?(URI)
33
+ address = URI.parse(path)
34
+ end
35
+ self._url = address.to_s
36
+ end
37
+
29
38
  def select_dir(options = {})
30
39
  flags = 0
31
40
  flags |= Window::FD_OPEN if options[:open]
@@ -100,6 +100,16 @@ module Bowline
100
100
  $LOAD_PATH.uniq!
101
101
  end
102
102
 
103
+ def disable_dependency_loading
104
+ if configuration.cache_classes && !configuration.dependency_loading
105
+ ActiveSupport::Dependencies.unhook!
106
+ end
107
+ end
108
+
109
+ def initialize_dependency_mechanism
110
+ ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
111
+ end
112
+
103
113
  # Initializes ActiveRecord databases
104
114
  def initialize_database
105
115
  if defined?(ActiveRecord)
@@ -286,6 +296,8 @@ module Bowline
286
296
  require_frameworks
287
297
  set_autoload_paths
288
298
  add_plugin_load_paths
299
+ initialize_dependency_mechanism
300
+ disable_dependency_loading
289
301
 
290
302
  initialize_encoding
291
303
  initialize_database
@@ -303,14 +315,13 @@ module Bowline
303
315
  load_app_config
304
316
 
305
317
  load_plugins
318
+ load_application_classes
319
+ load_application_helpers
306
320
 
307
321
  load_application_initializers
308
322
 
309
323
  after_initialize
310
-
311
- load_application_classes
312
- load_application_helpers
313
-
324
+
314
325
  initialize_js
315
326
  initialize_windows
316
327
 
@@ -401,6 +412,13 @@ module Bowline
401
412
  # You can add gems with the #gem method.
402
413
  attr_accessor :gems
403
414
 
415
+ attr_accessor :dependency_loading
416
+
417
+ def threadsafe!
418
+ self.cache_classes = true
419
+ self.dependency_loading = false
420
+ end
421
+
404
422
  # Adds a single Gem dependency to the Bowline application. By default, it will require
405
423
  # the library with the same name as the gem. Use :lib to specify a different name.
406
424
  #
@@ -469,6 +487,7 @@ module Bowline
469
487
  self.frameworks = default_frameworks
470
488
  self.load_paths = default_load_paths
471
489
  self.load_once_paths = default_load_once_paths
490
+ self.dependency_loading = default_dependency_loading
472
491
  self.eager_load_paths = default_eager_load_paths
473
492
  self.log_path = default_log_path
474
493
  self.log_level = default_log_level
@@ -568,14 +587,18 @@ module Bowline
568
587
  def default_load_once_paths
569
588
  []
570
589
  end
590
+
591
+ def default_dependency_loading
592
+ true
593
+ end
571
594
 
572
595
  def default_eager_load_paths
573
596
  %w(
574
- app/binders
575
597
  app/models
576
598
  app/remote
577
- app/helpers
578
599
  app/windows
600
+ app/binders
601
+ app/helpers
579
602
  ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
580
603
  end
581
604
 
@@ -2,8 +2,8 @@ module Bowline
2
2
  # Provides paths to Bowline's required libraries.
3
3
  module Library
4
4
  PROJECT_URL = "http://bowline.s3.amazonaws.com/#{Platform.type}"
5
- DESKTOP_URL = "#{PROJECT_URL}/bowline-desktop"
6
- RUBYLIB_URL = "#{PROJECT_URL}/rubylib.zip"
5
+ DESKTOP_URL = "#{PROJECT_URL}/bowline-desktop.zip"
6
+ LIBS_URL = "#{PROJECT_URL}/libs.zip"
7
7
 
8
8
  # Path to a folder stored under the users
9
9
  # home directory containing the downloaded libraries.
@@ -20,22 +20,16 @@ module Bowline
20
20
  end
21
21
  module_function :desktop_path
22
22
 
23
- # Path to Ruby's stdlib
24
- def rubylib_path
25
- File.join(path, "rubylib")
23
+ def libs_path
24
+ File.join(path, "libs")
26
25
  end
27
- module_function :rubylib_path
26
+ module_function :libs_path
28
27
 
29
28
  def local_bowline_path
30
29
  File.join(APP_ROOT, "vendor", "bowline")
31
30
  end
32
31
  module_function :local_bowline_path
33
32
 
34
- def local_rubylib_path
35
- File.join(APP_ROOT, "vendor", "rubylib")
36
- end
37
- module_function :local_rubylib_path
38
-
39
33
  def local_build_path
40
34
  File.join(APP_ROOT, "build")
41
35
  end
@@ -44,7 +38,7 @@ module Bowline
44
38
  # Returns true if all required libraries exist.
45
39
  def ready?
46
40
  File.exist?(desktop_path) &&
47
- File.directory?(rubylib_path) &&
41
+ File.directory?(libs_path) &&
48
42
  File.directory?(local_bowline_path)
49
43
  end
50
44
  module_function :ready?
@@ -15,7 +15,7 @@ module Bowline
15
15
 
16
16
  # Log an error backtrace if debugging is activated
17
17
  def log_error(e=$!)
18
- debug "#{e}\n\t" + e.backtrace.join("\n\t")
18
+ Bowline.logger.error "#{e}\n\t" + e.backtrace.join("\n\t")
19
19
  end
20
20
  module_function :log_error
21
21
  public :log_error
@@ -4,6 +4,44 @@ require 'rbconfig'
4
4
 
5
5
  namespace :app do
6
6
  namespace :build do
7
+ namespace :osx do
8
+ desc "Copy WebKit into app's Frameworks"
9
+ task :webkit_framework => :environment do
10
+ config = Bowline.configuration
11
+ build_path = Bowline::Library.local_build_path
12
+ app_path = File.join(build_path, "#{config.name}.app")
13
+ contents_path = File.join(app_path, "Contents")
14
+
15
+ webkit_path = ENV["WEBKIT_PATH"] || "/Applications/WebKit.app/Contents/Frameworks/10.5"
16
+ unless File.directory?(webkit_path)
17
+ raise "Install the WebKit nightly: http://nightly.webkit.org/"
18
+ end
19
+ frameworks = ["WebKit", "JavaScriptGlue", "WebCore", "JavaScriptCore"]
20
+
21
+ FileUtils.cd(contents_path) do
22
+ FileUtils.mkdir("Frameworks")
23
+
24
+ frameworks.each {|name|
25
+ name = "#{name}.framework"
26
+ FileUtils.cp_r(
27
+ File.join(webkit_path, name),
28
+ "Frameworks"
29
+ )
30
+ }
31
+
32
+ `install_name_tool -change \
33
+ /Volumes/Data/WebKit/52531/10.5/WebKit.framework/Versions/A/WebKit \
34
+ @executable_path/../Frameworks/WebKit.framework/Versions/A/WebKit \
35
+ MacOS/#{config.name}`
36
+
37
+ `install_name_tool -change \
38
+ /Volumes/Data/WebKit/52531/10.5/WebCore.framework/Versions/A/WebCore \
39
+ @executable_path/../Frameworks/WebCore.framework/Versions/A/WebCore \
40
+ MacOS/#{config.name}`
41
+ end
42
+ end
43
+ end
44
+
7
45
  task :osx => :environment do
8
46
  unless Bowline::Library.ready?
9
47
  Rake::Task["libs:setup"].invoke
@@ -61,22 +99,19 @@ namespace :app do
61
99
  %w{assets pkg examples bin templates .git}.each do |unused|
62
100
  FileUtils.rm_rf(File.join(bowline_path, unused))
63
101
  end
64
-
65
- rubylib_path = "rubylib"
66
- FileUtils.rm_rf(rubylib_path)
67
- FileUtils.cp_r(
68
- Bowline::Library.rubylib_path,
69
- rubylib_path
70
- )
71
102
  end
72
103
  end
73
104
 
74
- # Copy Bowline binary
105
+ # Copy Bowline binary & libs
75
106
  FileUtils.mkdir("MacOS")
76
107
  FileUtils.cp(
77
108
  Bowline::Library.desktop_path,
78
109
  File.join("MacOS", config.name)
79
110
  )
111
+ FileUtils.cp_r(
112
+ Bowline::Library.libs_path,
113
+ File.join("MacOS", "libs")
114
+ )
80
115
  end
81
116
  FileUtils.chmod_R(0755, app_path)
82
117
  FileUtils.chmod(0644, File.join(contents_path, "Info.plist"))
@@ -5,13 +5,14 @@ require 'progressbar'
5
5
  require 'zip/zip'
6
6
 
7
7
  def download(url)
8
+ puts "Retrieving: #{url}"
8
9
  name = url.split("/").last
9
10
  file = Tempfile.new("download_#{name}")
10
11
  url = URI.parse(url)
11
12
  req = Net::HTTP::Get.new(url.path)
12
13
  res = Net::HTTP.start(url.host, url.port) {|http|
13
14
  http.request(req) {|resp|
14
- pbar = ProgressBar.new("Downloading...", resp.content_length)
15
+ pbar = ProgressBar.new("Downloading", resp.content_length || 0)
15
16
  resp.read_body {|seg|
16
17
  pbar.inc(seg.length)
17
18
  file.write(seg)
@@ -41,7 +42,7 @@ def sym_or_copy(from, to)
41
42
  end
42
43
  end
43
44
 
44
- namespace :libs do
45
+ namespace :libs do
45
46
  task :unpack => :environment do
46
47
  # Lots of people are using Ruby 1.8 with Bowline.
47
48
  # When bowline-desktop loads, it doesn't know where the
@@ -53,33 +54,27 @@ namespace :libs do
53
54
  Bowline.lib_path,
54
55
  local_bowline_path
55
56
  ) unless File.directory?(local_bowline_path)
56
-
57
- local_rubylib_path = Bowline::Library.local_rubylib_path
58
- raise "Run libs:download task first" unless File.directory?(Bowline::Library.rubylib_path)
59
- sym_or_copy(
60
- Bowline::Library.rubylib_path,
61
- local_rubylib_path
62
- ) unless File.directory?(local_rubylib_path)
63
57
  end
64
58
 
65
59
  desc "Download Bowline's binary and pre-compiled libs"
66
60
  task :download => :environment do
67
61
  FileUtils.mkdir_p(Bowline::Library.path)
68
62
  desktop_path = Bowline::Library.desktop_path
69
- rubylib_path = Bowline::Library.rubylib_path
63
+ libs_path = Bowline::Library.libs_path
70
64
 
71
65
  unless File.exist?(desktop_path)
72
66
  desktop_tmp = download(Bowline::Library::DESKTOP_URL)
73
67
  desktop_tmp.close
74
- FileUtils.mv(desktop_tmp.path, desktop_path)
68
+ puts "Extracting bowline-desktop.zip"
69
+ unzip(desktop_tmp.path, Bowline::Library.path)
75
70
  FileUtils.chmod(0755, desktop_path)
76
71
  end
77
72
 
78
- unless File.directory?(rubylib_path)
79
- rubylib_tmp = download(Bowline::Library::RUBYLIB_URL)
80
- rubylib_tmp.close
81
- puts "Extracting..."
82
- unzip(rubylib_tmp.path, Bowline::Library.path)
73
+ unless File.directory?(libs_path)
74
+ libs_tmp = download(Bowline::Library::LIBS_URL)
75
+ libs_tmp.close
76
+ puts "Extracting libs.zip (this could take some time)"
77
+ unzip(libs_tmp.path, Bowline::Library.path)
83
78
  end
84
79
  end
85
80
 
@@ -88,8 +83,6 @@ namespace :libs do
88
83
  desc "Update Bowline's binary and pre-compiled libs"
89
84
  task :update => :environment do
90
85
  FileUtils.rm_rf(Bowline::Library.path)
91
- FileUtils.rm_rf(Bowline::Library.local_bowline_path)
92
- FileUtils.rm_rf(Bowline::Library.local_rubylib_path)
93
86
  Rake::Task["libs:setup"].invoke
94
87
  end
95
88
  end
@@ -2,10 +2,10 @@ module Bowline
2
2
  module Version #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 5
5
- TINY = 6
5
+ TINY = 7
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
 
9
9
  CODENAME = "If you can meet with Triumph and Disaster".freeze
10
10
  end
11
- end
11
+ end
@@ -10,8 +10,5 @@ Bowline::Initializer.run do |config|
10
10
 
11
11
  # config.gem "activerecord"
12
12
  # config.gem "net-mdns", :lib => 'net/dns/mdns'
13
- # config.gem "rack"
14
13
  # config.gem "rubyzip", :lib => 'zip/zip'
15
- # Bowline Edge:
16
- # config.gem "maccman-bowline", :lib => "bowline", :source => "http://gems.github.com"
17
14
  end
@@ -12,9 +12,7 @@
12
12
  <script type="text/javascript" charset="utf-8">
13
13
  // Binder Example:
14
14
  // jQuery(function($){
15
- // $.bowline.ready(function(){
16
- // $('#tweets').bindto('TweetsBinder');
17
- // })
15
+ // $('#tweets').bowlineBind('TweetsBinder');
18
16
  // });
19
17
  </script>
20
18
  </head>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bowline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex MacCaw
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-27 00:00:00 +00:00
12
+ date: 2010-01-19 00:00:00 +00:00
13
13
  default_executable: bowline-gen
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -59,8 +59,13 @@ files:
59
59
  - Rakefile
60
60
  - TODO
61
61
  - VERSION
62
+ - assets/animations.css
62
63
  - assets/bowline.js
64
+ - assets/bowline.menu.js
65
+ - assets/bowline.state.js
66
+ - assets/bowline.view.js
63
67
  - assets/jquery.chain.js
68
+ - assets/jquery.dataset.js
64
69
  - assets/jquery.js
65
70
  - assets/json2.js
66
71
  - assets/osx/Info.plist.erb