Merge lp:~rharding/juju-gui/search-widget into lp:juju-gui/experimental

Proposed by Richard Harding
Status: Merged
Merged at revision: 429
Proposed branch: lp:~rharding/juju-gui/search-widget
Merge into: lp:juju-gui/experimental
Diff against target: 599 lines (+409/-24)
11 files modified
app/modules-debug.js (+4/-0)
app/subapps/browser/templates/fullscreen.handlebars (+2/-1)
app/subapps/browser/templates/sidebar.handlebars (+0/-7)
app/subapps/browser/views/fullscreen.js (+13/-3)
app/subapps/browser/views/sidebar.js (+60/-13)
app/templates/browser-search.handlebars (+12/-0)
app/widgets/charm-search.js (+195/-0)
lib/views/stylesheet.less (+5/-0)
test/index.html (+1/-0)
test/test_browser_app.js (+4/-0)
test/test_browser_search_widget.js (+113/-0)
To merge this branch: bzr merge lp:~rharding/juju-gui/search-widget
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+152737@code.launchpad.net

Description of the change

Implement the browser search control widget.

- Add a new widget containing the search input
- Provide events to the outside world to update/watch for search phrase
changes
- Add tests
- Hook widget into the render of the fullscreen and sidebar views.

https://codereview.appspot.com/7519044/

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) wrote :

Reviewers: mp+152737_code.launchpad.net,

Message:
Please take a look.

Description:
Implement the browser search control widget.

- Add a new widget containing the search input
- Provide events to the outside world to update/watch for search phrase
changes
- Add tests
- Hook widget into the render of the fullscreen and sidebar views.
- NOTES:
   - There is discussion under way of design changes to the search area
so it's
   not completely tied into the views. The sidebar view has some event
binding
   to demonstrate use, but it's not complete and doesn't exist in the
   fullscreen view at the moment.
   - Currently the design would have this widget exist twice, once in
each
   sidebar/fullscreen view. If we do keep the views around (persist them)
for
   performance we'll need to add a sync mechanism so they both represent
the
   same search. Not implemented at this time.
   - The search widget will support autocomplete. It's added to the board
as a
   second card.

https://code.launchpad.net/~rharding/juju-gui/search-widget/+merge/152737

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/7519044/

Affected files:
   A [revision details]
   M app/modules-debug.js
   M app/subapps/browser/templates/fullscreen.handlebars
   M app/subapps/browser/templates/sidebar.handlebars
   M app/subapps/browser/views/fullscreen.js
   M app/subapps/browser/views/sidebar.js
   A app/templates/browser-search.handlebars
   A app/widgets/charm-search.js
   M lib/views/stylesheet.less
   M test/index.html
   M test/test_browser_app.js
   A test/test_browser_search_widget.js

Revision history for this message
Jeff Pihach (hatch) wrote :

Looks good! Just a few small comments/changes below

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/fullscreen.js
File app/subapps/browser/views/fullscreen.js (right):

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/fullscreen.js#newcode45
app/subapps/browser/views/fullscreen.js:45:
search.render(tpl_node.one('.bws-search'));
At this point you are rendering a widget into an element which isn't yet
rendered onto the page. What you might notice is that you will end up
with odd bugs when doing this because of dom calculations (scrollview
has this issue).

A workaround is to put these in an 'afterRender' method and then call
that method in the showView() callback.

