Merge lp:~jcsackett/juju-gui/charm-slider into lp:juju-gui/experimental
- charm-slider
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 420 |
Proposed branch: | lp:~jcsackett/juju-gui/charm-slider |
Merge into: | lp:juju-gui/experimental |
Diff against target: |
512 lines (+447/-2) 8 files modified
app/modules-debug.js (+4/-0) app/templates/charm-small-widget.handlebars (+1/-1) app/widgets/charm-slider.js (+329/-0) app/widgets/charm-small.js (+1/-1) lib/views/browser/charm-slider.less (+29/-0) lib/views/stylesheet.less (+1/-0) test/index.html (+1/-0) test/test_charm_slider.js (+81/-0) |
To merge this branch: | bzr merge lp:~jcsackett/juju-gui/charm-slider |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+152418@code.launchpad.net |
Commit message
Description of the change
Adds the charm slider widget
This adds a slider widget derived from Jeff Pihach's flickr carousel. It
doesn't wire it into anything yet.
j.c.sackett (jcsackett) wrote : | # |
Richard Harding (rharding) wrote : | # |
Some light weight changes. Many have a lot of occurances so didn't mark
each one for the first pass, but {Object} vs { Object } and String vs
string.
Some other suggestions and additional tests requested.
https:/
File app/widgets/
https:/
app/widgets/
namespace juju; modules widgets; submodule browser.notifier I think is
how it works.
https:/
app/widgets/
comma here and combine with next var
https:/
app/widgets/
In the doc string can you put a sample of min. html needed to use the
widget? Want to include enough to reuse without too much hunting.
https:/
app/widgets/
Caps String for a class name. No spaces inside the {}.
https:/
app/widgets/
extra space here
https:/
app/widgets/
extra space here (my snippets fault I know...)
https:/
app/widgets/
please move private methods to the top of the class functions.
https:/
app/widgets/
that.get('width'), index: index}));
you get width twice. Please just get the var and cache it to avoid
lookups that aren't required.
https:/
app/widgets/
or a designated index
end comment with .
https:/
app/widgets/
why does index need to be parsed? How is it coming in as a string?
https:/
app/widgets/
can we rename this to pause(d)OnHover. It matches up better since it's a
completed state. Maybe even just move to paused. Who cares if we're
paused for hover or some manual control.
https:/
app/widgets/
Y.juju.
to prevent the nested lookup use ns. please.
https:/
app/widgets/
since this is a little slider let's default to something closer to what
we would use like 150 or 200px.
- 431. By j.c.sackett
-
Addressed comments from review.
j.c.sackett (jcsackett) wrote : | # |
Agree with most comments, address the remainder. Code is coming up
shortly.
https:/
File app/widgets/
https:/
app/widgets/
On 2013/03/08 15:12:02, rharding wrote:
> In the doc string can you put a sample of min. html needed to use the
widget?
> Want to include enough to reuse without too much hunting.
Per discussion, this doesn't actual require any setup; just pass in
parentNode to render, as with default Y.Widget.
https:/
app/widgets/
On 2013/03/08 15:12:02, rharding wrote:
> why does index need to be parsed? How is it coming in as a string?
We get index out of a data-* attribute on the element, but I have moved
the parseInt to where we fetch it, so it's an int when it hits this
method.
j.c.sackett (jcsackett) wrote : | # |
Please take a look.
Jeff Pihach (hatch) wrote : | # |
Thanks for the code! See my comments (as we discussed) below.
https:/
File app/widgets/
https:/
app/widgets/
We decided to no longer use isValue() as all it's really doing is a
glorified falsy check
https:/
app/widgets/
index: index}));
There is no need to do the that=this trick here because (like most
methods of this type in yui) it has a final param which is the context.
http://
https:/
app/widgets/
setContent() is depricated use setHTML()
https:/
app/widgets/
'info', this.name);
I think we have standardized on using console.log()
https:/
app/widgets/
function(item, index) {
Like I mentioned above, YUI's iterators have a context param as the
final param so the that=this can be removed in favour of that.
https:/
app/widgets/
this.getAttribu
event callbacks are passed an event object which hold reference to the
target.
so this can be changed to e.currentTarget
https:/
app/widgets/
delegate() also has a context property
https:/
File lib/views/
https:/
lib/views/
.yui3-browser-
Because we are using less you can actually nest most of the rules in
this commit - let me know if you need help doing this.
- 432. By j.c.sackett
-
Changes from hatch's review
j.c.sackett (jcsackett) wrote : | # |
On 2013/03/08 19:23:49, jeff.pihach wrote:
> Thanks for the code! See my comments (as we discussed) below.
https:/
> File app/widgets/
https:/
> app/widgets/
> We decided to no longer use isValue() as all it's really doing is a
glorified
> falsy check
https:/
> app/widgets/
index:
> index}));
> There is no need to do the that=this trick here because (like most
methods of
> this type in yui) it has a final param which is the context.
> http://
https:/
> app/widgets/
> setContent() is depricated use setHTML()
https:/
> app/widgets/
'info',
> this.name);
> I think we have standardized on using console.log()
https:/
> app/widgets/
function(item,
> index) {
> Like I mentioned above, YUI's iterators have a context param as the
final param
> so the that=this can be removed in favour of that.
https:/
> app/widgets/
this.getAttribu
> event callbacks are passed an event object which hold reference to the
target.
> so this can be changed to e.currentTarget
https:/
> app/widgets/
> delegate() also has a context property
https:/
> File lib/views/
https:/
> lib/views/
.yui3-browser-
> Because we are using less you can actually nest most of the rules in
this commit
> - let me know if you need help doing this.
I've address your points, code coming shortly.
j.c.sackett (jcsackett) wrote : | # |
Please take a look.
Jeff Pihach (hatch) wrote : | # |
Richard Harding (rharding) wrote : | # |
On 2013/03/08 20:17:48, jeff.pihach wrote:
> LGTM
lgtm as well
j.c.sackett (jcsackett) wrote : | # |
*** Submitted:
Adds the charm slider widget
This adds a slider widget derived from Jeff Pihach's flickr carousel. It
doesn't wire it into anything yet.
R=rharding, jeff.pihach
CC=
https:/
Preview Diff
1 | === modified file 'app/modules-debug.js' | |||
2 | --- app/modules-debug.js 2013-03-06 16:17:11 +0000 | |||
3 | +++ app/modules-debug.js 2013-03-08 19:44:21 +0000 | |||
4 | @@ -52,6 +52,10 @@ | |||
5 | 52 | fullpath: '/juju-ui/widgets/charm-small.js' | 52 | fullpath: '/juju-ui/widgets/charm-small.js' |
6 | 53 | }, | 53 | }, |
7 | 54 | 54 | ||
8 | 55 | 'browser-charm-slider': { | ||
9 | 56 | fullpath: '/juju-ui/widgets/charm-slider.js' | ||
10 | 57 | }, | ||
11 | 58 | |||
12 | 55 | 'reconnecting-websocket': { | 59 | 'reconnecting-websocket': { |
13 | 56 | fullpath: '/juju-ui/assets/javascripts/reconnecting-websocket.js' | 60 | fullpath: '/juju-ui/assets/javascripts/reconnecting-websocket.js' |
14 | 57 | }, | 61 | }, |
15 | 58 | 62 | ||
16 | === modified file 'app/templates/charm-small-widget.handlebars' | |||
17 | --- app/templates/charm-small-widget.handlebars 2013-03-01 20:58:58 +0000 | |||
18 | +++ app/templates/charm-small-widget.handlebars 2013-03-08 19:44:21 +0000 | |||
19 | @@ -1,4 +1,4 @@ | |||
21 | 1 | <div > | 1 | <div> |
22 | 2 | <img url="{{ iconfile }}" /> | 2 | <img url="{{ iconfile }}" /> |
23 | 3 | <h3 class="title">{{ title }}</h3> | 3 | <h3 class="title">{{ title }}</h3> |
24 | 4 | <p class="description">{{ description }}</p> | 4 | <p class="description">{{ description }}</p> |
25 | 5 | 5 | ||
26 | === added file 'app/widgets/charm-slider.js' | |||
27 | --- app/widgets/charm-slider.js 1970-01-01 00:00:00 +0000 | |||
28 | +++ app/widgets/charm-slider.js 2013-03-08 19:44:21 +0000 | |||
29 | @@ -0,0 +1,329 @@ | |||
30 | 1 | 'use strict'; | ||
31 | 2 | |||
32 | 3 | |||
33 | 4 | /** | ||
34 | 5 | * Provides the Charm Slider widget. | ||
35 | 6 | * | ||
36 | 7 | * @namespace juju | ||
37 | 8 | * @module widgets | ||
38 | 9 | * @submodule browser.CharmSlider | ||
39 | 10 | * | ||
40 | 11 | */ | ||
41 | 12 | YUI.add('browser-charm-slider', function(Y) { | ||
42 | 13 | var sub = Y.Lang.sub, | ||
43 | 14 | ns = Y.namespace('juju.widgets.browser'); | ||
44 | 15 | |||
45 | 16 | /** | ||
46 | 17 | * The CharmSlider provides a rotating display of one member of a generic set | ||
47 | 18 | * of items, with controls to go directly to a given item. | ||
48 | 19 | * | ||
49 | 20 | * @class CharmSlider | ||
50 | 21 | * @extends {Y.ScrollView} | ||
51 | 22 | * | ||
52 | 23 | */ | ||
53 | 24 | ns.CharmSlider = new Y.Base.create('browser-charm-slider', Y.ScrollView, [], { | ||
54 | 25 | |||
55 | 26 | /** | ||
56 | 27 | * Template for the CharmSlider | ||
57 | 28 | * | ||
58 | 29 | * @property charmSliderTemplate | ||
59 | 30 | * @type {String} | ||
60 | 31 | * | ||
61 | 32 | */ | ||
62 | 33 | charmSliderTemplate: '<ul width="{width}px" />', | ||
63 | 34 | |||
64 | 35 | /** | ||
65 | 36 | * Template for a given item in the slider | ||
66 | 37 | * | ||
67 | 38 | * @property itemTemplate | ||
68 | 39 | * @type {String} | ||
69 | 40 | * | ||
70 | 41 | */ | ||
71 | 42 | itemTemplate: '<li width="{width}px" data-index="{index}" />', | ||
72 | 43 | |||
73 | 44 | /** | ||
74 | 45 | * Template used for the navigation controls. | ||
75 | 46 | * | ||
76 | 47 | * @property prevNavTemplate | ||
77 | 48 | * @type {String} | ||
78 | 49 | */ | ||
79 | 50 | navTemplate: '<ul class="navigation"></div>', | ||
80 | 51 | |||
81 | 52 | /** | ||
82 | 53 | * Template used for items in the navigation. | ||
83 | 54 | * | ||
84 | 55 | * @property navItemTemplate | ||
85 | 56 | * @type {String} | ||
86 | 57 | */ | ||
87 | 58 | navItemTemplate: '<li data-index="{index}">O</li>', | ||
88 | 59 | |||
89 | 60 | /** | ||
90 | 61 | * Advances the slider to the next item, or a designated index. | ||
91 | 62 | * | ||
92 | 63 | * @method _advanceSlide | ||
93 | 64 | * @param {string} Index to move to; if not supplied, advances to next | ||
94 | 65 | * slide. | ||
95 | 66 | * @private | ||
96 | 67 | */ | ||
97 | 68 | _advanceSlide: function(index) { | ||
98 | 69 | var pages = this.pages; | ||
99 | 70 | if (index) { | ||
100 | 71 | this._stopTimer(); | ||
101 | 72 | pages.scrollToIndex(index); | ||
102 | 73 | this._startTimer(); | ||
103 | 74 | } else { | ||
104 | 75 | index = pages.get('index'); | ||
105 | 76 | if (index < pages.get('total') - 1) { | ||
106 | 77 | pages.next(); | ||
107 | 78 | } else { | ||
108 | 79 | pages.scrollToIndex(0); | ||
109 | 80 | } | ||
110 | 81 | } | ||
111 | 82 | }, | ||
112 | 83 | |||
113 | 84 | /** | ||
114 | 85 | * Creates the structure and DOM nodes for the slider. | ||
115 | 86 | * | ||
116 | 87 | * @method _generateDOM | ||
117 | 88 | * @private | ||
118 | 89 | * @return {Node} The slider's DOM nodes. | ||
119 | 90 | * | ||
120 | 91 | */ | ||
121 | 92 | _generateDOM: function() { | ||
122 | 93 | var width = this.get('width'), | ||
123 | 94 | slider = Y.Node.create( | ||
124 | 95 | sub(this.charmSliderTemplate, {width: width})); | ||
125 | 96 | |||
126 | 97 | Y.Array.map(this.get('items'), function(item, index) { | ||
127 | 98 | var tmpNode = Y.Node.create( | ||
128 | 99 | sub(this.itemTemplate, {width: width, index: index})); | ||
129 | 100 | tmpNode.setHTML(item); | ||
130 | 101 | slider.append(tmpNode); | ||
131 | 102 | }, this); | ||
132 | 103 | return slider; | ||
133 | 104 | }, | ||
134 | 105 | |||
135 | 106 | /** | ||
136 | 107 | * Generates and appends the navigation controls for the slider | ||
137 | 108 | * | ||
138 | 109 | * @method _generateSliderControls | ||
139 | 110 | * @private | ||
140 | 111 | */ | ||
141 | 112 | _generateSliderControls: function() { | ||
142 | 113 | var nav = Y.Node.create(this.navTemplate); | ||
143 | 114 | Y.Array.each(this.get('items'), function(item, index) { | ||
144 | 115 | nav.append(Y.Node.create(sub( | ||
145 | 116 | this.navItemTemplate, {index: index}))); | ||
146 | 117 | }, this); | ||
147 | 118 | this.get('boundingBox').append(nav); | ||
148 | 119 | }, | ||
149 | 120 | |||
150 | 121 | /** | ||
151 | 122 | * Mouseenter/mouseleave event handler | ||
152 | 123 | * | ||
153 | 124 | * @method _pauseAutoAdvance | ||
154 | 125 | * @private | ||
155 | 126 | * @param {object} mouseout or mouseover event object. | ||
156 | 127 | */ | ||
157 | 128 | _pauseAutoAdvance: function(e) { | ||
158 | 129 | if (e.type === 'mouseenter') { | ||
159 | 130 | this.set('paused', true); | ||
160 | 131 | } else { | ||
161 | 132 | this.set('paused', false); | ||
162 | 133 | } | ||
163 | 134 | }, | ||
164 | 135 | |||
165 | 136 | /** | ||
166 | 137 | * Checks to see if autoadvance is set then sets up the timeouts | ||
167 | 138 | * | ||
168 | 139 | * @method _startTimer | ||
169 | 140 | * @private | ||
170 | 141 | */ | ||
171 | 142 | _startTimer: function() { | ||
172 | 143 | |||
173 | 144 | if (this.get('autoAdvance') === true) { | ||
174 | 145 | var timer = Y.later(this.get('advanceDelay'), this, function() { | ||
175 | 146 | if (this.get('paused') !== true) { | ||
176 | 147 | this._advanceSlide(); | ||
177 | 148 | } | ||
178 | 149 | }, null, true); | ||
179 | 150 | this.set('timer', timer); | ||
180 | 151 | } | ||
181 | 152 | }, | ||
182 | 153 | |||
183 | 154 | /** | ||
184 | 155 | * Stops the timer for autoadvance | ||
185 | 156 | * | ||
186 | 157 | * @method _stopTimer | ||
187 | 158 | * @private | ||
188 | 159 | */ | ||
189 | 160 | _stopTimer: function() { | ||
190 | 161 | var timer = this.get('timer'); | ||
191 | 162 | if (timer) { | ||
192 | 163 | timer.cancel(); | ||
193 | 164 | } | ||
194 | 165 | }, | ||
195 | 166 | |||
196 | 167 | /** | ||
197 | 168 | * Binds the navigate event listeners | ||
198 | 169 | * | ||
199 | 170 | * @method bindUI | ||
200 | 171 | * @private | ||
201 | 172 | */ | ||
202 | 173 | bindUI: function() { | ||
203 | 174 | |||
204 | 175 | //Call the parent bindUI method | ||
205 | 176 | ns.CharmSlider.superclass.bindUI.apply(this); | ||
206 | 177 | |||
207 | 178 | var events = this.get('_events'), | ||
208 | 179 | boundingBox = this.get('boundingBox'), | ||
209 | 180 | nav = boundingBox.one('.navigation'); | ||
210 | 181 | events.push(this.after('render', this._startTimer, this)); | ||
211 | 182 | events.push(boundingBox.on('mouseenter', this._pauseAutoAdvance, this)); | ||
212 | 183 | events.push(boundingBox.on('mouseleave', this._pauseAutoAdvance, this)); | ||
213 | 184 | events.push(nav.delegate('click', function(e) { | ||
214 | 185 | var index = e.currentTarget.getAttribute('data-index'); | ||
215 | 186 | index = parseInt(index, 10); | ||
216 | 187 | this._advanceSlide(index); | ||
217 | 188 | }, 'li', this)); | ||
218 | 189 | }, | ||
219 | 190 | |||
220 | 191 | /** | ||
221 | 192 | * Detaches events attached during instantiation | ||
222 | 193 | * | ||
223 | 194 | * @method destructor | ||
224 | 195 | * @private | ||
225 | 196 | */ | ||
226 | 197 | destructor: function() { | ||
227 | 198 | this.get('_events').each(function(event) { | ||
228 | 199 | event.detach(); | ||
229 | 200 | }); | ||
230 | 201 | }, | ||
231 | 202 | |||
232 | 203 | /** | ||
233 | 204 | * Initializer | ||
234 | 205 | * | ||
235 | 206 | * @method initializer | ||
236 | 207 | * @param {Object} The config object. | ||
237 | 208 | * | ||
238 | 209 | */ | ||
239 | 210 | initializer: function(cfg) { | ||
240 | 211 | this.plug(Y.Plugin.ScrollViewPaginator, { | ||
241 | 212 | selector: 'li' | ||
242 | 213 | }); | ||
243 | 214 | |||
244 | 215 | }, | ||
245 | 216 | |||
246 | 217 | /** | ||
247 | 218 | * Render the nodes and HTML for the slider. | ||
248 | 219 | * | ||
249 | 220 | * @method renderUI | ||
250 | 221 | * @private | ||
251 | 222 | */ | ||
252 | 223 | renderUI: function() { | ||
253 | 224 | this.get('contentBox').setHTML(this._generateDOM()); | ||
254 | 225 | this._generateSliderControls(); | ||
255 | 226 | } | ||
256 | 227 | }, { | ||
257 | 228 | ATTRS: { | ||
258 | 229 | |||
259 | 230 | /** | ||
260 | 231 | * @attribute width | ||
261 | 232 | * @default 200 | ||
262 | 233 | * @type {Int} | ||
263 | 234 | * | ||
264 | 235 | */ | ||
265 | 236 | width: { | ||
266 | 237 | value: 500 | ||
267 | 238 | }, | ||
268 | 239 | |||
269 | 240 | /** | ||
270 | 241 | * @attribute autoAdvance | ||
271 | 242 | * @default true | ||
272 | 243 | * @type {Boolean} | ||
273 | 244 | * | ||
274 | 245 | */ | ||
275 | 246 | autoAdvance: { | ||
276 | 247 | value: true | ||
277 | 248 | }, | ||
278 | 249 | |||
279 | 250 | /** | ||
280 | 251 | * @attribute advanceDelay | ||
281 | 252 | * @default 3000 | ||
282 | 253 | * @type {Int} | ||
283 | 254 | * | ||
284 | 255 | */ | ||
285 | 256 | advanceDelay: { | ||
286 | 257 | value: 3000 | ||
287 | 258 | }, | ||
288 | 259 | |||
289 | 260 | /** | ||
290 | 261 | * @attribute paused | ||
291 | 262 | * @default false | ||
292 | 263 | * @type {Boolean} | ||
293 | 264 | * | ||
294 | 265 | */ | ||
295 | 266 | paused: { | ||
296 | 267 | value: false | ||
297 | 268 | }, | ||
298 | 269 | |||
299 | 270 | /** | ||
300 | 271 | * @attribute items | ||
301 | 272 | * @default [] | ||
302 | 273 | * @type {Array} | ||
303 | 274 | * | ||
304 | 275 | */ | ||
305 | 276 | items: { | ||
306 | 277 | value: [], | ||
307 | 278 | /** | ||
308 | 279 | * Verify items aren't larger than max value. | ||
309 | 280 | * | ||
310 | 281 | * @method validator | ||
311 | 282 | * @param {Array} The items being validated. | ||
312 | 283 | */ | ||
313 | 284 | validator: function(val) { | ||
314 | 285 | return (val.length <= this.get('max')); | ||
315 | 286 | } | ||
316 | 287 | }, | ||
317 | 288 | |||
318 | 289 | /** | ||
319 | 290 | * @attribute _events | ||
320 | 291 | * @default [] | ||
321 | 292 | * @type {Array} | ||
322 | 293 | * | ||
323 | 294 | */ | ||
324 | 295 | _events: { | ||
325 | 296 | value: [] | ||
326 | 297 | }, | ||
327 | 298 | |||
328 | 299 | /** | ||
329 | 300 | * @attribute max | ||
330 | 301 | * @default 5 | ||
331 | 302 | * @type {Int} | ||
332 | 303 | * | ||
333 | 304 | */ | ||
334 | 305 | max: { | ||
335 | 306 | value: 5 | ||
336 | 307 | }, | ||
337 | 308 | |||
338 | 309 | /** | ||
339 | 310 | * @attribute timer | ||
340 | 311 | * @default null | ||
341 | 312 | * @type {Object} | ||
342 | 313 | * | ||
343 | 314 | */ | ||
344 | 315 | timer: { | ||
345 | 316 | value: null | ||
346 | 317 | } | ||
347 | 318 | } | ||
348 | 319 | }); | ||
349 | 320 | |||
350 | 321 | }, '0.1.0', { | ||
351 | 322 | requires: [ | ||
352 | 323 | 'array-extras', | ||
353 | 324 | 'base', | ||
354 | 325 | 'event-mouseenter', | ||
355 | 326 | 'scrollview', | ||
356 | 327 | 'scrollview-paginator' | ||
357 | 328 | ] | ||
358 | 329 | }); | ||
359 | 0 | 330 | ||
360 | === modified file 'app/widgets/charm-small.js' | |||
361 | --- app/widgets/charm-small.js 2013-03-04 21:26:27 +0000 | |||
362 | +++ app/widgets/charm-small.js 2013-03-08 19:44:21 +0000 | |||
363 | @@ -57,7 +57,7 @@ | |||
364 | 57 | }, | 57 | }, |
365 | 58 | 58 | ||
366 | 59 | /** | 59 | /** |
368 | 60 | * Desctructor | 60 | * Destructor |
369 | 61 | * | 61 | * |
370 | 62 | * @method destructor | 62 | * @method destructor |
371 | 63 | * @return {undefined} Mutates only. | 63 | * @return {undefined} Mutates only. |
372 | 64 | 64 | ||
373 | === added file 'lib/views/browser/charm-slider.less' | |||
374 | --- lib/views/browser/charm-slider.less 1970-01-01 00:00:00 +0000 | |||
375 | +++ lib/views/browser/charm-slider.less 2013-03-08 19:44:21 +0000 | |||
376 | @@ -0,0 +1,29 @@ | |||
377 | 1 | .yui3-browser-charm-slider { | ||
378 | 2 | |||
379 | 3 | .yui3-browser-charm-slider-content { | ||
380 | 4 | white-space: nowrap; | ||
381 | 5 | |||
382 | 6 | ul { | ||
383 | 7 | margin: 0; | ||
384 | 8 | -moz-padding-start: 0; | ||
385 | 9 | padding-start: 0; | ||
386 | 10 | -webkit-padding-start: 0; | ||
387 | 11 | } | ||
388 | 12 | |||
389 | 13 | li { | ||
390 | 14 | display: inline-block; | ||
391 | 15 | text-align: center; | ||
392 | 16 | vertical-align: middle; | ||
393 | 17 | } | ||
394 | 18 | } | ||
395 | 19 | |||
396 | 20 | .navigate { | ||
397 | 21 | cursor: pointer; | ||
398 | 22 | list-style-type: none; | ||
399 | 23 | |||
400 | 24 | li { | ||
401 | 25 | display: block-inline; | ||
402 | 26 | width: auto; | ||
403 | 27 | } | ||
404 | 28 | } | ||
405 | 29 | } | ||
406 | 0 | 30 | ||
407 | === modified file 'lib/views/stylesheet.less' | |||
408 | --- lib/views/stylesheet.less 2013-03-06 15:07:47 +0000 | |||
409 | +++ lib/views/stylesheet.less 2013-03-08 19:44:21 +0000 | |||
410 | @@ -1635,3 +1635,4 @@ | |||
411 | 1635 | } | 1635 | } |
412 | 1636 | 1636 | ||
413 | 1637 | @import "browser/charm-small.less"; | 1637 | @import "browser/charm-small.less"; |
414 | 1638 | @import "browser/charm-slider.less"; | ||
415 | 1638 | 1639 | ||
416 | === modified file 'test/index.html' | |||
417 | --- test/index.html 2013-03-06 15:59:28 +0000 | |||
418 | +++ test/index.html 2013-03-08 19:44:21 +0000 | |||
419 | @@ -39,6 +39,7 @@ | |||
420 | 39 | <script src="test_charm_configuration.js"></script> | 39 | <script src="test_charm_configuration.js"></script> |
421 | 40 | <script src="test_charm_panel.js"></script> | 40 | <script src="test_charm_panel.js"></script> |
422 | 41 | <script src="test_charm_small_widget.js"></script> | 41 | <script src="test_charm_small_widget.js"></script> |
423 | 42 | <script src="test_charm_slider.js"></script> | ||
424 | 42 | <script src="test_charm_store.js"></script> | 43 | <script src="test_charm_store.js"></script> |
425 | 43 | <script src="test_charm_view.js"></script> | 44 | <script src="test_charm_view.js"></script> |
426 | 44 | <script src="test_console.js"></script> | 45 | <script src="test_console.js"></script> |
427 | 45 | 46 | ||
428 | === added file 'test/test_charm_slider.js' | |||
429 | --- test/test_charm_slider.js 1970-01-01 00:00:00 +0000 | |||
430 | +++ test/test_charm_slider.js 2013-03-08 19:44:21 +0000 | |||
431 | @@ -0,0 +1,81 @@ | |||
432 | 1 | 'use strict'; | ||
433 | 2 | |||
434 | 3 | describe('charm slider', function() { | ||
435 | 4 | var container, Y; | ||
436 | 5 | |||
437 | 6 | before(function(done) { | ||
438 | 7 | Y = YUI(GlobalConfig).use( | ||
439 | 8 | ['browser-charm-slider', 'browser-charm-small', 'event-simulate', | ||
440 | 9 | 'node-event-simulate', 'node'], function(Y) { | ||
441 | 10 | done(); | ||
442 | 11 | }); | ||
443 | 12 | }); | ||
444 | 13 | |||
445 | 14 | beforeEach(function() { | ||
446 | 15 | container = Y.Node.create('<div id="container"></div>'); | ||
447 | 16 | Y.one('body').prepend(container); | ||
448 | 17 | }); | ||
449 | 18 | |||
450 | 19 | afterEach(function() { | ||
451 | 20 | container.remove(true); | ||
452 | 21 | }); | ||
453 | 22 | |||
454 | 23 | it('initializes', function() { | ||
455 | 24 | var cs = new Y.juju.widgets.browser.CharmSlider(); | ||
456 | 25 | assert.isObject(cs); | ||
457 | 26 | }); | ||
458 | 27 | |||
459 | 28 | it('creates the right DOM', function() { | ||
460 | 29 | var cs = new Y.juju.widgets.browser.CharmSlider(), | ||
461 | 30 | items = ['foo', 'bar', 'baz']; | ||
462 | 31 | cs.set('items', items); | ||
463 | 32 | var sliderDOM = cs._generateDOM(); | ||
464 | 33 | assert.equal(3, sliderDOM.all('li').size()); | ||
465 | 34 | var html = sliderDOM.get('outerHTML'); | ||
466 | 35 | Y.Array.each(items, function(item) { | ||
467 | 36 | assert.notEqual(-1, html.indexOf(item)); | ||
468 | 37 | }); | ||
469 | 38 | }); | ||
470 | 39 | |||
471 | 40 | it('renders', function() { | ||
472 | 41 | var cs = new Y.juju.widgets.browser.CharmSlider({ | ||
473 | 42 | items: ['<div id="foo"/>'] | ||
474 | 43 | }); | ||
475 | 44 | cs.render(container); | ||
476 | 45 | assert.isObject(Y.one('#foo')); | ||
477 | 46 | }); | ||
478 | 47 | |||
479 | 48 | it('it generates buttons for each', function() { | ||
480 | 49 | var cs = new Y.juju.widgets.browser.CharmSlider(), | ||
481 | 50 | items = ['<div />', '<div />']; | ||
482 | 51 | cs.set('items', items); | ||
483 | 52 | cs.render(container); | ||
484 | 53 | var nav = Y.one('.navigation'); | ||
485 | 54 | assert.equal(items.length, nav.all('li').size()); | ||
486 | 55 | }); | ||
487 | 56 | |||
488 | 57 | it('pauses on hover', function() { | ||
489 | 58 | var cs = new Y.juju.widgets.browser.CharmSlider({items: ['<div/>']}); | ||
490 | 59 | cs.render(container); | ||
491 | 60 | Y.one('.yui3-browser-charm-slider').simulate('mouseover'); | ||
492 | 61 | assert.isTrue(cs.get('paused'), 'Slider is not paused.'); | ||
493 | 62 | Y.one('.yui3-browser-charm-slider').simulate('mouseout'); | ||
494 | 63 | assert.isFalse(cs.get('paused'), 'Slider is not paused.'); | ||
495 | 64 | }); | ||
496 | 65 | |||
497 | 66 | it('goes to the right slide on nav click', function() { | ||
498 | 67 | var cs = new Y.juju.widgets.browser.CharmSlider({ | ||
499 | 68 | items: ['<div/>', '<div/>'], | ||
500 | 69 | autoAdvance: false | ||
501 | 70 | }); | ||
502 | 71 | cs.render(container); | ||
503 | 72 | assert.equal( | ||
504 | 73 | 0, cs.pages.get('index'), | ||
505 | 74 | 'Slider did not start on first slide.'); | ||
506 | 75 | var li = Y.one('.navigation').all('li').pop(); | ||
507 | 76 | li.simulate('click'); | ||
508 | 77 | assert.equal( | ||
509 | 78 | 1, cs.pages.get('index'), | ||
510 | 79 | 'Slider did not advance to second slide.'); | ||
511 | 80 | }); | ||
512 | 81 | }); |
Reviewers: mp+152418_ code.launchpad. net,
Message:
Please take a look.
Description:
Adds the charm slider widget
This adds a slider widget derived from Jeff Pihach's flickr carousel. It
doesn't wire it into anything yet.
https:/ /code.launchpad .net/~jcsackett /juju-gui/ charm-slider/ +merge/ 152418
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/7641043/
Affected files: debug.js charm-small- widget. handlebars charm-slider. js charm-small. js browser/ charm-slider. less stylesheet. less charm_slider. js
A [revision details]
M app/modules-
M app/templates/
A app/widgets/
M app/widgets/
A lib/views/
M lib/views/
M test/index.html
A test/test_