1
1
var App = SC . Application . create ( ) ;
2
2
3
+ // Put jQuery UI inside its own namespace
3
4
JQ = { } ;
4
5
6
+ // Create a new mixin for jQuery UI widgets using the new SproutCore 2.0
7
+ // mixin syntax.
5
8
JQ . Widget = SC . Mixin . create ( {
9
+ // When SproutCore creates the view's DOM element, it will call this
10
+ // method.
6
11
didCreateElement : function ( ) {
7
12
this . _super ( ) ;
8
13
14
+ // Make jQuery UI options available as SproutCore properties
9
15
var options = this . _gatherOptions ( ) ;
16
+
17
+ // Make sure that jQuery UI events trigger methods on this view.
10
18
this . _gatherEvents ( options ) ;
11
19
20
+ // Create a new instance of the jQuery UI widget based on its `uiType`
21
+ // and the current element.
12
22
var ui = jQuery . ui [ this . get ( 'uiType' ) ] ( options , this . get ( 'element' ) ) ;
13
23
24
+ // Save off the instance of the jQuery UI widget as the `ui` property
25
+ // on this SproutCore view.
14
26
this . set ( 'ui' , ui ) ;
15
27
} ,
16
28
17
- _gatherEvents : function ( options ) {
18
- var uiEvents = this . get ( 'uiEvents' ) || [ ] , self = this ;
19
-
20
- uiEvents . forEach ( function ( event ) {
21
- var callback = self [ event ] ;
22
-
23
- if ( callback ) {
24
- options [ event ] = function ( event , ui ) { callback . call ( self , event , ui ) ; } ;
25
- }
26
- } ) ;
27
- } ,
28
-
29
+ // When SproutCore tears down the view's DOM element, it will call
30
+ // this method.
29
31
willDestroyElement : function ( ) {
30
32
var ui = this . get ( 'ui' ) ;
33
+
31
34
if ( ui ) {
35
+ // Tear down any observers that were created to make jQuery UI
36
+ // options available as SproutCore properties.
32
37
var observers = this . _observers ;
33
38
for ( var prop in observers ) {
34
39
if ( observers . hasOwnProperty ( prop ) ) {
@@ -39,40 +44,82 @@ JQ.Widget = SC.Mixin.create({
39
44
}
40
45
} ,
41
46
47
+ // Each jQuery UI widget has a series of options that can be configured.
48
+ // For instance, to disable a button, you call
49
+ // `button.options('disabled', true)` in jQuery UI. To make this compatible
50
+ // with SproutCore bindings, any time the SproutCore property for a
51
+ // given jQuery UI option changes, we update the jQuery UI widget.
42
52
_gatherOptions : function ( ) {
43
53
var uiOptions = this . get ( 'uiOptions' ) , options = { } ;
44
54
55
+ // The view can specify a list of jQuery UI options that should be treated
56
+ // as SproutCore properties.
45
57
uiOptions . forEach ( function ( key ) {
46
58
options [ key ] = this . get ( key ) ;
47
59
60
+ // Set up an observer on the SproutCore property. When it changes,
61
+ // call jQuery UI's `setOption` method to reflect the property onto
62
+ // the jQuery UI widget.
48
63
var observer = function ( ) {
49
64
var value = this . get ( key ) ;
50
65
this . get ( 'ui' ) . _setOption ( key , value ) ;
51
66
} ;
52
67
53
68
this . addObserver ( key , observer ) ;
69
+
70
+ // Insert the observer in a Hash so we can remove it later.
54
71
this . _observers = this . _observers || { } ;
55
72
this . _observers [ key ] = observer ;
56
73
} , this ) ;
57
74
58
75
return options ;
76
+ } ,
77
+
78
+ // Each jQuery UI widget has a number of custom events that they can
79
+ // trigger. For instance, the progressbar widget triggers a `complete`
80
+ // event when the progress bar finishes. Make these events behave like
81
+ // normal SproutCore events. For instance, a subclass of JQ.ProgressBar
82
+ // could implement the `complete` method to be notified when the jQuery
83
+ // UI widget triggered the event.
84
+ _gatherEvents : function ( options ) {
85
+ var uiEvents = this . get ( 'uiEvents' ) || [ ] , self = this ;
86
+
87
+ uiEvents . forEach ( function ( event ) {
88
+ var callback = self [ event ] ;
89
+
90
+ if ( callback ) {
91
+ // You can register a handler for a jQuery UI event by passing
92
+ // it in along with the creation options. Update the options hash
93
+ // to include any event callbacks.
94
+ options [ event ] = function ( event , ui ) { callback . call ( self , event , ui ) ; } ;
95
+ }
96
+ } ) ;
59
97
}
60
98
} ) ;
61
99
100
+ // Create a new SproutCore view for the jQuery UI Button widget
62
101
JQ . Button = SC . View . extend ( JQ . Widget , {
63
102
uiType : 'button' ,
64
103
uiOptions : [ 'label' , 'disabled' ] ,
65
104
66
105
tagName : 'button'
67
106
} ) ;
68
107
108
+ // Create a new SproutCore view for the jQuery UI Menu widget (new
109
+ // in jQuery UI 1.9). Because it wraps a collection, we extend from
110
+ // SproutCore's CollectionView rather than a normal view.
111
+ //
112
+ // This means that you should use `#collection` in your template to
113
+ // create this view.
69
114
JQ . Menu = SC . CollectionView . extend ( JQ . Widget , {
70
115
uiType : 'menu' ,
71
116
uiOptions : [ 'disabled' ] ,
72
117
uiEvents : [ 'select' ] ,
73
118
74
119
tagName : 'ul' ,
75
120
121
+ // Whenever the underlying Array for this `CollectionView` changes,
122
+ // refresh the jQuery UI widget.
76
123
arrayDidChange : function ( content , start , removed , added ) {
77
124
this . _super ( content , start , removed , added ) ;
78
125
@@ -81,37 +128,60 @@ JQ.Menu = SC.CollectionView.extend(JQ.Widget, {
81
128
}
82
129
} ) ;
83
130
84
- App . controller = SC . Object . create ( {
85
- progress : 0 ,
86
- menuDisabled : true
87
- } ) ;
88
-
131
+ // Create a new SproutCore view for the jQuery UI Progrress Bar widget
89
132
JQ . ProgressBar = SC . View . extend ( JQ . Widget , {
90
133
uiType : 'progressbar' ,
91
134
uiOptions : [ 'value' , 'max' ] ,
92
135
uiEvents : [ 'change' , 'complete' ]
93
136
} ) ;
94
137
138
+ // Create a simple controller to hold values that will be shared across
139
+ // views.
140
+ App . controller = SC . Object . create ( {
141
+ progress : 0 ,
142
+ menuDisabled : true
143
+ } ) ;
144
+
145
+ // Create a subclass of `JQ.Button` to define behavior for our button.
95
146
App . Button = JQ . Button . extend ( {
147
+ // When the button is clicked...
96
148
click : function ( ) {
97
- var self = this ;
149
+ // Disable the button.
98
150
this . set ( 'disabled' , true ) ;
99
- setTimeout ( function ( ) { self . increment . call ( self ) } , 30 ) ;
151
+
152
+ // Increment the progress bar.
153
+ this . increment ( ) ;
100
154
} ,
101
155
102
156
increment : function ( ) {
103
157
var self = this ;
158
+
159
+ // Get the current progress value from the controller.
104
160
var val = App . controller . get ( 'progress' ) ;
161
+
105
162
if ( val < 100 ) {
163
+ // If the value is less than 100, increment it.
106
164
App . controller . set ( 'progress' , val + 1 ) ;
107
- setTimeout ( function ( ) { self . increment . call ( self ) } , 30 ) ;
165
+
166
+ // Schedule another increment call from 30ms.
167
+ setTimeout ( function ( ) { self . increment ( ) } , 30 ) ;
108
168
}
109
169
}
110
170
} ) ;
111
171
172
+ // Create a subclass of `JQ.ProgressBar` to define behavior for our
173
+ // progress bar.
112
174
App . ProgressBar = JQ . ProgressBar . extend ( {
175
+ // When the jQuery UI progress bar reaches 100%, it will invoke the
176
+ // `complete` event. Recall that JQ.Widget registers a callback for
177
+ // the `complete` event in `didCreateElement`, which calls the
178
+ // `complete` method.
113
179
complete : function ( ) {
114
- App . set ( 'people' , [
180
+ // When the progress bar finishes, update App.controller with the
181
+ // list of people. Because our template binds the JQ.Menu to this
182
+ // value, it will automatically populate with the new people and
183
+ // refresh the menu.
184
+ App . controller . set ( 'people' , [
115
185
SC . Object . create ( {
116
186
name : "Tom DAAAAALE"
117
187
} ) ,
@@ -122,24 +192,29 @@ App.ProgressBar = JQ.ProgressBar.extend({
122
192
name : "Majd Potatoes"
123
193
} )
124
194
] ) ;
195
+
196
+ // Set the `menuDisabled` property of our controller to false.
197
+ // Because the JQ.Menu binds its `disabled` property to
198
+ // App.controller.menuDisabled, this will enable it.
125
199
App . controller . set ( 'menuDisabled' , false ) ;
126
200
}
127
201
} ) ;
128
202
129
- // App.people = [
130
- // SC.Object.create({
131
- // name: "Tom DAAAAALE"
132
- // }),
133
- // SC.Object.create({
134
- // name: "Yehuda Katz"
135
- // }),
136
- // SC.Object.create({
137
- // name: "Majd Potatoes"
138
- // })
139
- // ]
140
-
141
- App . MyView = SC . View . extend ( {
142
- mouseDown : function ( ) {
143
- window . alert ( "hello world!" ) ;
144
- }
145
- } ) ;
203
+ /**
204
+ Template:
205
+
206
+ {{view App.Button label="Click to Load People"}}
207
+ <br><br>
208
+ {{view App.ProgressBar valueBinding="App.controller.progress"}}
209
+ <br><br>
210
+ {{#collection JQ.Menu
211
+ contentBinding="App.controller.people"
212
+ disabledBinding="App.controller.menuDisabled"}}
213
+ <a href="#">
214
+ {{content.name}}
215
+ {{view JQ.Button labelBinding="parentView.content.name"}}
216
+ </a>
217
+ {{else}}
218
+ <a href="#">LIST NOT LOADED</a>
219
+ {{/collection}}
220
+ */
0 commit comments