sproutcore 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +233 -0
- data/Manifest.txt +67 -34
- data/bin/sc-build +12 -1
- data/bin/sc-gen +1 -1
- data/bin/sproutcore +14 -0
- data/clients/sc_docs/controllers/docs.js +38 -8
- data/clients/sc_docs/english.lproj/body.css +80 -127
- data/clients/sc_docs/english.lproj/body.rhtml +43 -23
- data/clients/sc_docs/english.lproj/no_docs.rhtml +2 -1
- data/clients/sc_docs/english.lproj/tabs.rhtml +16 -0
- data/clients/sc_docs/main.js +14 -9
- data/clients/sc_docs/models/doc.js +1 -1
- data/clients/sc_docs/tests/controllers/docs.rhtml +1 -2
- data/clients/sc_docs/tests/models/doc.rhtml +1 -2
- data/clients/sc_docs/tests/views/doc_frame.rhtml +1 -2
- data/clients/sc_docs/tests/views/doc_label_view.rhtml +1 -2
- data/clients/sc_docs/views/doc_frame.js +1 -1
- data/clients/sc_test_runner/controllers/runner.js +31 -8
- data/clients/sc_test_runner/english.lproj/body.css +62 -122
- data/clients/sc_test_runner/english.lproj/body.rhtml +62 -26
- data/clients/sc_test_runner/main.js +1 -6
- data/clients/sc_test_runner/models/test.js +14 -1
- data/clients/sc_test_runner/views/runner_frame.js +4 -2
- data/clients/view_builder/builders/builder.js +339 -0
- data/clients/view_builder/builders/button.js +81 -0
- data/clients/view_builder/controllers/document.js +21 -0
- data/clients/view_builder/core.js +19 -0
- data/clients/view_builder/english.lproj/body.css +77 -0
- data/clients/view_builder/english.lproj/body.rhtml +41 -0
- data/clients/{sc_docs → view_builder}/english.lproj/controls.css +0 -0
- data/clients/view_builder/english.lproj/strings.js +14 -0
- data/clients/view_builder/main.js +38 -0
- data/clients/view_builder/tests/controllers/document.rhtml +20 -0
- data/clients/view_builder/tests/views/builder.rhtml +20 -0
- data/clients/view_builder/views/builder.js +23 -0
- data/frameworks/prototype/prototype.js +1 -1
- data/frameworks/sproutcore/Core.js +32 -7
- data/frameworks/sproutcore/README +1 -1
- data/frameworks/sproutcore/animation/animation.js +411 -0
- data/frameworks/sproutcore/controllers/array.js +17 -9
- data/frameworks/sproutcore/controllers/collection.js +9 -110
- data/frameworks/sproutcore/controllers/controller.js +1 -1
- data/frameworks/sproutcore/controllers/object.js +2 -1
- data/frameworks/sproutcore/drag/drag.js +267 -56
- data/frameworks/sproutcore/drag/drag_data_source.js +24 -16
- data/frameworks/sproutcore/drag/drag_source.js +53 -42
- data/frameworks/sproutcore/drag/drop_target.js +2 -2
- data/frameworks/sproutcore/english.lproj/buttons.css +337 -236
- data/frameworks/sproutcore/english.lproj/core.css +115 -0
- data/frameworks/sproutcore/english.lproj/icons.css +227 -0
- data/{clients/sc_docs → frameworks/sproutcore}/english.lproj/images/indicator.gif +0 -0
- data/frameworks/sproutcore/english.lproj/images/sc-theme-sprite.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/sc-theme-ysprite.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/shared-icons.png +0 -0
- data/frameworks/sproutcore/english.lproj/menu.css +1 -1
- data/frameworks/sproutcore/english.lproj/strings.js +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +405 -31
- data/frameworks/sproutcore/foundation/application.js +15 -11
- data/frameworks/sproutcore/foundation/benchmark.js +1 -1
- data/frameworks/sproutcore/foundation/binding.js +2 -2
- data/frameworks/sproutcore/foundation/date.js +1 -1
- data/frameworks/sproutcore/foundation/error.js +1 -1
- data/frameworks/sproutcore/foundation/input_manager.js +32 -21
- data/frameworks/sproutcore/foundation/mock.js +1 -1
- data/frameworks/sproutcore/foundation/node_descriptor.js +9 -6
- data/frameworks/sproutcore/foundation/object.js +249 -177
- data/frameworks/sproutcore/foundation/page.js +5 -2
- data/frameworks/sproutcore/foundation/path_module.js +11 -10
- data/frameworks/sproutcore/foundation/responder.js +5 -2
- data/frameworks/sproutcore/foundation/routes.js +17 -13
- data/frameworks/sproutcore/foundation/run_loop.js +249 -11
- data/frameworks/sproutcore/foundation/server.js +1 -1
- data/frameworks/sproutcore/foundation/set.js +3 -3
- data/frameworks/sproutcore/foundation/string.js +5 -3
- data/frameworks/sproutcore/foundation/timer.js +371 -0
- data/frameworks/sproutcore/foundation/undo_manager.js +1 -1
- data/frameworks/sproutcore/foundation/unittest.js +3 -3
- data/frameworks/sproutcore/foundation/utils.js +161 -2
- data/frameworks/sproutcore/globals/panels.js +1 -1
- data/frameworks/sproutcore/globals/popups.js +4 -3
- data/frameworks/sproutcore/globals/window.js +44 -4
- data/frameworks/sproutcore/lib/button_views.rb +328 -0
- data/frameworks/sproutcore/lib/collection_view.rb +80 -0
- data/frameworks/sproutcore/lib/core_views.rb +281 -0
- data/frameworks/sproutcore/lib/form_views.rb +253 -0
- data/frameworks/sproutcore/lib/index.rhtml +2 -0
- data/frameworks/sproutcore/lib/menu_views.rb +88 -0
- data/frameworks/sproutcore/{foundation → mixins}/array.js +60 -29
- data/frameworks/sproutcore/mixins/control.js +265 -0
- data/frameworks/sproutcore/mixins/delegate_support.js +66 -0
- data/frameworks/sproutcore/{foundation → mixins}/observable.js +176 -6
- data/frameworks/sproutcore/mixins/scrollable.js +245 -0
- data/frameworks/sproutcore/mixins/selection_support.js +148 -0
- data/frameworks/sproutcore/mixins/validatable.js +152 -0
- data/frameworks/sproutcore/models/collection.js +5 -5
- data/frameworks/sproutcore/models/record.js +1 -1
- data/frameworks/sproutcore/models/store.js +1 -1
- data/frameworks/sproutcore/panes/dialog.js +1 -1
- data/frameworks/sproutcore/panes/manager.js +1 -1
- data/frameworks/sproutcore/panes/menu.js +1 -1
- data/frameworks/sproutcore/panes/overlay.js +2 -2
- data/frameworks/sproutcore/panes/panel.js +1 -1
- data/frameworks/sproutcore/panes/picker.js +1 -1
- data/frameworks/sproutcore/tests/controllers/array.rhtml +44 -4
- data/frameworks/sproutcore/tests/foundation/timer/invalidate.rhtml +33 -0
- data/frameworks/sproutcore/tests/foundation/timer/invokeLater.rhtml +145 -0
- data/frameworks/sproutcore/tests/foundation/timer/isPaused.rhtml +70 -0
- data/frameworks/sproutcore/tests/foundation/timer/schedule.rhtml +145 -0
- data/frameworks/sproutcore/tests/views/{scroll.rhtml → checkbox.rhtml} +3 -3
- data/frameworks/sproutcore/tests/views/{collection.rhtml → collection/base.rhtml} +33 -32
- data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +260 -0
- data/frameworks/sproutcore/tests/views/image_cell.rhtml +19 -0
- data/frameworks/sproutcore/tests/views/label_item.rhtml +2 -4
- data/frameworks/sproutcore/tests/views/list.rhtml +2 -3
- data/frameworks/sproutcore/tests/views/list_item.rhtml +20 -0
- data/frameworks/sproutcore/tests/views/slider.rhtml +20 -0
- data/frameworks/sproutcore/tests/views/text_cell.rhtml +19 -0
- data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +395 -0
- data/frameworks/sproutcore/tests/views/view/frame.rhtml +353 -0
- data/frameworks/sproutcore/tests/views/view/innerFrame.rhtml +347 -0
- data/frameworks/sproutcore/tests/views/view/isVisibleInWindow.rhtml +148 -0
- data/frameworks/sproutcore/tests/views/view/scrollFrame.rhtml +468 -0
- data/frameworks/sproutcore/validators/credit_card.js +33 -13
- data/frameworks/sproutcore/validators/date.js +26 -6
- data/frameworks/sproutcore/validators/email.js +21 -3
- data/frameworks/sproutcore/validators/not_empty.js +11 -1
- data/frameworks/sproutcore/validators/number.js +18 -4
- data/frameworks/sproutcore/validators/password.js +12 -1
- data/frameworks/sproutcore/validators/validator.js +204 -194
- data/frameworks/sproutcore/views/{button.js → button/button.js} +96 -94
- data/frameworks/sproutcore/views/button/checkbox.js +29 -0
- data/frameworks/sproutcore/views/button/disclosure.js +42 -0
- data/frameworks/sproutcore/views/button/radio.js +29 -0
- data/frameworks/sproutcore/views/{collection.js → collection/collection.js} +1373 -1024
- data/frameworks/sproutcore/views/collection/grid.js +124 -46
- data/frameworks/sproutcore/views/collection/image_cell.js +17 -46
- data/frameworks/sproutcore/views/collection/list.js +45 -35
- data/frameworks/sproutcore/views/collection/source_list.js +386 -0
- data/frameworks/sproutcore/views/collection/table.js +118 -0
- data/frameworks/sproutcore/views/container.js +7 -2
- data/frameworks/sproutcore/views/error_explanation.js +23 -10
- data/frameworks/sproutcore/views/{checkbox_field.js → field/checkbox_field.js} +16 -6
- data/frameworks/sproutcore/views/field/field.js +219 -0
- data/frameworks/sproutcore/views/{radio_field.js → field/radio_field.js} +27 -12
- data/frameworks/sproutcore/views/{select_field.js → field/select_field.js} +116 -90
- data/frameworks/sproutcore/views/{text_field.js → field/text_field.js} +57 -8
- data/frameworks/sproutcore/views/{textarea_field.js → field/textarea_field.js} +13 -3
- data/frameworks/sproutcore/views/filter_button.js +2 -2
- data/frameworks/sproutcore/views/form.js +3 -3
- data/frameworks/sproutcore/views/image.js +128 -21
- data/frameworks/sproutcore/views/inline_text_editor.js +1 -1
- data/frameworks/sproutcore/views/label.js +149 -92
- data/frameworks/sproutcore/views/list_item.js +225 -0
- data/frameworks/sproutcore/views/menu_item.js +10 -4
- data/frameworks/sproutcore/views/pagination.js +11 -4
- data/frameworks/sproutcore/views/popup_button.js +25 -21
- data/frameworks/sproutcore/views/popup_menu.js +10 -4
- data/frameworks/sproutcore/views/progress.js +29 -16
- data/frameworks/sproutcore/views/radio_group.js +1 -1
- data/frameworks/sproutcore/views/scroll.js +60 -20
- data/frameworks/sproutcore/views/segmented.js +1 -1
- data/frameworks/sproutcore/views/slider.js +132 -0
- data/frameworks/sproutcore/views/source_list_group.js +130 -0
- data/frameworks/sproutcore/views/spinner.js +1 -1
- data/frameworks/sproutcore/views/split.js +292 -0
- data/frameworks/sproutcore/views/split_divider.js +109 -0
- data/frameworks/sproutcore/views/tab.js +1 -1
- data/frameworks/sproutcore/views/toolbar.js +1 -1
- data/frameworks/sproutcore/views/view.js +1272 -591
- data/generators/client/templates/english.lproj/body.css +1 -1
- data/generators/controller/controller_generator.rb +1 -1
- data/generators/controller/templates/test.rhtml +2 -1
- data/generators/model/templates/test.rhtml +1 -1
- data/generators/test/templates/test.rhtml +1 -1
- data/generators/view/templates/test.rhtml +1 -1
- data/jsdoc/templates/sproutcore/class.tmpl +241 -338
- data/jsdoc/templates/sproutcore/default.css +105 -155
- data/jsdoc/templates/sproutcore/index.tmpl +43 -8
- data/jsdoc/templates/sproutcore/publish.js +9 -4
- data/lib/sproutcore/build_tools/html_builder.rb +29 -13
- data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
- data/lib/sproutcore/bundle.rb +86 -25
- data/lib/sproutcore/jsdoc.rb +2 -0
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +36 -3
- data/tasks/deployment.rake +1 -1
- metadata +69 -36
- data/clients/sc_docs/english.lproj/icons/small/next.png +0 -0
- data/clients/sc_docs/english.lproj/icons/small/reset.png +0 -0
- data/clients/sc_docs/english.lproj/images/gradients.png +0 -0
- data/clients/sc_docs/english.lproj/images/toolbar.png +0 -0
- data/clients/sc_docs/english.lproj/warning.rhtml +0 -6
- data/clients/sc_test_runner/english.lproj/warning.rhtml +0 -6
- data/frameworks/sproutcore/english.lproj/buttons.png +0 -0
- data/frameworks/sproutcore/english.lproj/collections.css +0 -82
- data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
- data/frameworks/sproutcore/views/collection/collection_item.js +0 -36
- data/frameworks/sproutcore/views/collection/text_cell.js +0 -128
- data/frameworks/sproutcore/views/field.js +0 -214
- data/frameworks/sproutcore/views/workspace.js +0 -170
- data/generators/client/templates/english.lproj/controls.css +0 -0
- data/generators/framework/templates/english.lproj/body.css +0 -0
- data/generators/framework/templates/english.lproj/body.rhtml +0 -3
- data/generators/framework/templates/english.lproj/controls.css +0 -0
- data/lib/sproutcore/view_helpers/button_views.rb +0 -302
- data/lib/sproutcore/view_helpers/core_views.rb +0 -292
- data/lib/sproutcore/view_helpers/form_views.rb +0 -258
- data/lib/sproutcore/view_helpers/menu_views.rb +0 -94
@@ -1,10 +1,11 @@
|
|
1
1
|
// ========================================================================
|
2
2
|
// SproutCore
|
3
|
-
// copyright 2006-
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
4
|
// ========================================================================
|
5
5
|
|
6
6
|
require('controllers/controller') ;
|
7
|
-
require('
|
7
|
+
require('mixins/array') ;
|
8
|
+
require('mixins/selection_support') ;
|
8
9
|
require('foundation/binding') ;
|
9
10
|
|
10
11
|
/** @class
|
@@ -18,7 +19,7 @@ until you call commitChanges().
|
|
18
19
|
@extends SC.Array
|
19
20
|
|
20
21
|
*/
|
21
|
-
SC.ArrayController = SC.Controller.extend(SC.Array,
|
22
|
+
SC.ArrayController = SC.Controller.extend(SC.Array, SC.SelectionSupport,
|
22
23
|
/** @scope SC.ArrayController.prototype */
|
23
24
|
{
|
24
25
|
/**
|
@@ -26,7 +27,7 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
26
27
|
@property
|
27
28
|
@type {SC.ArrayController}
|
28
29
|
*/
|
29
|
-
arrangedObjects: function() { return this; }.property(),
|
30
|
+
arrangedObjects: function() { return this; }.property('content'),
|
30
31
|
|
31
32
|
/**
|
32
33
|
The array content that is being managed by the controller.
|
@@ -52,8 +53,12 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
52
53
|
@observes content
|
53
54
|
*/
|
54
55
|
_contentObserver: function() {
|
56
|
+
this.beginPropertyChanges();
|
55
57
|
this.contentCloneReset();
|
56
58
|
this.arrayContentDidChange() ;
|
59
|
+
this.notifyPropertyChange('length') ;
|
60
|
+
this.updateSelectionAfterContentChange();
|
61
|
+
this.endPropertyChanges() ;
|
57
62
|
}.observes('content'),
|
58
63
|
|
59
64
|
/**
|
@@ -114,13 +119,14 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
114
119
|
|
115
120
|
// and record additions
|
116
121
|
if (!this._changelog) this._changelog = [];
|
117
|
-
this._changelog.push({ idx: idx, amt: amt, objects:
|
122
|
+
this._changelog.push({ idx: idx, amt: amt, objects: sourceObjects });
|
118
123
|
|
119
124
|
// then actually perform the edit on the contentClone
|
120
|
-
contentClone.replace(idx, amt,
|
125
|
+
contentClone.replace(idx, amt, sourceObjects);
|
121
126
|
|
122
127
|
this.editorDidChange() ;
|
123
128
|
this.arrayContentDidChange();
|
129
|
+
this.updateSelectionAfterContentChange();
|
124
130
|
|
125
131
|
return this;
|
126
132
|
},
|
@@ -132,7 +138,8 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
132
138
|
* return null.
|
133
139
|
*/
|
134
140
|
objectAt: function(idx) {
|
135
|
-
var obj = this._getSourceContent()
|
141
|
+
var obj = this._getSourceContent() ;
|
142
|
+
obj = (obj && obj.objectAt) ? obj.objectAt(idx) : null;
|
136
143
|
return this._objectControllerFor(obj) ;
|
137
144
|
},
|
138
145
|
/**
|
@@ -141,7 +148,8 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
141
148
|
* @type {integer}
|
142
149
|
*/
|
143
150
|
length: function( key, value ) {
|
144
|
-
|
151
|
+
var ret = this._getSourceContent() ;
|
152
|
+
return (ret && ret.get) ? (ret.get('length') || 0) : 0 ;
|
145
153
|
}.property(),
|
146
154
|
|
147
155
|
/**
|
@@ -237,7 +245,7 @@ SC.ArrayController = SC.Controller.extend(SC.Array,
|
|
237
245
|
will be returned.
|
238
246
|
*/
|
239
247
|
_sourceObjectFor: function(obj) {
|
240
|
-
return (obj && obj.
|
248
|
+
return (obj && obj.kindOf && obj.kindOf(SC.Controller)) ? obj.get('content') : obj ;
|
241
249
|
}
|
242
250
|
|
243
251
|
});
|
@@ -1,8 +1,9 @@
|
|
1
1
|
// ========================================================================
|
2
2
|
// SproutCore
|
3
|
-
// copyright 2006-
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
4
|
// ========================================================================
|
5
5
|
|
6
|
+
require('mixins/selection_support') ;
|
6
7
|
require('controllers/object') ;
|
7
8
|
|
8
9
|
/** @class
|
@@ -15,7 +16,7 @@ require('controllers/object') ;
|
|
15
16
|
|
16
17
|
@extends SC.ObjectController
|
17
18
|
*/
|
18
|
-
SC.CollectionController = SC.ObjectController.extend(
|
19
|
+
SC.CollectionController = SC.ObjectController.extend(SC.SelectionSupport,
|
19
20
|
/** @scope SC.CollectionController.prototype */
|
20
21
|
{
|
21
22
|
|
@@ -30,85 +31,7 @@ SC.CollectionController = SC.ObjectController.extend(
|
|
30
31
|
*/
|
31
32
|
arrangedObjects: [],
|
32
33
|
|
33
|
-
/**
|
34
|
-
@property {Array} selection
|
35
|
-
This is the current selection. You can make this selection and another
|
36
|
-
controller's selection work in concert by binding them together. You
|
37
|
-
generally have a master selection that relays changes TO all the others.
|
38
|
-
*/
|
39
|
-
selection: function(key,value)
|
40
|
-
{
|
41
|
-
if (value !== undefined)
|
42
|
-
{
|
43
|
-
// selection must be an array... force if needed....
|
44
|
-
value = (value) ? ((value instanceof Array) ? value : [value]) : [];
|
45
|
-
|
46
|
-
var allowsSelection = this.get('allowsSelection');
|
47
|
-
var allowsEmptySelection = this.get('allowsEmptySelection');
|
48
|
-
var allowsMultipleSelection = this.get('allowsMultipleSelection');
|
49
|
-
|
50
|
-
// are we even allowing selection at all?
|
51
|
-
// if not, then bail out.
|
52
|
-
if ( !allowsSelection ) return this._selection;
|
53
|
-
|
54
|
-
// ok, new decide if the *type* of seleciton is allowed...
|
55
|
-
switch ( value.length )
|
56
|
-
{
|
57
|
-
case 0:
|
58
|
-
// check to see if we're attemting to set an empty array
|
59
|
-
// if that's not allowed, set to the first available item in arrangedObjects
|
60
|
-
this._selection = allowsEmptySelection ? value : (this.get('arrangedObjects') || []).first();
|
61
|
-
break;
|
62
|
-
case 1:
|
63
|
-
// check to see id we've just taken focus away from a new record
|
64
|
-
// if so, queue up the callback to be triggered...
|
65
|
-
if ( this._editingNewRecord && (this._editingNewRecord != value[0]) )
|
66
|
-
{
|
67
|
-
setTimeout(this._newRecordDidLoseFocus.bind(this,this._editingNewRecord),1);
|
68
|
-
this._editingNewRecord = null;
|
69
|
-
}
|
70
|
-
this._selection = value;
|
71
|
-
break;
|
72
|
-
default:
|
73
|
-
// fall through for >= 2 items...
|
74
|
-
// only allow if configured for multi-select
|
75
|
-
this._selection = allowsMultipleSelection ? value : this._selection;
|
76
|
-
break;
|
77
|
-
}
|
78
|
-
|
79
|
-
if ( this._selection && (this._selection.length > 1) )
|
80
|
-
{
|
81
|
-
var collection = this.get('content');
|
82
|
-
var order = collection ? collection.get('orderBy') : null;
|
83
|
-
if ( !order ) order = ['guid'];
|
84
|
-
this._selection = this._selection.sort(function(a,b) { return a.compareTo(b,order); });
|
85
|
-
}
|
86
|
-
}
|
87
|
-
|
88
|
-
return this._selection;
|
89
|
-
}.property(),
|
90
|
-
|
91
|
-
/**
|
92
|
-
If true, selection is allowed.
|
93
34
|
|
94
|
-
@type bool
|
95
|
-
*/
|
96
|
-
allowsSelection: true,
|
97
|
-
|
98
|
-
/**
|
99
|
-
If true, multiple selection is allowed.
|
100
|
-
|
101
|
-
@type bool
|
102
|
-
*/
|
103
|
-
allowsMultipleSelection: true,
|
104
|
-
|
105
|
-
/**
|
106
|
-
If true, allow empty selection
|
107
|
-
|
108
|
-
@type bool
|
109
|
-
*/
|
110
|
-
allowsEmptySelection: true,
|
111
|
-
|
112
35
|
/**
|
113
36
|
If true, new, add, remove will work.
|
114
37
|
|
@@ -167,11 +90,10 @@ SC.CollectionController = SC.ObjectController.extend(
|
|
167
90
|
try {
|
168
91
|
if (content.newRecord) {
|
169
92
|
var rec = content.newRecord(settings) ;
|
170
|
-
var
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
},1) ;
|
93
|
+
var t = function() {
|
94
|
+
this.set('selection',(rec) ? [rec] : []) ;
|
95
|
+
this._editingNewRecord = rec ;
|
96
|
+
}.invokeLater(this, 1) ;
|
175
97
|
return rec;
|
176
98
|
}
|
177
99
|
}
|
@@ -273,33 +195,10 @@ SC.CollectionController = SC.ObjectController.extend(
|
|
273
195
|
value = Array.asArray(target.get(key)) ;
|
274
196
|
|
275
197
|
this.set('arrangedObjects',value.slice()) ;
|
276
|
-
// update selection.
|
277
|
-
var objects = this.get('arrangedObjects') || [] ;
|
278
|
-
if (!(objects instanceof Array)) objects = [objects] ;
|
279
198
|
|
280
|
-
|
281
|
-
|
199
|
+
// update selection.
|
200
|
+
this.updateSelectionAfterContentChange() ;
|
282
201
|
|
283
|
-
// the new selection is the current selection that exists in
|
284
|
-
// arrangedObjects.
|
285
|
-
currentSelection.each(function(obj) {
|
286
|
-
if (objects.include(obj)) sel.push(obj) ;
|
287
|
-
}) ;
|
288
|
-
|
289
|
-
// make new selection match current selection settings.
|
290
|
-
if (!this.allowsSelection) {
|
291
|
-
sel = [] ;
|
292
|
-
}
|
293
|
-
|
294
|
-
if ((sel.length>1) && !this.allowsMultipleSelection) {
|
295
|
-
sel = [sel[0]] ;
|
296
|
-
}
|
297
|
-
|
298
|
-
if ((sel.length == 0) && !this.allowsEmptySelection) {
|
299
|
-
if (objects.length > 0) sel = [objects[0]] ;
|
300
|
-
}
|
301
|
-
|
302
|
-
this.set('selection',sel) ;
|
303
202
|
}.observes('records')
|
304
203
|
|
305
204
|
}) ;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// ========================================================================
|
2
2
|
// SproutCore
|
3
|
-
// copyright 2006-
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
4
|
// ========================================================================
|
5
5
|
|
6
6
|
require('foundation/object') ;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// ========================================================================
|
2
2
|
// SproutCore
|
3
|
-
// copyright 2006-
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
4
|
// ========================================================================
|
5
5
|
|
6
6
|
require('controllers/controller') ;
|
@@ -134,6 +134,7 @@ SC.ObjectController = SC.Controller.extend(
|
|
134
134
|
var oldValue = content.get ? content.get(key) : content[key];
|
135
135
|
var newValue = this._changes[key];
|
136
136
|
|
137
|
+
if (oldValue == null && newValue == '') newValue = null;
|
137
138
|
if (newValue != oldValue)
|
138
139
|
{
|
139
140
|
(content.set) ? content.set('isDirty', true) : (content['isDirty'] = true);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
// ========================================================================
|
2
2
|
// SproutCore
|
3
|
-
// copyright 2006-
|
3
|
+
// copyright 2006-2008 Sprout Systems, Inc.
|
4
4
|
// ========================================================================
|
5
5
|
|
6
6
|
require('Core') ;
|
@@ -8,6 +8,7 @@ require('views/view') ;
|
|
8
8
|
|
9
9
|
SC.DRAG_LINK = 0x0004; SC.DRAG_COPY = 0x0001; SC.DRAG_MOVE = 0x0002;
|
10
10
|
SC.DRAG_NONE = 0x0000; SC.DRAG_ANY = 0x0007 ;
|
11
|
+
SC.DRAG_AUTOSCROLL_ZONE_THICKNESS = 20 ;
|
11
12
|
|
12
13
|
/**
|
13
14
|
|
@@ -20,57 +21,49 @@ SC.DRAG_NONE = 0x0000; SC.DRAG_ANY = 0x0007 ;
|
|
20
21
|
To initiate a drag, you should call SC.Drag.start() with the options below
|
21
22
|
specified in a hash. Pass the ones you need to get the drag you want:
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
dragView
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
the ghost view does not appear in the main UI.
|
50
|
-
|
51
|
-
data:
|
52
|
-
Optional hash of data types and values. You can use this to pass a
|
53
|
-
static set of data instead of providing a dataSource. If you provide
|
24
|
+
- *event: (req)* The mouse event that triggered the drag. This will be used
|
25
|
+
to position the element.
|
26
|
+
|
27
|
+
- *source: (req)* The drag source object that should be consulted during
|
28
|
+
the drag operations. This is usually the container view that initiated
|
29
|
+
the drag.
|
30
|
+
|
31
|
+
- *dragView: (req)* This should point to a view that will be used as the
|
32
|
+
source image for the drag. The drag operation will clone the DOM elements
|
33
|
+
for this view and add the class name 'drag-image' to the outermost
|
34
|
+
element.
|
35
|
+
|
36
|
+
- *ghost: YES | NO* If YES or not passed, then drag view image will show,
|
37
|
+
but the source dragView will not be hidden. set to NO to make it appear
|
38
|
+
that the dragView itself is being dragged around.
|
39
|
+
|
40
|
+
- *slideBack: YES | NO* If YES or not specified, then if the drag
|
41
|
+
operation is cancelled, the dragView will slide back to its source
|
42
|
+
origin.
|
43
|
+
|
44
|
+
- *origin:* If passed, this will be used as the origin point for the
|
45
|
+
ghostView when it slides back. You normally do not need to pass this
|
46
|
+
unless the ghost view does not appear in the main UI.
|
47
|
+
|
48
|
+
- *data:* Optional hash of data types and values. You can use this to pass
|
49
|
+
a static set of data instead of providing a dataSource. If you provide
|
54
50
|
a dataSource, it will override this.
|
55
51
|
|
56
|
-
dataSource
|
57
|
-
|
58
|
-
|
59
|
-
hash, then the source object will be used if it implements the
|
52
|
+
- *dataSource:* Optional object that will provide the data for the drag to
|
53
|
+
be consumed by the drop target. If you do not pass this parameter or the
|
54
|
+
data hash, then the source object will be used if it implements the
|
60
55
|
SC.DragDataSource protocol.
|
61
56
|
|
62
|
-
anchorView
|
63
|
-
|
64
|
-
|
65
|
-
child of this view during the drag. Normally the anchorView is the
|
57
|
+
- *anchorView:* if you pass this optional view, then the drag will only be
|
58
|
+
allowed to happen within this view. The ghostView will actually be added
|
59
|
+
as a child of this view during the drag. Normally the anchorView is the
|
66
60
|
window.
|
67
|
-
}}}
|
68
61
|
|
69
62
|
@extends SC.Object
|
70
63
|
*/
|
71
64
|
SC.Drag = SC.Object.extend(
|
72
|
-
/** @scope SC.Drag.prototype */
|
73
|
-
|
65
|
+
/** @scope SC.Drag.prototype */ {
|
66
|
+
|
74
67
|
/** [RO] The source object used to coordinate this drag. */
|
75
68
|
source: null,
|
76
69
|
|
@@ -120,7 +113,7 @@ SC.Drag = SC.Object.extend(
|
|
120
113
|
//
|
121
114
|
|
122
115
|
/**
|
123
|
-
|
116
|
+
Data types supported by this drag operation.
|
124
117
|
|
125
118
|
Returns an array of data types supported by the drag source. This may
|
126
119
|
be generated dynamically depending on the data source.
|
@@ -132,7 +125,7 @@ SC.Drag = SC.Object.extend(
|
|
132
125
|
on your dragEntered() and prepareForDragOperation() methods to determine
|
133
126
|
if you can handle any of the data types offered up by the drag source.
|
134
127
|
|
135
|
-
@
|
128
|
+
@field {Array} available data types
|
136
129
|
*/
|
137
130
|
dataTypes: function() {
|
138
131
|
|
@@ -220,6 +213,9 @@ SC.Drag = SC.Object.extend(
|
|
220
213
|
*/
|
221
214
|
data: null,
|
222
215
|
|
216
|
+
// required by autoscroll
|
217
|
+
_dragInProgress: YES,
|
218
|
+
|
223
219
|
// this will actually start the drag process.
|
224
220
|
startDrag: function() {
|
225
221
|
|
@@ -227,8 +223,11 @@ SC.Drag = SC.Object.extend(
|
|
227
223
|
this._createGhostView() ;
|
228
224
|
|
229
225
|
// compute the offset from the original mouse location.
|
230
|
-
var origin = this.dragView.convertFrameToView(this.dragView.get('
|
226
|
+
var origin = this.dragView.convertFrameToView(this.dragView.get('frame'), null);
|
231
227
|
var pointer = Event.pointerLocation(this.event) ;
|
228
|
+
|
229
|
+
window.dragEvent = this.event ;
|
230
|
+
|
232
231
|
this.ghostOffset = { x: (pointer.x-origin.x), y: (pointer.y-origin.y) };
|
233
232
|
|
234
233
|
// position the ghost view.
|
@@ -254,10 +253,11 @@ SC.Drag = SC.Object.extend(
|
|
254
253
|
*/
|
255
254
|
mouseDragged: function(evt) {
|
256
255
|
|
257
|
-
// ignore duplicate calls.
|
258
256
|
var loc = Event.pointerLocation(evt) ;
|
257
|
+
var scrolled = this._autoscroll(evt) ;
|
259
258
|
|
260
|
-
|
259
|
+
// ignore duplicate calls.
|
260
|
+
if (!scrolled && (loc.x == this._lastLoc.x) && (loc.y == this._lastLoc.y)) return ;
|
261
261
|
this._lastLoc = loc ;
|
262
262
|
this.set('location', loc) ;
|
263
263
|
|
@@ -372,18 +372,25 @@ SC.Drag = SC.Object.extend(
|
|
372
372
|
this.source.dragDidEnd(this, loc, op) ;
|
373
373
|
}
|
374
374
|
|
375
|
+
this._dragInProgress = NO ; // required by autoscroll.
|
376
|
+
|
375
377
|
},
|
376
378
|
|
377
379
|
// ..........................................
|
378
380
|
// PRIVATE PROPERTIES AND METHODS
|
379
381
|
//
|
380
382
|
|
383
|
+
_ghostViewClass: SC.View.extend({
|
384
|
+
emptyElement: '<div class="sc-ghost-view"></div>'
|
385
|
+
}),
|
386
|
+
|
381
387
|
// positions the ghost view underneath the mouse with the initial offset
|
382
388
|
// recorded by when the drag started.
|
383
389
|
_positionGhostView: function(evt) {
|
384
|
-
var loc =
|
390
|
+
var loc = Event.pointerLocation(evt) ;
|
385
391
|
loc.x -= this.ghostOffset.x ;
|
386
392
|
loc.y -= this.ghostOffset.y ;
|
393
|
+
loc = this._ghostView.convertFrameFromView(loc, null) ;
|
387
394
|
this._ghostView.set('origin', loc) ;
|
388
395
|
},
|
389
396
|
|
@@ -397,8 +404,7 @@ SC.Drag = SC.Object.extend(
|
|
397
404
|
// create the ghost view instance add ghost class name.
|
398
405
|
this._ghostView = this._ghostViewClass.viewFor(el) ;
|
399
406
|
this._ghostView.owner = this ;
|
400
|
-
this._ghostView.addClassName('ghost') ;
|
401
|
-
this._ghostView.set('isPositioned', true) ; // make absolute position.
|
407
|
+
this._ghostView.addClassName('sc-ghost-view') ;
|
402
408
|
|
403
409
|
// add to bottom of main document body and to window.
|
404
410
|
SC.window.appendChild(this._ghostView) ;
|
@@ -451,7 +457,7 @@ SC.Drag = SC.Object.extend(
|
|
451
457
|
// target area.
|
452
458
|
_findDropTarget: function(evt) {
|
453
459
|
var dt = this._dropTargets() ;
|
454
|
-
var loc =
|
460
|
+
var loc = Event.pointerLocation(evt) ;
|
455
461
|
|
456
462
|
var ret = null ;
|
457
463
|
for(var idx=0;idx<dt.length;idx++) {
|
@@ -460,7 +466,7 @@ SC.Drag = SC.Object.extend(
|
|
460
466
|
if(!t.get('isVisibleInWindow')) continue ;
|
461
467
|
|
462
468
|
// get frame, converted to view.
|
463
|
-
var f = t.convertFrameToView(t.get('
|
469
|
+
var f = t.convertFrameToView(t.get('clippingFrame'), null) ;
|
464
470
|
|
465
471
|
// check to see if loc is inside. If so, then make this the drop
|
466
472
|
// target unless there is a drop target and the current one
|
@@ -479,13 +485,201 @@ SC.Drag = SC.Object.extend(
|
|
479
485
|
return null ;
|
480
486
|
},
|
481
487
|
|
482
|
-
|
488
|
+
// ............................................
|
489
|
+
// AUTOSCROLLING
|
490
|
+
//
|
491
|
+
|
492
|
+
// Performs auto-scrolling for the drag. This will only do anything if
|
493
|
+
// the user keeps the mouse within a few pixels of one location for a little
|
494
|
+
// while.
|
495
|
+
//
|
496
|
+
// Returns true if a scroll was performed
|
497
|
+
_autoscroll: function(evt) {
|
498
|
+
|
499
|
+
// If drag has ended, exit
|
500
|
+
if (!this._dragInProgress) return ;
|
501
|
+
|
502
|
+
// STEP 1: Find the first view that we can actually scroll. This view
|
503
|
+
// must be:
|
504
|
+
// - scrollable
|
505
|
+
// - the mouse pointer must be within a scrolling hot zone
|
506
|
+
// - there must be room left to scroll in that direction.
|
507
|
+
|
508
|
+
// NOTE: an event is passed only when called from mouseDragged
|
509
|
+
var loc = (evt) ? Event.pointerLocation(evt) : this._lastMouseLocation ;
|
510
|
+
if (!loc) return false ;
|
511
|
+
this._lastMouseLocation = loc ;
|
512
|
+
|
513
|
+
var view = this._findScrollableView(loc) ;
|
514
|
+
|
515
|
+
// these will become either 1 or -1 to indicate scroll direction or 0 for no scroll.
|
516
|
+
var verticalScroll, horizontalScroll ;
|
517
|
+
var min, max, edge ;
|
518
|
+
var scrollableView = null;
|
519
|
+
|
520
|
+
while(view && !scrollableView) {
|
521
|
+
|
522
|
+
// quick check...can we scroll this view right now?
|
523
|
+
verticalScroll = view.get('hasVerticalScroller') ? 1 : 0;
|
524
|
+
horizontalScroll = view.get('hasHorizontalScroller') ? 1 : 0;
|
525
|
+
|
526
|
+
// at least one direction might be scrollable. Collect some extra
|
527
|
+
// info to investigate further.
|
528
|
+
if ((verticalScroll != 0) || (horizontalScroll != 0)) {
|
529
|
+
var f = view.convertFrameToView(view.get('frame'), null) ;
|
530
|
+
var innerSize = view.get('innerFrame') ;
|
531
|
+
var scrollFrame = view.get('scrollFrame') ;
|
532
|
+
}
|
533
|
+
|
534
|
+
|
535
|
+
if (verticalScroll != 0) {
|
536
|
+
|
537
|
+
// bottom hotzone?
|
538
|
+
max = SC.maxY(f); min = max - SC.DRAG_AUTOSCROLL_ZONE_THICKNESS ;
|
539
|
+
edge = SC.maxY(scrollFrame) ;
|
540
|
+
|
541
|
+
if ((edge >= innerSize.height) && (loc.y >= min) && (loc.y <= max)) {
|
542
|
+
verticalScroll = 1 ;
|
543
|
+
|
544
|
+
// no...how about top hotzone?
|
545
|
+
} else {
|
546
|
+
min = SC.minY(f); max = min + SC.DRAG_AUTOSCROLL_ZONE_THICKNESS ;
|
547
|
+
edge = SC.minY(scrollFrame) ;
|
548
|
+
if ((edge <= innerSize.height) && (loc.y >= min) && (loc.y <= max)) {
|
549
|
+
verticalScroll = -1 ;
|
550
|
+
|
551
|
+
// no, ok don't scroll vertical
|
552
|
+
} else verticalScroll = 0 ;
|
553
|
+
}
|
554
|
+
}
|
555
|
+
|
556
|
+
if (horizontalScroll != 0) {
|
557
|
+
// right hotzone?
|
558
|
+
max = SC.maxX(f); min = max - SC.DRAG_AUTOSCROLL_ZONE_THICKNESS ;
|
559
|
+
edge = SC.maxX(scrollFrame) ;
|
560
|
+
if ((edge >= innerSize.width) && (loc.x >= min) && (loc.x <= max)) {
|
561
|
+
horizontalScroll = 1 ;
|
562
|
+
|
563
|
+
// no...how about left hotzone?
|
564
|
+
} else {
|
565
|
+
min = SC.minY(f); max = min + SC.DRAG_AUTOSCROLL_ZONE_THICKNESS ;
|
566
|
+
edge = SC.minY(scrollFrame) ;
|
567
|
+
if ((edge <= innerSize.width) && (loc.x >= min) && (loc.x <= max)) {
|
568
|
+
horizontalScroll = -1 ;
|
569
|
+
|
570
|
+
// no, ok don't scroll vertical
|
571
|
+
} else horizontalScroll = 0 ;
|
572
|
+
}
|
573
|
+
}
|
574
|
+
|
575
|
+
// if we can scroll, then set this.
|
576
|
+
if ((verticalScroll != 0) || (horizontalScroll != 0)) {
|
577
|
+
scrollableView = view ;
|
578
|
+
} else view = this._findNextScrollableView(view) ;
|
579
|
+
}
|
580
|
+
|
581
|
+
|
582
|
+
// STEP 2: Only scroll if the user remains within the hot-zone for a period of
|
583
|
+
// time
|
584
|
+
if (scrollableView && (this._lastScrollableView == scrollableView)) {
|
585
|
+
if ((Date.now() - this._hotzoneStartTime) > 100) {
|
586
|
+
this._horizontalScrollAmount *= 1.05 ;
|
587
|
+
this._verticalScrollAmount *= 1.05 ;
|
588
|
+
}
|
589
|
+
|
590
|
+
// otherwise, reset everything and disallow scroll
|
591
|
+
} else {
|
592
|
+
this._lastScrollableView = scrollableView ;
|
593
|
+
this._horizontalScrollAmount = 15 ;
|
594
|
+
this._verticalScrollAmount = 15 ;
|
595
|
+
this._hotzoneStartTime = (scrollableView) ? Date.now() : null ;
|
596
|
+
|
597
|
+
horizontalScroll = verticalScroll = 0 ;
|
598
|
+
}
|
599
|
+
|
600
|
+
// STEP 3: Scroll!
|
601
|
+
if (scrollableView && ((horizontalScroll != 0) || (verticalScroll != 0))) {
|
602
|
+
var scroll = {
|
603
|
+
x: horizontalScroll * this._horizontalScrollAmount,
|
604
|
+
y: verticalScroll * this._verticalScrollAmount
|
605
|
+
} ;
|
606
|
+
|
607
|
+
scrollableView.scrollBy(scroll) ;
|
608
|
+
|
609
|
+
}
|
610
|
+
|
611
|
+
// If a scrollable view was found, then reschedule
|
612
|
+
if (scrollableView) {
|
613
|
+
this.invokeLater('_autoscroll', 100, null);
|
614
|
+
return true ;
|
615
|
+
} else return false ;
|
616
|
+
},
|
617
|
+
|
618
|
+
// Returns an array of scrollable views, sorted with nested scrollable
|
619
|
+
// views at the top of the array. The first time this method is called
|
620
|
+
// during a drag, it will reconstrut this array using the current ste of
|
621
|
+
// scrollable views. Afterwards it uses the cached set until the drop
|
622
|
+
// completes.
|
623
|
+
_scrollableViews: function() {
|
624
|
+
if (this._cachedScrollableView) return this._cachedScrollableView ;
|
625
|
+
var ret = [];
|
626
|
+
|
627
|
+
// build array of drop targets
|
628
|
+
var dt = SC.Drag._scrollableViews ;
|
629
|
+
for(var key in dt) {
|
630
|
+
if (!dt.hasOwnProperty(key)) continue ;
|
631
|
+
ret.push(dt[key]) ;
|
632
|
+
}
|
633
|
+
|
634
|
+
// now resort. This custom function will sort nested drop targets
|
635
|
+
// at the start of the list.
|
636
|
+
ret = ret.sort(function(a,b) {
|
637
|
+
var view = a;
|
638
|
+
while((view = view.parentNode) && (view != SC.window)) {
|
639
|
+
if (b == view) return -1 ;
|
640
|
+
}
|
641
|
+
return 1;
|
642
|
+
}) ;
|
643
|
+
|
644
|
+
this._cachedScrollableView = ret ;
|
645
|
+
|
646
|
+
return ret ;
|
647
|
+
},
|
648
|
+
|
649
|
+
// This will search through the scrollable views, looking for one in the
|
650
|
+
// target area.
|
651
|
+
_findScrollableView: function(loc) {
|
652
|
+
var dt = this._scrollableViews() ;
|
653
|
+
|
654
|
+
var ret = null ;
|
655
|
+
for(var idx=0;idx<dt.length;idx++) {
|
656
|
+
var t = dt[idx] ;
|
657
|
+
|
658
|
+
if(!t.get('isVisibleInWindow')) continue ;
|
659
|
+
|
660
|
+
// get frame, converted to view.
|
661
|
+
var f = t.convertFrameToView(t.get('frame'), null) ;
|
662
|
+
|
663
|
+
// check to see if loc is inside.
|
664
|
+
if (SC.pointInRect(loc, f)) return t;
|
665
|
+
}
|
666
|
+
return null ;
|
667
|
+
},
|
668
|
+
|
669
|
+
// Search the parent nodes of the target to find another scrollable view.
|
670
|
+
// return null if none is found.
|
671
|
+
_findNextScrollableView: function(view) {
|
672
|
+
while ((view = view.parentNode) && (view != SC.window)) {
|
673
|
+
if (SC.Drag._scrollableViews[view._guid]) return view ;
|
674
|
+
}
|
675
|
+
return null ;
|
676
|
+
}
|
677
|
+
|
483
678
|
|
484
679
|
}) ;
|
485
680
|
|
486
681
|
SC.Drag.mixin(
|
487
|
-
/** @scope SC.Drag */
|
488
|
-
{
|
682
|
+
/** @scope SC.Drag */ {
|
489
683
|
|
490
684
|
|
491
685
|
/**
|
@@ -502,6 +696,23 @@ SC.Drag.mixin(
|
|
502
696
|
},
|
503
697
|
|
504
698
|
_dropTargets: {},
|
699
|
+
_scrollableViews: {},
|
700
|
+
|
701
|
+
/**
|
702
|
+
Register the view object as a scrollable view. These views will auto-scroll
|
703
|
+
during a drag.
|
704
|
+
*/
|
705
|
+
addScrollableView: function(target) {
|
706
|
+
this._scrollableViews[target._guid] = target ;
|
707
|
+
},
|
708
|
+
|
709
|
+
/**
|
710
|
+
Remove the view object as a scrollable view. These views will auto-scroll
|
711
|
+
during a drag.
|
712
|
+
*/
|
713
|
+
removeScrollableView: function(target) {
|
714
|
+
delete this._scrollableViews[target._guid] ;
|
715
|
+
},
|
505
716
|
|
506
717
|
/**
|
507
718
|
Register the view object as a drop target.
|