sproutcore 0.9.14 → 0.9.15
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +43 -0
- data/Manifest.txt +12 -3
- data/bin/sc-build +19 -3
- data/bin/sc-install +5 -0
- data/bin/sc-remove +5 -0
- data/bin/sc-update +5 -0
- data/frameworks/prototype/prototype.js +267 -230
- data/frameworks/sproutcore/HISTORY +281 -135
- data/frameworks/sproutcore/controllers/array.js +133 -22
- data/frameworks/sproutcore/controllers/collection.js +4 -5
- data/frameworks/sproutcore/controllers/object.js +8 -2
- data/frameworks/sproutcore/core.js +361 -159
- data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
- data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +2 -2
- data/frameworks/sproutcore/foundation/application.js +6 -1
- data/frameworks/sproutcore/foundation/benchmark.js +37 -11
- data/frameworks/sproutcore/foundation/date.js +1 -1
- data/frameworks/sproutcore/foundation/enumerator.js +105 -0
- data/frameworks/sproutcore/foundation/object.js +19 -20
- data/frameworks/sproutcore/foundation/responder.js +1 -1
- data/frameworks/sproutcore/foundation/set.js +164 -57
- data/frameworks/sproutcore/foundation/string.js +151 -47
- data/frameworks/sproutcore/foundation/utils.js +84 -3
- data/frameworks/sproutcore/lib/collection_view.rb +1 -0
- data/frameworks/sproutcore/license.js +28 -0
- data/frameworks/sproutcore/mixins/array.js +73 -209
- data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
- data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
- data/frameworks/sproutcore/mixins/observable.js +153 -84
- data/frameworks/sproutcore/mixins/selection_support.js +13 -1
- data/frameworks/sproutcore/models/record.js +74 -27
- data/frameworks/sproutcore/models/store.js +7 -3
- data/frameworks/sproutcore/server/rails_server.js +82 -0
- data/frameworks/sproutcore/server/rest_server.js +178 -0
- data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
- data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
- data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
- data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
- data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
- data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
- data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
- data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
- data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
- data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
- data/frameworks/sproutcore/validators/date.js +1 -7
- data/frameworks/sproutcore/views/collection/collection.js +7 -2
- data/frameworks/sproutcore/views/list_item.js +141 -3
- data/frameworks/sproutcore/views/split.js +14 -11
- data/frameworks/sproutcore/views/view.js +9 -6
- data/lib/sproutcore/build_tools/html_builder.rb +19 -3
- data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
- data/lib/sproutcore/bundle.rb +21 -0
- data/lib/sproutcore/bundle_manifest.rb +64 -20
- data/lib/sproutcore/helpers/capture_helper.rb +2 -2
- data/lib/sproutcore/library.rb +33 -9
- data/lib/sproutcore/merb/bundle_controller.rb +16 -5
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +1 -1
- data/{sc-config.rb → sc-config} +5 -2
- metadata +24 -5
@@ -10,101 +10,102 @@
|
|
10
10
|
|
11
11
|
<script>
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
//
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
//
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
//
|
46
|
-
//
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
// //
|
54
|
-
// // CASE 2: Manual-layout of view
|
55
|
-
// Test.context("CASE 2: Manual-layout of view", {
|
56
|
-
//
|
57
|
-
// "frame should reflect current offset settings at first": function() {
|
58
|
-
// var el = this.v.rootElement ;
|
59
|
-
// var f = { x: el.offsetTop, y: el.offsetLeft, width: el.offsetWidth, height: el.offsetHeight };
|
60
|
-
// SC.rectsEqual(f, this.v.get('frame')).shouldEqual(true) ;
|
61
|
-
// },
|
13
|
+
Test.context("CASE 1: Auto-layout view with no padding & no border", {
|
14
|
+
|
15
|
+
"frame should reflect current offset settings": function() {
|
16
|
+
var el = this.v.rootElement ;
|
17
|
+
var f = { x: el.offsetTop, y: el.offsetLeft, width: el.offsetWidth, height: el.offsetHeight };
|
18
|
+
console.log(this.v.get('frame').x) ;
|
19
|
+
console.log('this.frame', this.v.get('frame')) ;
|
20
|
+
SC.rectsEqual(f, this.v.get('frame')).shouldEqual(true) ;
|
21
|
+
},
|
22
|
+
|
23
|
+
"frame should change when CSS changed": function() {
|
24
|
+
var origFrame = this.v.get('frame') ;
|
25
|
+
|
26
|
+
this.v.addClassName('half') ;
|
27
|
+
this.v.viewFrameDidChange() ;
|
28
|
+
|
29
|
+
SC.rectsEqual(this.v.get('frame'), origFrame).shouldEqual(false) ;
|
30
|
+
|
31
|
+
// remove the class. make sure we have restored the frame
|
32
|
+
this.v.removeClassName('half') ; //reset
|
33
|
+
this.v.viewFrameDidChange() ;
|
34
|
+
SC.rectsEqual(this.v.get('frame'), origFrame).shouldEqual(true) ;
|
35
|
+
},
|
36
|
+
|
37
|
+
"setting frame should change style, even if it does not impact actual value": function() {
|
38
|
+
var f = this.v.get('frame') ;
|
39
|
+
var ret = this.v.set('frame', { x: 10, y: 10 }) ;
|
40
|
+
|
41
|
+
// it should change the style though
|
42
|
+
this.v.getStyle('left').shouldEqual('10px');
|
43
|
+
this.v.getStyle('top').shouldEqual('10px');
|
44
|
+
|
45
|
+
// change the top & left. Since the layout is static here, this should not actually
|
46
|
+
// change anything.
|
47
|
+
SC.rectsEqual(ret, f).shouldEqual(true) ;
|
48
|
+
},
|
49
|
+
|
50
|
+
setup: function() { this.v = SC.page.get('case1'); }
|
51
|
+
|
52
|
+
});
|
62
53
|
//
|
63
|
-
//
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
54
|
+
// CASE 2: Manual-layout of view
|
55
|
+
Test.context("CASE 2: Manual-layout of view", {
|
56
|
+
|
57
|
+
"frame should reflect current offset settings at first": function() {
|
58
|
+
var el = this.v.rootElement ;
|
59
|
+
var f = { x: el.offsetTop, y: el.offsetLeft, width: el.offsetWidth, height: el.offsetHeight };
|
60
|
+
SC.rectsEqual(f, this.v.get('frame')).shouldEqual(true) ;
|
61
|
+
},
|
62
|
+
|
63
|
+
"should get absolute positioning": function() {
|
64
|
+
this.v.getStyle('position').shouldEqual('absolute') ;
|
65
|
+
},
|
66
|
+
|
67
|
+
"frame should reflect set values exactly": function() {
|
68
|
+
var f = { x: 10, y: 10, width: 20, height: 20 } ;
|
69
|
+
var ret = this.v.set('frame', f);
|
70
|
+
SC.rectsEqual(f,ret).shouldEqual(true) ;
|
71
|
+
SC.rectsEqual(this.v.get('frame'), f).shouldEqual(true) ;
|
72
|
+
},
|
73
|
+
|
74
|
+
"actual offset should reflect set values exactly": function() {
|
75
|
+
var f = { x: 10, y: 10, width: 20, height: 20 } ;
|
76
|
+
var ret = this.v.set('frame', f);
|
77
|
+
var el = this.v.rootElement;
|
78
|
+
el.offsetLeft.shouldEqual(10) ;
|
79
|
+
el.offsetTop.shouldEqual(10) ;
|
80
|
+
el.offsetWidth.shouldEqual(20) ;
|
81
|
+
el.offsetHeight.shouldEqual(20) ;
|
82
|
+
},
|
83
|
+
|
84
|
+
"applying CSS class should not change frame": function() {
|
85
|
+
var f = this.v.get('frame') ;
|
86
|
+
this.v.addClassName('half') ;
|
87
|
+
SC.rectsEqual(this.v.get('frame'),f).shouldEqual(true) ;
|
88
|
+
},
|
89
|
+
|
90
|
+
"getting frame should cache the value": function() {
|
91
|
+
f = this.v.get('frame') ;
|
92
|
+
this.assertNotNull(this.v._frame) ;
|
93
|
+
},
|
94
|
+
|
95
|
+
setup: function() { this.v = SC.page.get('case2'); }
|
96
|
+
|
97
|
+
});
|
98
98
|
|
99
99
|
// CASE 3: Manual-layout View with padding & border
|
100
100
|
Test.context("CASE 3: Manual-layout of view with padding & border", {
|
101
101
|
|
102
102
|
"frame size should include padding and border": function() {
|
103
|
-
var f =
|
104
|
-
var el =
|
103
|
+
var f = v.get('frame') ;
|
104
|
+
var el = v.rootElement ;
|
105
105
|
|
106
|
-
|
107
|
-
Math.round(v.get('
|
106
|
+
//debugger ;
|
107
|
+
assertEqual(Math.round(v.get('styleWidth')), f.width-24, 'width') ;
|
108
|
+
assertEqual(Math.round(v.get('styleHeight')), f.height-24, 'height') ;
|
108
109
|
},
|
109
110
|
|
110
111
|
"changing frame size should subtract padding and border": function() {
|
@@ -155,11 +156,13 @@ Test.context("CASE 4: Absolute positioned Child view inside of view with overflo
|
|
155
156
|
Test.context("CASE 5: Non-positioned Child view inside of view with overflow = hidden", {
|
156
157
|
|
157
158
|
"frame origin should be 0,0 & size should match owner's innerFrame": function() {
|
159
|
+
SC.DEBUGIT = YES ;
|
158
160
|
var vf = this.v.get('innerFrame') ;
|
159
161
|
var f = this.v.child.get('frame') ;
|
160
162
|
f.x.shouldEqual(0) ;
|
161
163
|
f.y.shouldEqual(0) ;
|
162
164
|
f.width.shouldEqual(vf.width) ;
|
165
|
+
SC.DEBUGIT = NO ;
|
163
166
|
},
|
164
167
|
|
165
168
|
"nested frame origin should be 1,1 to account for border offset of parent": function() {
|
@@ -21,12 +21,6 @@ SC.Validator.Date = SC.Validator.extend(
|
|
21
21
|
*/
|
22
22
|
format: 'NNN d, yyyy h:mm:ss a',
|
23
23
|
|
24
|
-
/**
|
25
|
-
If true, dates will be converted to a natural language format if
|
26
|
-
possible such as "Tomorrow" or "Today".
|
27
|
-
*/
|
28
|
-
naturalLanguage: true,
|
29
|
-
|
30
24
|
/**
|
31
25
|
if we have a number, then convert to a date object.
|
32
26
|
*/
|
@@ -36,7 +30,7 @@ SC.Validator.Date = SC.Validator.extend(
|
|
36
30
|
date = new Date(object) ;
|
37
31
|
} else if (object instanceof Date) { date = object; }
|
38
32
|
|
39
|
-
if (date) object = date.format(this.get('format')
|
33
|
+
if (date) object = date.format(this.get('format')) ;
|
40
34
|
|
41
35
|
return object ;
|
42
36
|
},
|
@@ -1575,14 +1575,19 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1575
1575
|
|
1576
1576
|
// get the content. Bail if this cannot be used as an array.
|
1577
1577
|
var content = this.get('content') ;
|
1578
|
-
if (!content
|
1578
|
+
if (!content) return NO; // nothing to do
|
1579
|
+
|
1580
|
+
// determine the method to use
|
1581
|
+
var hasDestroyObject = $type(content.destroyObject) === T_FUNCTION ;
|
1582
|
+
var hasRemoveObject = $type(content.removeObject) === T_FUNCTION ;
|
1583
|
+
if (!hasDestroyObject && !hasRemoveObject) return NO; // nothing to do
|
1579
1584
|
|
1580
1585
|
// suspend property notifications and remove the objects...
|
1581
1586
|
if (content.beginPropertyChanges) content.beginPropertyChanges();
|
1582
1587
|
var idx = sel.get('length') ;
|
1583
1588
|
while(--idx >= 0) {
|
1584
1589
|
var item = sel.objectAt(idx) ;
|
1585
|
-
content.removeObject(item)
|
1590
|
+
(hasDestroyObject) ? content.destroyObject(item) : content.removeObject(item);
|
1586
1591
|
}
|
1587
1592
|
// begin notifying again...
|
1588
1593
|
if (content.endPropertyChanges) content.endPropertyChanges() ;
|
@@ -52,6 +52,15 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
52
52
|
*/
|
53
53
|
hasContentBranch: NO,
|
54
54
|
|
55
|
+
/**
|
56
|
+
(displayDelegate) The name of the property used for the checkbox value.
|
57
|
+
|
58
|
+
The checkbox will only be visible if this key is not null.
|
59
|
+
|
60
|
+
@type {String}
|
61
|
+
*/
|
62
|
+
contentCheckboxKey: null,
|
63
|
+
|
55
64
|
/**
|
56
65
|
(displayDelegate) Property key to use for the icon url
|
57
66
|
|
@@ -105,6 +114,13 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
105
114
|
var content = this.get('content') ;
|
106
115
|
var del = this.displayDelegate ;
|
107
116
|
|
117
|
+
// handle checkbox
|
118
|
+
var checkboxKey = this.getDelegateProperty(del, 'contentCheckboxKey') ;
|
119
|
+
if (checkboxKey) {
|
120
|
+
var checkboxValue = (content && content.get) ? content.get(checkboxKey) : false ;
|
121
|
+
html.push(this.renderCheckboxHtml(checkboxValue)) ;
|
122
|
+
}
|
123
|
+
|
108
124
|
// handle icon
|
109
125
|
if (this.getDelegateProperty(del, 'hasContentIcon')) {
|
110
126
|
var iconKey = this.getDelegateProperty(del,'contentIconKey') ;
|
@@ -147,12 +163,50 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
147
163
|
}
|
148
164
|
},
|
149
165
|
|
166
|
+
/**
|
167
|
+
Generates the HTML string used to represent the checkbox for your list
|
168
|
+
item. Override this to return your own custom HTML. The default version
|
169
|
+
will use the HTML provided by SC.CheckboxView.
|
170
|
+
|
171
|
+
@returns {String}
|
172
|
+
@param state {String} the checkbox state. YES, NO, or SC.MIXED_STATE
|
173
|
+
*/
|
174
|
+
renderCheckboxHtml: function(state) {
|
175
|
+
var ret ;
|
176
|
+
|
177
|
+
// Note: this basically takes the HTML from the checkbox view and then
|
178
|
+
// inserts class names as necessary. This is cached to avoid using too
|
179
|
+
// much memory.
|
180
|
+
if (state === SC.MIXED_STATE) {
|
181
|
+
ret = SC.ListItemView._mixedCheckboxHtml ;
|
182
|
+
if (!ret) {
|
183
|
+
ret = SC.CheckboxView.prototype.emptyElement ;
|
184
|
+
ret = ret.replace('class="', 'class="mixed ') ;
|
185
|
+
SC.ListItemView._mixedCheckboxHtml = ret ;
|
186
|
+
}
|
187
|
+
} else if (state) {
|
188
|
+
ret = SC.ListItemView._selectedCheckboxHtml ;
|
189
|
+
if (!ret) {
|
190
|
+
ret = SC.CheckboxView.prototype.emptyElement ;
|
191
|
+
ret = ret.replace('class="', 'class="sel ') ;
|
192
|
+
SC.ListItemView._selectedCheckboxHtml = ret ;
|
193
|
+
}
|
194
|
+
} else {
|
195
|
+
ret = SC.ListItemView._normalCheckboxHtml ;
|
196
|
+
if (!ret) {
|
197
|
+
ret = SC.CheckboxView.prototype.emptyElement ;
|
198
|
+
SC.ListItemView._normalCheckboxHtml = ret ;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
return ret ;
|
202
|
+
},
|
203
|
+
|
150
204
|
/**
|
151
205
|
renderIconHtml generates the html string used to represent the icon for
|
152
206
|
your list item. override this to return your own custom HTML
|
153
207
|
|
154
208
|
@returns {String}
|
155
|
-
@
|
209
|
+
@param icon {String} the icon property based on your view's contentIconKey
|
156
210
|
*/
|
157
211
|
renderIconHtml: function(icon){
|
158
212
|
var html = [];
|
@@ -177,7 +231,7 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
177
231
|
for your list item. override this to return your own custom HTML
|
178
232
|
|
179
233
|
@returns {String}
|
180
|
-
@
|
234
|
+
@param label {String} the label property based on your view's
|
181
235
|
contentValueKey
|
182
236
|
*/
|
183
237
|
renderLabelHtml: function(label){
|
@@ -203,7 +257,7 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
203
257
|
own custom HTML
|
204
258
|
|
205
259
|
@returns {String}
|
206
|
-
@
|
260
|
+
@param count {Integer} the label property based on your view's
|
207
261
|
contentValueKey
|
208
262
|
*/
|
209
263
|
renderCountHtml: function(count) {
|
@@ -245,6 +299,90 @@ SC.ListItemView = SC.View.extend(SC.Control, SC.InlineEditorDelegate,
|
|
245
299
|
return html.join('');
|
246
300
|
},
|
247
301
|
|
302
|
+
_isInsideElementWithClassName: function(className, evt) {
|
303
|
+
var el = Event.element(evt) ;
|
304
|
+
var rootElement = this.rootElement;
|
305
|
+
var ret = NO ;
|
306
|
+
while(!ret && el && (el !== rootElement)) {
|
307
|
+
if (Element.hasClassName(el, className)) ret = YES ;
|
308
|
+
el = el.parentNode ;
|
309
|
+
}
|
310
|
+
|
311
|
+
rootElement = el = null ; //avoid memory leaks
|
312
|
+
return ret ;
|
313
|
+
},
|
314
|
+
|
315
|
+
/** @private
|
316
|
+
mouseDown is handled only for clicks on the checkbox view or or action
|
317
|
+
button.
|
318
|
+
*/
|
319
|
+
mouseDown: function(evt) {
|
320
|
+
var del = this.displayDelegate ;
|
321
|
+
var checkboxKey = this.getDelegateProperty(del, 'contentCheckboxKey') ;
|
322
|
+
if (checkboxKey) {
|
323
|
+
if (this._isInsideElementWithClassName('sc-checkbox-view', evt)) {
|
324
|
+
this._addCheckboxActiveState() ;
|
325
|
+
this._isMouseDownOnCheckbox = YES ;
|
326
|
+
this._isMouseInsideCheckbox = YES ;
|
327
|
+
return true ;
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
return false ; // otherwise let normal handlers do it...
|
332
|
+
},
|
333
|
+
|
334
|
+
mouseUp: function(evt) {
|
335
|
+
var ret= NO ;
|
336
|
+
if (this._isMouseDownOnCheckbox) {
|
337
|
+
|
338
|
+
// update only if mouse inside on mouse up...
|
339
|
+
if (this._isMouseInsideCheckbox) {
|
340
|
+
var del = this.displayDelegate ;
|
341
|
+
var checkboxKey = this.getDelegateProperty(del, 'contentCheckboxKey') ;
|
342
|
+
var content = this.get('content') ;
|
343
|
+
if (content && content.get) {
|
344
|
+
var value = content.get(checkboxKey) ;
|
345
|
+
value = (value === SC.MIXED_STATE) ? YES : !value ;
|
346
|
+
content.set(checkboxKey, value) ;
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
this._removeCheckboxActiveState() ;
|
351
|
+
ret = YES ;
|
352
|
+
}
|
353
|
+
|
354
|
+
this._isMouseInsideCheckbox = this._isMouseDownOnCheckbox = NO ;
|
355
|
+
return ret ;
|
356
|
+
},
|
357
|
+
|
358
|
+
mouseOut: function(evt) {
|
359
|
+
if (this._isMouseDownOnCheckbox) {
|
360
|
+
this._removeCheckboxActiveState() ;
|
361
|
+
this._isMouseInsideCheckbox = NO ;
|
362
|
+
}
|
363
|
+
return NO ;
|
364
|
+
},
|
365
|
+
|
366
|
+
mouseOver: function(evt) {
|
367
|
+
if (this._isMouseDownOnCheckbox) {
|
368
|
+
this._addCheckboxActiveState() ;
|
369
|
+
this._isMouseInsideCheckbox = YES ;
|
370
|
+
}
|
371
|
+
return NO ;
|
372
|
+
},
|
373
|
+
|
374
|
+
_addCheckboxActiveState: function() {
|
375
|
+
var el = this.$sel('.sc-checkbox-view') ;
|
376
|
+
if (this.get('isEnabled')) Element.addClassName(el, 'active') ;
|
377
|
+
el = null ;
|
378
|
+
},
|
379
|
+
|
380
|
+
_removeCheckboxActiveState: function() {
|
381
|
+
var el = this.$sel('.sc-checkbox-view') ;
|
382
|
+
Element.removeClassName(el, 'active') ;
|
383
|
+
el = null ;
|
384
|
+
},
|
385
|
+
|
248
386
|
/**
|
249
387
|
Returns true if a click is on the label text itself to enable editing.
|
250
388
|
|
@@ -108,17 +108,14 @@ SC.SplitView = SC.View.extend(SC.DelegateSupport,
|
|
108
108
|
|
109
109
|
// thickness cannot be greater than the total of all the other views (
|
110
110
|
// except for the flexibleView) added together.
|
111
|
-
|
112
|
-
available =
|
113
|
-
|
114
|
-
|
115
|
-
var flexibleView = this.get('flexibleView')
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
available -= this.thicknessForView(currentView) ;
|
120
|
-
}
|
121
|
-
}
|
111
|
+
|
112
|
+
// available = total minus thickness of all views except "view" and
|
113
|
+
// "flexible view" that is the same as thickness 'view' plus thickness
|
114
|
+
// 'flexible view'
|
115
|
+
var flexibleView = this.get('flexibleView');
|
116
|
+
var available = this.thicknessForView(view) +
|
117
|
+
this.thicknessForView(flexibleView);
|
118
|
+
|
122
119
|
thickness = Math.min(thickness, available) ;
|
123
120
|
|
124
121
|
// cannot be less than 0
|
@@ -160,6 +157,7 @@ SC.SplitView = SC.View.extend(SC.DelegateSupport,
|
|
160
157
|
*/
|
161
158
|
computeFlexibleView: function() {
|
162
159
|
var flexibleView = this.get('flexibleView') ;
|
160
|
+
var originalFlexibleView = flexibleView ;
|
163
161
|
if (!flexibleView) {
|
164
162
|
var views = this.get('childNodes') ;
|
165
163
|
flexibleView = views[Math.ceil(views.length/2)] ;
|
@@ -170,6 +168,11 @@ SC.SplitView = SC.View.extend(SC.DelegateSupport,
|
|
170
168
|
flexibleView = flexibleView.get('nextSibling') ;
|
171
169
|
}
|
172
170
|
|
171
|
+
// save new flexible view if we had to fix it up.
|
172
|
+
if (originalFlexibleView !== flexibleView) {
|
173
|
+
this.set('flexibleView', flexibleView);
|
174
|
+
}
|
175
|
+
|
173
176
|
return flexibleView;
|
174
177
|
},
|
175
178
|
|
@@ -711,7 +711,7 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
|
|
711
711
|
this.viewFrameDidChange() ;
|
712
712
|
}
|
713
713
|
ret = this.getStyle(key) ;
|
714
|
-
ret = (ret === 'auto') ? null :
|
714
|
+
ret = (ret === 'auto') ? null : Math.round(parseFloat(ret)) ;
|
715
715
|
|
716
716
|
// all other properties just pass through (and do not change frame)
|
717
717
|
} else {
|
@@ -960,7 +960,8 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
|
|
960
960
|
// impact the offset
|
961
961
|
if (SC.Platform.Firefox) {
|
962
962
|
var parent = el.offsetParent ;
|
963
|
-
|
963
|
+
var overflow = (parent) ? Element.getStyle(parent, 'overflow') : 'visible' ;
|
964
|
+
if (overflow && overflow !== 'visible') {
|
964
965
|
var left = parseInt(Element.getStyle(parent, 'borderLeftWidth'),0) || 0 ;
|
965
966
|
var top = parseInt(Element.getStyle(parent, 'borderTopWidth'),0) || 0 ;
|
966
967
|
f.x += left; f.y += top ;
|
@@ -1087,7 +1088,8 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
|
|
1087
1088
|
// impact the offset
|
1088
1089
|
if (SC.Platform.Firefox) {
|
1089
1090
|
var parent = el.offsetParent ;
|
1090
|
-
|
1091
|
+
var overflow = (parent) ? Element.getStyle(parent, 'overflow') : 'visible' ;
|
1092
|
+
if (overflow && overflow !== 'visible') {
|
1091
1093
|
var left = parseInt(Element.getStyle(parent, 'borderLeftWidth'),0) || 0 ;
|
1092
1094
|
var top = parseInt(Element.getStyle(parent, 'borderTopWidth'),0) || 0 ;
|
1093
1095
|
f.x += left; f.y += top ;
|
@@ -1321,7 +1323,7 @@ SC.View = SC.Responder.extend(SC.PathModule, SC.DelegateSupport,
|
|
1321
1323
|
prect.x -= scrollFrame.x ;
|
1322
1324
|
prect.y -= scrollFrame.y ;
|
1323
1325
|
}
|
1324
|
-
|
1326
|
+
|
1325
1327
|
// blend with current frame
|
1326
1328
|
f = SC.intersectRects(f, prect) ;
|
1327
1329
|
} else {
|
@@ -2026,7 +2028,7 @@ SC.View.mixin({
|
|
2026
2028
|
if (el && el._configured) return SC.View.findViewForElement(el);
|
2027
2029
|
|
2028
2030
|
// Now that we have found an element, instantiate the view.
|
2029
|
-
var args =
|
2031
|
+
var args = SC.$A(arguments) ; args[0] = { rootElement: el } ;
|
2030
2032
|
if (r) vStart = new Date().getTime();
|
2031
2033
|
var ret = new this(args,this) ; // create instance.
|
2032
2034
|
if (r) SC.idt.v_t += (new Date().getTime()) - vStart;
|
@@ -2039,7 +2041,7 @@ SC.View.mixin({
|
|
2039
2041
|
|
2040
2042
|
// create in the view work is like viewFor but with 'null' for el
|
2041
2043
|
create: function(configs) {
|
2042
|
-
var args =
|
2044
|
+
var args = SC.$A(arguments) ;
|
2043
2045
|
args.unshift(null) ;
|
2044
2046
|
return this.viewFor.apply(this,args) ;
|
2045
2047
|
},
|
@@ -2106,6 +2108,7 @@ SC.View.mixin({
|
|
2106
2108
|
break;
|
2107
2109
|
case SC.window.rootElement:
|
2108
2110
|
parentView = SC.window ;
|
2111
|
+
break;
|
2109
2112
|
default:
|
2110
2113
|
node = node.parentNode ;
|
2111
2114
|
}
|
@@ -8,7 +8,7 @@ module SproutCore
|
|
8
8
|
|
9
9
|
# Whenever you build an HTML file for a SproutCore client, an instance of
|
10
10
|
# this class is created to actually process and build the HTML using
|
11
|
-
# Erubus. If you want to add more methods to use in your HTML files, just
|
11
|
+
# Erubus or Haml. If you want to add more methods to use in your HTML files, just
|
12
12
|
# include them in HtmlContext.
|
13
13
|
#
|
14
14
|
class HtmlContext
|
@@ -67,7 +67,15 @@ module SproutCore
|
|
67
67
|
# Finally, render the layout. This should produce the final output to
|
68
68
|
# return
|
69
69
|
input = File.read(@layout_path)
|
70
|
-
|
70
|
+
|
71
|
+
# render using either erb or haml
|
72
|
+
case File.extname(@layout_path)
|
73
|
+
when /\.rhtml$/, /\.html.erb$/
|
74
|
+
return eval(Erubis::Eruby.new.convert(input))
|
75
|
+
when /\.haml$/, /\.html.haml$/
|
76
|
+
require 'haml'
|
77
|
+
return Haml::Engine.new(input).to_html(self)
|
78
|
+
end
|
71
79
|
end
|
72
80
|
|
73
81
|
# render a single entry
|
@@ -80,7 +88,15 @@ module SproutCore
|
|
80
88
|
|
81
89
|
# render. Result goes into @content_for_resources
|
82
90
|
input = File.read(@entry.source_path)
|
83
|
-
|
91
|
+
|
92
|
+
# render using either erb or haml
|
93
|
+
case File.extname(@entry.source_path)
|
94
|
+
when /\.rhtml$/, /\.html.erb$/
|
95
|
+
@content_for_resources += eval(Erubis::Eruby.new.convert(input))
|
96
|
+
when /\.haml$/, /\.html.haml$/
|
97
|
+
require 'haml'
|
98
|
+
@content_for_resources += Haml::Engine.new(input).to_html(self)
|
99
|
+
end
|
84
100
|
|
85
101
|
@filename =nil
|
86
102
|
@entry = nil
|
@@ -59,9 +59,9 @@ module SproutCore
|
|
59
59
|
#
|
60
60
|
# The default will rewrite calls to static_url().
|
61
61
|
def rewrite_inline_code(line, filename)
|
62
|
-
line.gsub(/static_url\([\'\"](
|
62
|
+
line.gsub(/static_url\([\'\"](.+?)[\'\"]\)/) do | rsrc |
|
63
63
|
entry = bundle.find_resource_entry($1, :language => language)
|
64
|
-
static_url(entry.nil? ? '' : entry.
|
64
|
+
static_url(entry.nil? ? '' : entry.cacheable_url)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -205,7 +205,13 @@ module SproutCore
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
-
def self.build_fixture(entry, bundle)
|
208
|
+
def self.build_fixture(entry, bundle)
|
209
|
+
build_javascript(entry, bundle)
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.build_debug(entry, bundle)
|
213
|
+
build_javascript(entry, bundle)
|
214
|
+
end
|
209
215
|
|
210
216
|
end
|
211
217
|
|
data/lib/sproutcore/bundle.rb
CHANGED
@@ -66,6 +66,14 @@ module SproutCore
|
|
66
66
|
# bundle_name:relative_path/to/client. Default:
|
67
67
|
# sproutcore:lib/index.html
|
68
68
|
#
|
69
|
+
# autobuild?: True if the bundle should be included in default builds.
|
70
|
+
# If set to false, then you must ASK for the bundle specifically to be
|
71
|
+
# built.
|
72
|
+
#
|
73
|
+
# use_digest_token: If true, the unique tokens adds to files will be
|
74
|
+
# MD5 digests instead of timestamps. This will ensure uniqueness when
|
75
|
+
# building on multiple machines.
|
76
|
+
#
|
69
77
|
class Bundle
|
70
78
|
|
71
79
|
LONG_LANGUAGE_MAP = { :english => :en, :french => :fr, :german => :de, :japanese => :ja, :spanish => :es, :italian => :it }
|
@@ -85,6 +93,7 @@ module SproutCore
|
|
85
93
|
attr_reader :source_root, :build_root, :url_root, :index_root
|
86
94
|
attr_reader :build_mode, :layout
|
87
95
|
attr_reader :make_resources_relative
|
96
|
+
attr_reader :use_digest_tokens
|
88
97
|
|
89
98
|
def library_root
|
90
99
|
@library_root ||= library.nil? ? nil : library.root_path
|
@@ -116,6 +125,12 @@ module SproutCore
|
|
116
125
|
library.minify_build_modes.include?(build_mode)
|
117
126
|
end
|
118
127
|
|
128
|
+
# ==== Returns
|
129
|
+
# true if this bundle should be auto-built.
|
130
|
+
def autobuild?
|
131
|
+
@autobuild.nil? ? true : @autobuild
|
132
|
+
end
|
133
|
+
|
119
134
|
# ==== Returns
|
120
135
|
# The computed path to the layout rhtml.
|
121
136
|
def layout_path
|
@@ -215,6 +230,12 @@ module SproutCore
|
|
215
230
|
# layout: Path to the layout resource. This should be of the form
|
216
231
|
@layout = opts[:layout] || 'sproutcore:lib/index.rhtml'
|
217
232
|
|
233
|
+
# autobuild?: Determines if you should autobuild...
|
234
|
+
@autobuild = opts[:autobuild]
|
235
|
+
@autobuild = true if @autobuild.nil?
|
236
|
+
|
237
|
+
@use_digest_tokens = opts[:use_digest_tokens] || (@build_mode == :production)
|
238
|
+
|
218
239
|
reload!
|
219
240
|
end
|
220
241
|
|