bowline 0.5.6 → 0.5.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/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