You don't need to change this - I was just pointing that out in the
event you run into that issue :-)

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js
File app/subapps/browser/views/sidebar.js (right):

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode42
app/subapps/browser/views/sidebar.js:42: _bindEvents: function() {
Where is this method called from?

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode44
app/subapps/browser/views/sidebar.js:44:
this.search.on(this.search.EVT_UPDATE_SEARCH, this._searchChanged,
this);
These events aren't being detached on destroy

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode103
app/subapps/browser/views/sidebar.js:103:
this.search.render(tpl_node.one('.bws-search'));
See the rendering outside of the DOM issue comment from the previous
file.

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js
File app/widgets/charm-search.js (right):

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js#newcode110
app/widgets/charm-search.js:110:
this.get('contentBox').one('input').set('value', '');
If the input is in focus then this will trigger valueChange, I
recommend:

input.blur();
input.set('value', '');

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js#newcode175
app/widgets/charm-search.js:175:
this.get('boundingBox').one('input').set('value', newval);
If this input is in focus then it will trigger valueChange. See above.

https://codereview.appspot.com/7519044/diff/1/test/test_browser_search_widget.js
File test/test_browser_search_widget.js (right):

https://codereview.appspot.com/7519044/diff/1/test/test_browser_search_widget.js#newcode33
test/test_browser_search_widget.js:33: it('should supports search
changed events', function(done) {
s/supports/support
s/changed/change
;-)

https://codereview.appspot.com/7519044/diff/1/test/test_browser_search_widget.js#newcode55
test/test_browser_search_widget.js:55: it('should supports setting
search string', function() {
%s/supports/support
:-D

https://codereview.appspot.com/7519044/

lp:~rharding/juju-gui/search-widget updated
430. By Richard Harding

Code review updates

Revision history for this message
Richard Harding (rharding) wrote :
Download full text (3.2 KiB)

Comments submitted and code updated.

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/fullscreen.js
File app/subapps/browser/views/fullscreen.js (right):

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/fullscreen.js#newcode45
app/subapps/browser/views/fullscreen.js:45:
search.render(tpl_node.one('.bws-search'));
On 2013/03/12 16:25:35, jeff.pihach wrote:
> At this point you are rendering a widget into an element which isn't
yet
> rendered onto the page. What you might notice is that you will end up
with odd
> bugs when doing this because of dom calculations (scrollview has this
issue).

> A workaround is to put these in an 'afterRender' method and then call
that
> method in the showView() callback.

> You don't need to change this - I was just pointing that out in the
event you
> run into that issue :-)

Thanks for the heads up. In this case I don't think I'll hit any issues
with that. I'd rather make sure that the UI rendered in one swoop vs a
follow up.

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js
File app/subapps/browser/views/sidebar.js (right):

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode42
app/subapps/browser/views/sidebar.js:42: _bindEvents: function() {
On 2013/03/12 16:25:35, jeff.pihach wrote:
> Where is this method called from?

Ummm...well not i's called from the end of render() :)

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode44
app/subapps/browser/views/sidebar.js:44:
this.search.on(this.search.EVT_UPDATE_SEARCH, this._searchChanged,
this);
On 2013/03/12 16:25:35, jeff.pihach wrote:
> These events aren't being detached on destroy

Updated

https://codereview.appspot.com/7519044/diff/1/app/subapps/browser/views/sidebar.js#newcode103
app/subapps/browser/views/sidebar.js:103:
this.search.render(tpl_node.one('.bws-search'));
On 2013/03/12 16:25:35, jeff.pihach wrote:
> See the rendering outside of the DOM issue comment from the previous
file.

rgr, thanks for the heads up.

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js
File app/widgets/charm-search.js (right):

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js#newcode110
app/widgets/charm-search.js:110:
this.get('contentBox').one('input').set('value', '');
On 2013/03/12 16:25:35, jeff.pihach wrote:
> If the input is in focus then this will trigger valueChange, I
recommend:

> input.blur();
> input.set('value', '');

Thanks for bringing this up. I think the goal is to fire the event so
I've added focus() to the input. The use case for this is something
where something in the UI forces a search/filter update to be performed.
If another view/widget wants to update the search string, it should be
allowed, updated, and then this widget fires a change event so that the
view can reload new data.

https://codereview.appspot.com/7519044/diff/1/app/widgets/charm-search.js#newcode175
app/widgets/charm-search.js:175:
this.get('boundingBox').one('input').set('value', newval);
On 2013/03/12 16:25:35, jeff.pihach wrote:
> If this input is in focus then it will trigger ...

Read more...

Revision history for this message
Richard Harding (rharding) wrote :
lp:~rharding/juju-gui/search-widget updated
431. By Richard Harding

Add the focus to the input to make sure change event is fired on update

Revision history for this message
Richard Harding (rharding) wrote :
Revision history for this message
Jeff Pihach (hatch) wrote :
Revision history for this message
j.c.sackett (jcsackett) wrote :

LGTM, just one question below.

https://codereview.appspot.com/7519044/diff/13001/app/widgets/charm-search.js
File app/widgets/charm-search.js (right):

https://codereview.appspot.com/7519044/diff/13001/app/widgets/charm-search.js#newcode165
app/widgets/charm-search.js:165: syncUI: function() {},
Do you even need it, then?

https://codereview.appspot.com/7519044/

lp:~rharding/juju-gui/search-widget updated
432. By Richard Harding

Garden

Revision history for this message
Richard Harding (rharding) wrote :

*** Submitted:

Implement the browser search control widget.

- Add a new widget containing the search input
- Provide events to the outside world to update/watch for search phrase
changes
- Add tests
- Hook widget into the render of the fullscreen and sidebar views.

R=jeff.pihach, j.c.sackett
CC=
https://codereview.appspot.com/7519044

https://codereview.appspot.com/7519044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/modules-debug.js'
2--- app/modules-debug.js 2013-03-11 20:46:31 +0000
3+++ app/modules-debug.js 2013-03-13 15:32:23 +0000
4@@ -68,6 +68,10 @@
5 fullpath: '/juju-ui/widgets/charm-slider.js'
6 },
7
8+ 'browser-search-widget': {
9+ fullpath: '/juju-ui/widgets/charm-search.js'
10+ },
11+
12 'reconnecting-websocket': {
13 fullpath: '/juju-ui/assets/javascripts/reconnecting-websocket.js'
14 },
15
16=== modified file 'app/subapps/browser/templates/fullscreen.handlebars'
17--- app/subapps/browser/templates/fullscreen.handlebars 2013-03-07 22:25:58 +0000
18+++ app/subapps/browser/templates/fullscreen.handlebars 2013-03-13 15:32:23 +0000
19@@ -1,3 +1,4 @@
20 <div id="bws-fullscreen">
21- <a href="#" class="hide">Hide</a>
22+ <div class="bws-search">
23+ </div>
24 </div>
25
26=== modified file 'app/subapps/browser/templates/sidebar.handlebars'
27--- app/subapps/browser/templates/sidebar.handlebars 2013-03-07 22:25:58 +0000
28+++ app/subapps/browser/templates/sidebar.handlebars 2013-03-13 15:32:23 +0000
29@@ -2,13 +2,6 @@
30 <div id="bws-sidebar">
31
32 <div class="bws-search">
33- <h5 class="reset">
34- <img height="16px" width="16px"/>&nbsp;Charm Browser
35- </h5>
36- <form>
37- <input type="search" name="search_term"
38- placeholder="Search for a charm..." />
39- </form>
40 </div>
41
42 <div class="bws-left">Main View</div>
43
44=== modified file 'app/subapps/browser/views/fullscreen.js'
45--- app/subapps/browser/views/fullscreen.js 2013-03-06 18:24:05 +0000
46+++ app/subapps/browser/views/fullscreen.js 2013-03-13 15:32:23 +0000
47@@ -3,7 +3,8 @@
48
49 YUI.add('subapp-browser-fullscreen', function(Y) {
50 var ns = Y.namespace('juju.browser.views'),
51- views = Y.namespace('juju.views');
52+ views = Y.namespace('juju.views'),
53+ widgets = Y.namespace('juju.widgets');
54
55 /**
56 * Browser Sub App for the Juju Gui.
57@@ -37,10 +38,16 @@
58 *
59 */
60 render: function(container) {
61+ var search = new widgets.browser.Search(),
62+ tpl = this.template(),
63+ tpl_node = Y.Node.create(tpl);
64+
65+ search.render(tpl_node.one('.bws-search'));
66+
67 if (!Y.Lang.isValue(container)) {
68 container = this.get('container');
69 }
70- container.setHTML(this.template({}));
71+ container.setHTML(tpl_node);
72 },
73
74 /**
75@@ -56,5 +63,8 @@
76 });
77
78 }, '0.1.0', {
79- requires: ['view']
80+ requires: [
81+ 'browser-search-widget',
82+ 'view'
83+ ]
84 });
85
86=== modified file 'app/subapps/browser/views/sidebar.js'
87--- app/subapps/browser/views/sidebar.js 2013-03-08 19:52:02 +0000
88+++ app/subapps/browser/views/sidebar.js 2013-03-13 15:32:23 +0000
89@@ -10,7 +10,8 @@
90 */
91 YUI.add('subapp-browser-sidebar', function(Y) {
92 var ns = Y.namespace('juju.browser.views'),
93- views = Y.namespace('juju.views');
94+ views = Y.namespace('juju.views'),
95+ widgets = Y.namespace('juju.widgets');
96
97 /**
98 * Sidebar master view for the gui browser.
99@@ -20,6 +21,7 @@
100 *
101 */
102 ns.Sidebar = Y.Base.create('browser-view-sidebar', Y.View, [], {
103+ _events: [],
104 template: views.Templates.sidebar,
105 visible: true,
106
107@@ -28,9 +30,39 @@
108 *
109 */
110 events: {
111- '.sidebar-toggle': {
112- click: '_toggleSidebar'
113- }
114+ },
115+
116+ /**
117+ * Bind the non native DOM events from within the View. This includes
118+ * watching widgets used for their exposed events.
119+ *
120+ * @method _bindEvents
121+ * @private
122+ *
123+ */
124+ _bindEvents: function() {
125+ // Watch the Search widget for changes to the search params.
126+ this._events.push(
127+ this.search.on(
128+ this.search.EVT_UPDATE_SEARCH, this._searchChanged, this)
129+ );
130+
131+ this._events.push(
132+ this.search.on(
133+ this.search.EVT_TOGGLE_VIEWABLE, this._toggleSidebar, this)
134+ );
135+ },
136+
137+ /**
138+ * When the search term or filter is changed, fetch new data and redraw.
139+ *
140+ * @method _searchChanged
141+ * @param {Event} ev event object from catching changes.
142+ * @private
143+ *
144+ */
145+ _searchChanged: function(ev) {
146+ console.log('Sidebar search changed.');
147 },
148
149 /**
150@@ -55,6 +87,18 @@
151 },
152
153 /**
154+ * Destroy this view and clear from the dom world.
155+ *
156+ * @method destructor
157+ *
158+ */
159+ destructor: function() {
160+ Y.Array.each(this._events, function(ev) {
161+ ev.detach();
162+ });
163+ },
164+
165+ /**
166 * General YUI initializer.
167 *
168 * @method initializer
169@@ -70,19 +114,21 @@
170 *
171 */
172 render: function(container) {
173+ var tpl = this.template(),
174+ tpl_node = Y.Node.create(tpl);
175+
176+ // build widgets used in the template.
177+ this.search = new widgets.browser.Search(),
178+ this.search.render(tpl_node.one('.bws-search'));
179+
180 if (typeof container !== 'object') {
181 container = this.get('container');
182 }
183- container.setHTML(this.template({}));
184- },
185+ container.setHTML(tpl_node);
186
187- /**
188- * Destroy this view and clear from the dom world.
189- *
190- * @method destructor
191- *
192- */
193- destructor: function() {}
194+ // Bind extra events that aren't covered by the Y.View events object.
195+ this._bindEvents();
196+ }
197
198 }, {
199 ATTRS: {}
200@@ -90,6 +136,7 @@
201
202 }, '0.1.0', {
203 requires: [
204+ 'browser-search-widget',
205 'view'
206 ]
207 });
208
209=== added file 'app/templates/browser-search.handlebars'
210--- app/templates/browser-search.handlebars 1970-01-01 00:00:00 +0000
211+++ app/templates/browser-search.handlebars 2013-03-13 15:32:23 +0000
212@@ -0,0 +1,12 @@
213+<div class="search-container">
214+ <div class="bws-icon">Icon</div>
215+ <div class=""><a href="">Charm Browser</a></div>
216+ <div class="align-right">
217+ <form>
218+ <input type="search" name="bws_search"
219+ value="{{ term }}"
220+ placeholder="Search for a charm..."/>
221+ </form>
222+ </div>
223+ <div class="toggle-fullscreen align-right"> X </div>
224+</div>
225
226=== added file 'app/widgets/charm-search.js'
227--- app/widgets/charm-search.js 1970-01-01 00:00:00 +0000
228+++ app/widgets/charm-search.js 2013-03-13 15:32:23 +0000
229@@ -0,0 +1,195 @@
230+'use strict';
231+
232+
233+/**
234+ * The widget used across Browser view to manage the search box and the
235+ * controls for selecting which view you're in.
236+ *
237+ * @module widgets
238+ * @submodule browser
239+ *
240+ */
241+YUI.add('browser-search-widget', function(Y) {
242+ var ns = Y.namespace('juju.widgets.browser'),
243+ templates = Y.namespace('juju.views').Templates;
244+
245+ /**
246+ * Search widget present in the Charm browser across both fullscreen and
247+ * sidebar views.
248+ *
249+ * @class Search
250+ * @extends {Y.Widget}
251+ *
252+ */
253+ ns.Search = Y.Base.create('search-widget', Y.Widget, [], {
254+ _events: [],
255+
256+ EVT_CLEAR_SEARCH: 'clear_search',
257+ EVT_TOGGLE_VIEWABLE: 'toggle_viewable',
258+ EVT_TOGGLE_FULLSCREEN: 'toggle_fullscreen',
259+ EVT_UPDATE_SEARCH: 'update_search',
260+ EVT_SEARCH_CHANGED: 'search_changed',
261+
262+ TEMPLATE: templates['browser-search'],
263+
264+ /**
265+ * Expose to the outside world that we've got a request to go fullscreen.
266+ *
267+ * @method _toggleFullScreen
268+ * @param {Event} ev the click event from the control.
269+ * @private
270+ *
271+ */
272+ _toggleFullScreen: function(ev) {
273+ this.fire(this.EVT_TOGGLE_FULLSCREEN);
274+ },
275+
276+ /**
277+ * Expose to the outside world that we've got a request to hide from
278+ * sight.
279+ *
280+ * @method _toggleViewable
281+ * @param {Event} ev the click event from the control.
282+ * @private
283+ *
284+ */
285+ _toggleViewable: function(ev) {
286+ this.fire(this.EVT_TOGGLE_VIEWABLE);
287+ },
288+
289+ /**
290+ * detach listeners for dom events.
291+ *
292+ * @method _unbind_events
293+ * @private
294+ * @return {undefined} mutates only.
295+ */
296+ _unbindUI: function() {
297+ Y.array.each(this._events, function(item) {
298+ item.detach();
299+ });
300+ },
301+
302+ /**
303+ * bind the UI events to the DOM making up the widget control.
304+ *
305+ * @method bindUI
306+ *
307+ */
308+ bindUI: function() {
309+ var container = this.get('boundingBox');
310+
311+ this._events.push(
312+ container.one('.bws-icon').on(
313+ 'click', this._toggleViewable, this)
314+ );
315+ this._events.push(
316+ container.one('.toggle-fullscreen').on(
317+ 'click', this._toggleFullScreen, this)
318+ );
319+
320+ // Note that the search could be updated either from our internal input
321+ // control, or it could come from someone outside of the widget asking
322+ // it to update to a specific value. This is how things like clicking
323+ // categories can work.
324+ var input = container.one('input');
325+ this._events.push(
326+ input.on('valueChange', function(ev) {
327+ this.fire(this.EVT_SEARCH_CHANGED);
328+ }, this)
329+ );
330+ },
331+
332+ /**
333+ * Clear the search input control in order to reset it.
334+ *
335+ * @method clearSearch
336+ *
337+ */
338+ clearSearch: function() {
339+ var input = this.get('contentBox').one('input');
340+ input.focus();
341+ input.set('value', '');
342+ },
343+
344+
345+ /**
346+ * destory the widget and unbind all DOM events.
347+ *
348+ * @method destructor
349+ *
350+ */
351+ destructor: function() {
352+ this._unbindUI();
353+ },
354+
355+ /**
356+ * Generic initializer for the widget. Publish events we expose for
357+ * outside use.
358+ *
359+ * @method initializer
360+ * @param {Object} cfg configuration override object.
361+ *
362+ */
363+ initializer: function(cfg) {
364+ /**
365+ * Fires when the "Charm Browser" link is checked. Needs to communicate
366+ * with the parent view so that it can handle filters and the like. This
367+ * widget only needs to clear the search input box.
368+ *
369+ */
370+ this.publish(this.EVT_TOGGLE_VIEWABLE);
371+ this.publish(this.EVT_TOGGLE_FULLSCREEN);
372+ this.publish(this.EVT_SEARCH_CHANGED);
373+ },
374+
375+ /**
376+ * Render all the things!
377+ *
378+ * @method renderUI
379+ *
380+ */
381+ renderUI: function() {
382+ this.get('contentBox').setHTML(
383+ this.TEMPLATE(this.getAttrs())
384+ );
385+ },
386+
387+ /**
388+ * Update the search input to contain the string passed. This is meant to
389+ * be used by outside links that want to perform a pre-canned search and
390+ * display results.
391+ *
392+ * @method update_search
393+ * @param {String} newval the sting to update the input to.
394+ *
395+ */
396+ updateSearch: function(newval) {
397+ var input = this.get('contentBox').one('input');
398+ input.focus();
399+ input.set('value', newval);
400+ }
401+
402+ }, {
403+ ATTRS: {
404+
405+ /**
406+ * @attribute term
407+ * @default undefined
408+ * @type {String}
409+ *
410+ */
411+ term: {}
412+
413+ }
414+ });
415+
416+}, '0.1.0', {
417+ requires: [
418+ 'base',
419+ 'event',
420+ 'event-valuechange',
421+ 'juju-templates',
422+ 'widget'
423+ ]
424+});
425
426=== modified file 'lib/views/stylesheet.less'
427--- lib/views/stylesheet.less 2013-03-12 17:16:39 +0000
428+++ lib/views/stylesheet.less 2013-03-13 15:32:23 +0000
429@@ -23,6 +23,7 @@
430 @charm-panel-width: 292px;
431 @navbar-color: #2D2D2D!important;
432
433+
434 body {
435 margin-top: 87px;
436 background-color: #302b28;
437@@ -64,6 +65,10 @@
438 border: none;
439 }
440
441+.align-right {
442+ text-align: right;
443+}
444+
445 i.sprite {
446 display: inline-block;
447 vertical-align: middle;
448
449=== modified file 'test/index.html'
450--- test/index.html 2013-03-12 17:16:39 +0000
451+++ test/index.html 2013-03-13 15:32:23 +0000
452@@ -40,6 +40,7 @@
453 <script src="test_charm_panel.js"></script>
454 <script src="test_charm_small_widget.js"></script>
455 <script src="test_charm_slider.js"></script>
456+ <script src="test_browser_search_widget.js"></script>
457 <script src="test_charm_store.js"></script>
458 <script src="test_charm_view.js"></script>
459 <script src="test_console.js"></script>
460
461=== modified file 'test/test_browser_app.js'
462--- test/test_browser_app.js 2013-03-08 19:52:02 +0000
463+++ test/test_browser_app.js 2013-03-13 15:32:23 +0000
464@@ -39,6 +39,8 @@
465
466 // And the hide button is rendered to the container node.
467 assert.isTrue(Y.Lang.isObject(container.one('#bws-fullscreen')));
468+ // Also verify that the search widget has rendered into the view code.
469+ assert.isTrue(Y.Lang.isObject(container.one('input')));
470 });
471
472 });
473@@ -75,6 +77,8 @@
474
475 // And the hide button is rendered to the container node.
476 assert.isTrue(Y.Lang.isObject(container.one('#bws-sidebar')));
477+ // Also verify that the search widget has rendered into the view code.
478+ assert.isTrue(Y.Lang.isObject(container.one('input')));
479 });
480
481 });
482
483=== added file 'test/test_browser_search_widget.js'
484--- test/test_browser_search_widget.js 1970-01-01 00:00:00 +0000
485+++ test/test_browser_search_widget.js 2013-03-13 15:32:23 +0000
486@@ -0,0 +1,113 @@
487+'use strict';
488+
489+
490+describe('browser search widget', function() {
491+ var Y, container, Search;
492+
493+ before(function(done) {
494+ Y = YUI(GlobalConfig).use(['browser-search-widget',
495+ 'event-simulate',
496+ 'node-event-simulate',
497+ 'node'], function(Y) {
498+ Search = Y.juju.widgets.browser.Search;
499+ done();
500+ });
501+ });
502+
503+ beforeEach(function() {
504+ container = Y.Node.create('<div id="container"></div>');
505+ Y.one('body').prepend(container);
506+ });
507+
508+ afterEach(function() {
509+ container.remove(true);
510+ });
511+
512+ it('needs to render from the template', function() {
513+ var search = new Search();
514+ search.render(container);
515+ assert.isObject(container.one('.search-container'));
516+ assert.isObject(container.one('.bws-icon'));
517+ });
518+
519+ it('should support search chang events', function(done) {
520+ // Need a small timeout for the valueChange to pick up the change in the
521+ // search input.
522+ this.timeout(200);
523+ var search = new Search();
524+ search.render(container);
525+
526+ var triggered = false;
527+
528+ search.on(search.EVT_SEARCH_CHANGED, function(ev) {
529+ triggered = true;
530+ // now trigger the event and make sure that it fired to our custom
531+ // watcher outside the widget.
532+ triggered.should.eql(true);
533+ done();
534+ });
535+
536+ var input = container.one('input');
537+ input.focus();
538+ input.set('value', 'test');
539+ });
540+
541+ it('should support setting search string', function() {
542+ var search = new Search();
543+ search.render(container);
544+
545+ search.updateSearch('test');
546+ container.one('input').get('value').should.eql('test');
547+ });
548+
549+ it('should supports clearing search string', function() {
550+ var search = new Search({
551+ term: 'test'
552+ });
553+ search.render(container);
554+ container.one('input').get('value').should.eql('test');
555+
556+ search.clearSearch();
557+ container.one('input').get('value').should.eql('');
558+ });
559+
560+ it('should supports clearing search string', function() {
561+ var search = new Search({
562+ term: 'test'
563+ });
564+ search.render(container);
565+ container.one('input').get('value').should.eql('test');
566+
567+ search.clearSearch();
568+ container.one('input').get('value').should.eql('');
569+ });
570+
571+ it('should fire a toggle fullscreen event when expand clicked', function() {
572+ var search = new Search(),
573+ triggered = false;
574+ search.render(container);
575+
576+ search.on(search.EVT_TOGGLE_FULLSCREEN, function(ev) {
577+ triggered = true;
578+ });
579+
580+ var toggle = container.one('.toggle-fullscreen');
581+ toggle.simulate('click');
582+ triggered.should.eql(true);
583+ });
584+
585+ it('should fire a toggle viewable event when icon clicked', function() {
586+ var search = new Search(),
587+ triggered = false;
588+ search.render(container);
589+
590+ search.on(search.EVT_TOGGLE_VIEWABLE, function(ev) {
591+ triggered = true;
592+ });
593+
594+ var toggle = container.one('.bws-icon');
595+ toggle.simulate('click');
596+ triggered.should.eql(true);
597+ });
598+
599+});

Subscribers

People subscribed via source and target branches