Merge lp:~jcsackett/juju-gui/search-view into lp:juju-gui/experimental

Proposed by j.c.sackett
Status: Merged
Merged at revision: 598
Proposed branch: lp:~jcsackett/juju-gui/search-view
Merge into: lp:juju-gui/experimental
Diff against target: 785 lines (+371/-91)
16 files modified
app/modules-debug.js (+10/-2)
app/subapps/browser/browser.js (+43/-13)
app/subapps/browser/templates/search.handlebars (+4/-0)
app/subapps/browser/views/charm.js (+2/-13)
app/subapps/browser/views/editorial.js (+14/-15)
app/subapps/browser/views/search.js (+110/-0)
app/subapps/browser/views/utils.js (+43/-0)
app/subapps/browser/views/view.js (+14/-14)
app/templates/browser-search.handlebars (+1/-1)
app/widgets/charm-search.js (+23/-7)
test/index.html (+10/-8)
test/test_browser_app.js (+4/-4)
test/test_browser_charm_details.js (+0/-1)
test/test_browser_search_view.js (+72/-0)
test/test_browser_search_widget.js (+2/-13)
test/test_browser_view_utils.js (+19/-0)
To merge this branch: bzr merge lp:~jcsackett/juju-gui/search-view
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+159493@code.launchpad.net

Description of the change

Add search view.

SearchView is pretty basic; it knows its search text, and can query for it via
the Charmworld0 api.
It renders results out to a container, passed in at render.
It requeries and renders when the text changes.

https://codereview.appspot.com/8835044/

To post a comment you must log in.
Revision history for this message
j.c.sackett (jcsackett) wrote :

Reviewers: mp+159493_code.launchpad.net,

Message:
Please take a look.

Description:
Add search view.

SearchView is pretty basic; it knows its search text, and can query for
it via
the Charmworld0 api.
It renders results out to a container, passed in at render.
It requeries and renders when the text changes.

https://code.launchpad.net/~jcsackett/juju-gui/search-view/+merge/159493

(do not edit description out of merge proposal)

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

Affected files:
   A [revision details]
   M app/modules-debug.js
   A app/subapps/browser/views/search.js
   M test/index.html
   M test/test_browser_charm_details.js
   A test/test_browser_search_view.js

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

This branch seems to be missing the tie in for the text input. The
re-search is driven by the ATTR on the view, but getting that text into
there is missing. I'd like to chat and see what the plan is.

Comments below, but take those with a grain of salt as I'm not sure I
follow.

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

https://codereview.appspot.com/8835044/diff/1/app/subapps/browser/views/search.js#newcode29
app/subapps/browser/views/search.js:29: if (!this.get('rendered')) {
this can go away if you move the ajax call per the later comment.

https://codereview.appspot.com/8835044/diff/1/app/subapps/browser/views/search.js#newcode32
app/subapps/browser/views/search.js:32: if (!container) {
move this logic into the render and just assume you're always given a
container here. That way the logic isn't split in two places.

https://codereview.appspot.com/8835044/diff/1/app/subapps/browser/views/search.js#newcode36
app/subapps/browser/views/search.js:36: this.get('store').search(text, {
Can we move this back up to render as is done in the CharmView here:
http://bazaar.launchpad.net/~juju-gui/juju-gui/trunk/view/head:/app/subapps/browser/views/charm.js#L415

This way the _renderSearchResults is only rendering and known to have
results handed to it.

https://codereview.appspot.com/8835044/diff/1/app/subapps/browser/views/search.js#newcode83
app/subapps/browser/views/search.js:83: }));
you can pass the scope as the final parameter to after so that you don't
need to deal with the currentTarget business. Just
this.get('container').

https://codereview.appspot.com/8835044/diff/1/test/test_browser_search_view.js
File test/test_browser_search_view.js (right):

https://codereview.appspot.com/8835044/diff/1/test/test_browser_search_view.js#newcode24
test/test_browser_search_view.js:24: container = Y.Node.create('<div
id="container"></div>');
so the container should come from the View and then get appended to
something. I was trying to clean this up in
https://code.launchpad.net/~rharding/juju-gui/browser_links/+merge/159215

The way Y.View is meant to work (and I've been doing this wrong) is that
it defaults to an empty <div> as a container and then your render call
is responsible for putting it somewhere on the DOM.

https://codereview.appspot.com/8835044/

lp:~jcsackett/juju-gui/search-view updated
559. By j.c.sackett

Merged search-routing into search-view.

560. By j.c.sackett

Merged search-routing into search-view.

561. By j.c.sackett

Merged search-routing into search-view.

562. By j.c.sackett

Merged api-faiure-util into search-view.

563. By j.c.sackett

apiFailure driveby

564. By j.c.sackett

Search results rendering.

565. By j.c.sackett

Test fix.

566. By j.c.sackett

Test fixes.

567. By j.c.sackett

Resolved conflicts.

568. By j.c.sackett

Add apiFailure utils req.

569. By j.c.sackett

Merged api-faiure-util into search-view.

570. By j.c.sackett

Revert utils req; uneeded, breaks devel.

571. By j.c.sackett

Shut up, lint.

572. By j.c.sackett

No really, shut up, lint.

573. By j.c.sackett

Documentation.

574. By j.c.sackett

More lint.

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-04-13 00:18:21 +0000
3+++ app/modules-debug.js 2013-04-22 13:35:38 +0000
4@@ -288,6 +288,10 @@
5 fullpath: '/juju-ui/subapps/browser/views/fullscreen.js'
6 },
7
8+ 'subapp-browser-searchview': {
9+ fullpath: '/juju-ui/subapps/browser/views/search.js'
10+ },
11+
12 'subapp-browser-sidebar': {
13 fullpath: '/juju-ui/subapps/browser/views/sidebar.js',
14 requires: [
15@@ -298,8 +302,12 @@
16 },
17
18 'subapp-browser-editorial': {
19- fullpath: '/juju-ui/subapps/browser/views/editorial.js',
20- requires: ['subapp-browser-sidebar']
21+ fullpath: '/juju-ui/subapps/browser/views/editorial.js'
22+ },
23+
24+ //Browser view utils
25+ 'subapp-browser-view-utils': {
26+ fullpath: '/juju-ui/subapps/browser/views/utils.js'
27 },
28
29 //Browser Models
30
31=== modified file 'app/subapps/browser/browser.js'
32--- app/subapps/browser/browser.js 2013-04-19 17:58:14 +0000
33+++ app/subapps/browser/browser.js 2013-04-22 13:35:38 +0000
34@@ -63,9 +63,14 @@
35 if (this._viewState.charmID) {
36 urlParts.push(this._viewState.charmID);
37 }
38-
39- // Always end on a /
40- return urlParts.join('/');
41+ var url = urlParts.join('/');
42+ if (this._viewState.querystring) {
43+ url = Y.Lang.sub('{ url }?{ qs }', {
44+ url: url,
45+ qs: this._viewState.querystring
46+ });
47+ }
48+ return url;
49 },
50
51 /**
52@@ -201,7 +206,7 @@
53 this._viewState.viewmode = params.viewmode;
54
55 // Check for a charm id in the request.
56- if (params.id) {
57+ if (params.id && params.id !== 'search') {
58 this._viewState.charmID = params.id;
59 } else {
60 this._viewState.charmID = null;
61@@ -268,9 +273,9 @@
62 },
63
64 /**
65- * Render the sidebar view of a specific charm to the client.
66+ * Render the charm details view
67 *
68- * @method sidebarCharm
69+ * @method renderCharmDetails
70 * @param {Request} req current request object.
71 * @param {Response} res current response object.
72 * @param {function} next callable for the next route in the chain.
73@@ -317,7 +322,6 @@
74 renderEditorial: function(req, res, next) {
75 // If loading the interesting content then it's not a search going on.
76 var container = this.get('container'),
77- editorialContainer,
78 extraCfg = {};
79
80 if (this._viewState.viewmode === 'fullscreen') {
81@@ -346,11 +350,35 @@
82 },
83
84 /**
85- Place holder for a method to render out search so we can test url parsing
86+ * Render search results
87+ *
88+ * @method renderSearch
89+ * @param {Request} req current request object.
90+ * @param {Response} res current response object.
91+ * @param {function} next callable for the next route in the chain.
92+ */
93+ renderSearch: function(req, res, next) {
94+ var container = this.get('container'),
95+ extraCfg = {},
96+ query;
97+ if (this._viewState.querystring) {
98+ query = Y.QueryString.parse();
99+ } else {
100+ // If there's no querystring, we need a default "empty" search.
101+ query = {text: ''};
102+ }
103
104- */
105- renderSearchResults: function(req, res, next) {
106- console.log('rendered search results.');
107+ if (this._viewState.viewmode === 'fullscreen') {
108+ extraCfg.renderTo = container.one('.bws-view-data');
109+ extraCfg.isFullscreen = true;
110+ } else {
111+ extraCfg.renderTo = container.one('.bws-content');
112+ }
113+ extraCfg.text = query.text;
114+ this._search = new Y.juju.browser.views.BrowserSearchView(
115+ this._getViewCfg(extraCfg));
116+ this._search.render();
117+ this._search.addTarget(this);
118 },
119
120 /**
121@@ -379,7 +407,7 @@
122 } else if (this._shouldShowSearch()) {
123 // Render search results if search is in the url and the viewmode or
124 // the search has been changed in the state.
125- this.renderSearchResults(req, res, next);
126+ this.renderSearch(req, res, next);
127 } else if (!this._viewState.charmID) {
128 // Render the editorial in fullscreen only if we don't have a charmid
129 this.renderEditorial(req, res, next);
130@@ -409,7 +437,7 @@
131 // Render search results if search is in the url and the viewmode or the
132 // search has been changed in the state.
133 if (this._shouldShowSearch()) {
134- this.renderSearchResults(req, res, next);
135+ this.renderSearch(req, res, next);
136 }
137
138 if (this._shouldShowEditorial()) {
139@@ -531,10 +559,12 @@
140 requires: [
141 'juju-charm-store',
142 'juju-models',
143+ 'querystring-parse',
144 'sub-app',
145 'subapp-browser-charmview',
146 'subapp-browser-editorial',
147 'subapp-browser-fullscreen',
148+ 'subapp-browser-searchview',
149 'subapp-browser-sidebar'
150 ]
151 });
152
153=== added file 'app/subapps/browser/templates/search.handlebars'
154--- app/subapps/browser/templates/search.handlebars 1970-01-01 00:00:00 +0000
155+++ app/subapps/browser/templates/search.handlebars 2013-04-22 13:35:38 +0000
156@@ -0,0 +1,4 @@
157+<div id="bws-search">
158+ <h3>{{ count }} results found</h3>
159+ <div class="search-results"></div>
160+</div>
161
162=== modified file 'app/subapps/browser/views/charm.js'
163--- app/subapps/browser/views/charm.js 2013-04-19 15:51:06 +0000
164+++ app/subapps/browser/views/charm.js 2013-04-22 13:35:38 +0000
165@@ -68,19 +68,7 @@
166 *
167 */
168 apiFailure: function(data, request) {
169- var message;
170- if (data && data.type) {
171- message = 'Charm API error of type: ' + data.type;
172- } else {
173- message = 'Charm API server did not respond';
174- }
175- this.get('db').notifications.add(
176- new models.Notification({
177- title: 'Failed to load sidebar content.',
178- message: message,
179- level: 'error'
180- })
181- );
182+ Y.juju.browser.views.utils.apiFailure(data, request, this);
183 },
184
185 /**
186@@ -561,6 +549,7 @@
187 'juju-view-utils',
188 'node',
189 'prettify',
190+ 'subapp-browser-view-utils',
191 'view'
192 ]
193 });
194
195=== modified file 'app/subapps/browser/views/editorial.js'
196--- app/subapps/browser/views/editorial.js 2013-04-19 17:09:07 +0000
197+++ app/subapps/browser/views/editorial.js 2013-04-22 13:35:38 +0000
198@@ -51,6 +51,17 @@
199 },
200
201 /**
202+ * Generates a message to the user based on a bad api call.
203+ *
204+ * @method apiFailure
205+ * @param {Object} data the json decoded response text.
206+ * @param {Object} request the original io_request object for debugging.
207+ *
208+ */
209+ apiFailure: function(data, request) {
210+ Y.juju.browser.views.utils.apiFailure(data, request, this);
211+ },
212+ /**
213 * General YUI initializer.
214 *
215 * @method initializer
216@@ -131,24 +142,11 @@
217 ];
218 },
219
220- 'failure': function(data, request) {
221- var message;
222- if (data && data.type) {
223- message = 'Charm API error of type: ' + data.type;
224- } else {
225- message = 'Charm API server did not respond';
226- }
227- this.get('db').notifications.add(
228- new models.Notification({
229- title: 'Failed to load landing page content.',
230- message: message,
231- level: 'error'
232- })
233- );
234- }
235+ 'failure': this.apiFailure
236 }, this);
237 },
238
239+ /*
240 /**
241 * Destroy this view and clear from the dom world.
242 *
243@@ -210,6 +208,7 @@
244 'juju-charm-store',
245 'juju-models',
246 'juju-templates',
247+ 'subapp-browser-view-utils',
248 'view'
249 ]
250 });
251
252=== added file 'app/subapps/browser/views/search.js'
253--- app/subapps/browser/views/search.js 1970-01-01 00:00:00 +0000
254+++ app/subapps/browser/views/search.js 2013-04-22 13:35:38 +0000
255@@ -0,0 +1,110 @@
256+'use strict';
257+
258+
259+/**
260+ * Provides searching functionality for the charm browser.
261+ *
262+ * @namespace juju
263+ * @module browser
264+ * @submodule views
265+ */
266+YUI.add('subapp-browser-searchview', function(Y) {
267+ var ns = Y.namespace('juju.browser.views'),
268+ views = Y.namespace('juju.views'),
269+ widgets = Y.namespace('juju.widgets'),
270+ models = Y.namespace('juju.models');
271+
272+ ns.BrowserSearchView = Y.Base.create('browser-view-searchview', Y.View, [
273+ Y.Event.EventTracker
274+ ], {
275+ template: views.Templates.search,
276+ /**
277+ * Renders the search results from the the store query.
278+ *
279+ * @method _renderSearchResults
280+ * @param {Y.Node} container Optional container to render results to.
281+ */
282+ _renderSearchResults: function(results) {
283+ var target = this.get('renderTo'),
284+ tpl = this.template({count: results.size()}),
285+ tplNode = Y.Node.create(tpl),
286+ container = tplNode.one('.search-results');
287+
288+ results.map(function(charm) {
289+ var ct = new widgets.browser.CharmToken(charm.getAttrs());
290+ ct.render(container);
291+ });
292+ target.setHTML(tplNode);
293+ },
294+
295+ /**
296+ * Generates a message to the user based on a bad api call.
297+ *
298+ * @method apiFailure
299+ * @param {Object} data the json decoded response text.
300+ * @param {Object} request the original io_request object for debugging.
301+ *
302+ */
303+ apiFailure: function(data, request) {
304+ Y.juju.browser.views.utils.apiFailure(data, request, this);
305+ },
306+
307+ /**
308+ * Renders the searchview, rendering search results for the view's search
309+ * text.
310+ *
311+ * @method render
312+ */
313+ render: function() {
314+ var text = this.get('text');
315+ this.get('store').search(text, {
316+ 'success': function(data) {
317+ var results = this.get('store').resultsToCharmlist(data.result);
318+ this._renderSearchResults(results);
319+ },
320+ 'failure': this.apiFailure
321+ }, this);
322+ }
323+ }, {
324+ ATTRS: {
325+ /**
326+ * The container node the view is rendering to.
327+ *
328+ * @attribute renderTo
329+ * @default undefined
330+ * @type {Y.Node}
331+ */
332+ renderTo: {},
333+
334+ /**
335+ * An instance of the Charmworld API object to hit for any data that
336+ * needs fetching.
337+ *
338+ * @attribute store
339+ * @default undefined
340+ * @type {Charmworld0}
341+ *
342+ */
343+ store: {},
344+
345+ /**
346+ * The text being searched on
347+ *
348+ * @attribute text
349+ * @default ''
350+ * @type {String}
351+ */
352+ text: {}
353+ }
354+ });
355+
356+}, '0.1.0', {
357+ requires: [
358+ 'event-tracker',
359+ 'browser-overlay-indicator',
360+ 'base-build',
361+ 'browser-charm-token',
362+ 'subapp-browser-view-utils',
363+ 'view'
364+ ]
365+});
366
367=== added file 'app/subapps/browser/views/utils.js'
368--- app/subapps/browser/views/utils.js 1970-01-01 00:00:00 +0000
369+++ app/subapps/browser/views/utils.js 2013-04-22 13:35:38 +0000
370@@ -0,0 +1,43 @@
371+'use strict';
372+
373+
374+/**
375+ * The view utils.
376+ *
377+ * @namespace juju
378+ * @module juju.browser.views
379+ * @submodule juju.browser.views.utils
380+ */
381+YUI.add('subapp-browser-view-utils', function(Y) {
382+
383+ var ns = Y.namespace('juju.browser.views.utils'),
384+ models = Y.namespace('juju.models');
385+
386+ /**
387+ * Shared method to generate a message to the user based on a bad api
388+ * call from a view.
389+ *
390+ * @method apiFailure
391+ * @param {Object} data the json decoded response text.
392+ * @param {Object} request the original io_request object for debugging.
393+ *
394+ */
395+ ns.apiFailure = function(data, request, view) {
396+ var message;
397+ if (data && data.type) {
398+ message = 'Charm API error of type: ' + data.type;
399+ } else {
400+ message = 'Charm API server did not respond';
401+ }
402+ view.get('db').notifications.add(
403+ new models.Notification({
404+ title: 'Failed to load sidebar content.',
405+ message: message,
406+ level: 'error'
407+ })
408+ );
409+ };
410+
411+}, '0.1.0', {
412+ requires: []
413+});
414
415=== modified file 'app/subapps/browser/views/view.js'
416--- app/subapps/browser/views/view.js 2013-04-16 23:39:54 +0000
417+++ app/subapps/browser/views/view.js 2013-04-22 13:35:38 +0000
418@@ -107,7 +107,17 @@
419 *
420 */
421 _searchChanged: function(ev) {
422- console.log('search changed.');
423+ // NB: This is temporary; eventually filtering will include categories,
424+ // and the Filter object will handle qs generation. But it's an unwieldy
425+ // url to parse while we only support text search.
426+ var qs = Y.QueryString.stringify({text: ev.details[0]});
427+ var change = {
428+ search: true,
429+ querystring: qs
430+ };
431+ this.fire('viewNavigate', {
432+ change: change
433+ });
434 },
435
436 /**
437@@ -160,19 +170,7 @@
438 *
439 */
440 apiFailure: function(data, request) {
441- var message;
442- if (data && data.type) {
443- message = 'Charm API error of type: ' + data.type;
444- } else {
445- message = 'Charm API server did not respond';
446- }
447- this.get('db').notifications.add(
448- new models.Notification({
449- title: 'Failed to load sidebar content.',
450- message: message,
451- level: 'error'
452- })
453- );
454+ Y.juju.browser.views.utils.apiFaiure(data, request, this);
455 },
456
457 /**
458@@ -269,6 +267,8 @@
459 'event-tracker',
460 'juju-charm-store',
461 'juju-models',
462+ 'querystring-stringify',
463+ 'subapp-browser-view-utils',
464 'view'
465 ]
466 });
467
468=== modified file 'app/templates/browser-search.handlebars'
469--- app/templates/browser-search.handlebars 2013-04-16 21:58:19 +0000
470+++ app/templates/browser-search.handlebars 2013-04-22 13:35:38 +0000
471@@ -6,7 +6,7 @@
472 <div class="bws-searchbox">
473 <form>
474 <input type="search" name="bws-search"
475- value="{{ term }}"
476+ value="{{ text }}"
477 placeholder="Search&hellip;"/>
478 </form>
479 </div>
480
481=== modified file 'app/widgets/charm-search.js'
482--- app/widgets/charm-search.js 2013-04-09 17:00:45 +0000
483+++ app/widgets/charm-search.js 2013-04-22 13:35:38 +0000
484@@ -1,8 +1,7 @@
485 'use strict';
486
487
488-/**
489- * The widget used across Browser view to manage the search box and the
490+/** * The widget used across Browser view to manage the search box and the
491 * controls for selecting which view you're in.
492 *
493 * @module widgets
494@@ -34,6 +33,17 @@
495 TEMPLATE: templates['browser-search'],
496
497 /**
498+ * Halt page reload from form submit and let the app know we have a new
499+ * search.
500+ *
501+ * @method _handleSubmit
502+ * @param {Event} ev the submit event.
503+ */
504+ _handleSubmit: function(ev) {
505+ ev.halt();
506+ this.fire(this.EVT_UPDATE_SEARCH, this.get('text'));
507+ },
508+ /**
509 * Expose to the outside world that we've got a request to go fullscreen.
510 *
511 * @method _toggleFullScreen
512@@ -76,6 +86,10 @@
513 container.one('.toggle-fullscreen').on(
514 'click', this._toggleFullScreen, this)
515 );
516+ this.addEvent(
517+ container.one('form').on(
518+ 'submit', this._handleSubmit, this)
519+ );
520
521 // Note that the search could be updated either from our internal input
522 // control, or it could come from someone outside of the widget asking
523@@ -84,6 +98,8 @@
524 var input = container.one('input');
525 this.addEvent(
526 input.on('valueChange', function(ev) {
527+ var val = ev.currentTarget.get('value');
528+ this.set('text', val);
529 this.fire(this.EVT_SEARCH_CHANGED);
530 }, this)
531 );
532@@ -155,13 +171,13 @@
533 },
534
535 /**
536- * @attribute term
537- * @default undefined
538+ * The search text.
539+ *
540+ * @attribute text
541+ * @default ''
542 * @type {String}
543- *
544 */
545- term: {}
546-
547+ text: {}
548 }
549 });
550
551
552=== modified file 'test/index.html'
553--- test/index.html 2013-04-10 11:57:11 +0000
554+++ test/index.html 2013-04-22 13:35:38 +0000
555@@ -30,36 +30,38 @@
556
557 <!-- Tests (Alphabetical)-->
558
559+ <script src="test_app_hotkeys.js"></script>
560 <script src="test_app.js"></script>
561- <script src="test_app_hotkeys.js"></script>
562 <script src="test_application_notifications.js"></script>
563 <script src="test_browser_app.js"></script>
564 <script src="test_browser_charm_details.js"></script>
565 <script src="test_browser_models.js"></script>
566+ <script src="test_browser_search_view.js"></script>
567+ <script src="test_browser_search_widget.js"></script>
568+ <script src="test_browser_view_utils.js"></script>
569 <script src="test_charm_collection_view.js"></script>
570 <script src="test_charm_configuration.js"></script>
571 <script src="test_charm_container.js"></script>
572 <script src="test_charm_panel.js"></script>
573+ <script src="test_charm_store.js"></script>
574 <script src="test_charm_token.js"></script>
575- <script src="test_browser_search_widget.js"></script>
576- <script src="test_charm_store.js"></script>
577 <script src="test_charm_view.js"></script>
578 <script src="test_console.js"></script>
579 <script src="test_d3_components.js"></script>
580 <script src="test_endpoints.js"></script>
581+ <script src="test_env_go.js"></script>
582+ <script src="test_environment_view.js"></script>
583 <script src="test_env.js"></script>
584+ <script src="test_env_python.js"></script>
585 <script src="test_event_tracker.js"></script>
586- <script src="test_env_go.js"></script>
587- <script src="test_env_python.js"></script>
588- <script src="test_environment_view.js"></script>
589 <script src="test_fakebackend.js"></script>
590- <script src="test_overlay_indicator.js"></script>
591 <script src="test_landscape.js"></script>
592 <script src="test_login.js"></script>
593+ <script src="test_model_handlers.js"></script>
594 <script src="test_model.js"></script>
595- <script src="test_model_handlers.js"></script>
596 <script src="test_notifications.js"></script>
597 <script src="test_notifier_widget.js"></script>
598+ <script src="test_overlay_indicator.js"></script>
599 <script src="test_panzoom.js"></script>
600 <script src="test_prettify.js"></script>
601 <script src="test_routing.js"></script>
602
603=== modified file 'test/test_browser_app.js'
604--- test/test_browser_app.js 2013-04-19 17:59:38 +0000
605+++ test/test_browser_app.js 2013-04-22 13:35:38 +0000
606@@ -175,7 +175,7 @@
607 sidebar: false,
608 renderCharmDetails: false,
609 renderEditorial: false,
610- renderSearchResults: false
611+ renderSearch: false
612 };
613 };
614 done();
615@@ -213,8 +213,8 @@
616 browser.renderEditorial = function() {
617 hits.renderEditorial = true;
618 };
619- browser.renderSearchResults = function() {
620- hits.renderSearchResults = true;
621+ browser.renderSearch = function() {
622+ hits.renderSearch = true;
623 };
624 // showView needs to be hacked because it does the rendering of
625 // fullscreen/sidebar.
626@@ -272,7 +272,7 @@
627 };
628 var expected = Y.merge(hits, {
629 sidebar: true,
630- renderSearchResults: true,
631+ renderSearch: true,
632 renderCharmDetails: true
633 });
634
635
636=== modified file 'test/test_browser_charm_details.js'
637--- test/test_browser_charm_details.js 2013-04-18 05:01:43 +0000
638+++ test/test_browser_charm_details.js 2013-04-22 13:35:38 +0000
639@@ -46,7 +46,6 @@
640 delete window.juju_config;
641 });
642
643- // Ensure the search results are rendered inside the container.
644 it('should be able to locate a readme file', function() {
645 view = new CharmView({
646 charm: new models.BrowserCharm({
647
648=== added file 'test/test_browser_search_view.js'
649--- test/test_browser_search_view.js 1970-01-01 00:00:00 +0000
650+++ test/test_browser_search_view.js 2013-04-22 13:35:38 +0000
651@@ -0,0 +1,72 @@
652+'use strict';
653+
654+
655+describe('search view', function() {
656+ var apiURL,
657+ container,
658+ view,
659+ Y;
660+
661+ before(function(done) {
662+ Y = YUI(GlobalConfig).use(
663+ 'json',
664+ 'juju-charm-store',
665+ 'node',
666+ 'subapp-browser-searchview',
667+ function(Y) {
668+ done();
669+ });
670+ });
671+
672+ beforeEach(function() {
673+ // Mock out a dummy location for the Store used in view instances.
674+ window.juju_config = {charmworldURL: 'http://localhost'};
675+ container = Y.Node.create('<div id="container"></div>');
676+ Y.one('body').append(container);
677+ view = new Y.juju.browser.views.BrowserSearchView({text: 'foo'});
678+ //
679+ // Create monkeypatched store to verify right method is called.
680+ apiURL = '';
681+ var fakeStore = new Y.juju.Charmworld0({});
682+ var sampleData = {
683+ result: [{
684+ id: 'foo/bar-2',
685+ name: 'bar',
686+ description: 'some charm named bar'
687+ }]
688+ };
689+ fakeStore.set('datasource', {
690+ sendRequest: function(params) {
691+ // Stubbing the server callback value
692+ apiURL = params.request;
693+ params.callback.success({
694+ response: {
695+ results: [{
696+ responseText: Y.JSON.stringify(sampleData)
697+ }]
698+ }
699+ });
700+ }
701+ });
702+ view.set('store', fakeStore);
703+ view.set('renderTo', container);
704+ });
705+
706+ afterEach(function() {
707+ delete window.juju_config;
708+ view.destroy();
709+ container.remove(true);
710+ });
711+
712+ it('exists', function() {
713+ assert.isObject(view);
714+ });
715+
716+ it('renders correctly', function() {
717+ view.render();
718+ assert.equal('charms?text=foo', apiURL);
719+ assert.equal(1, Y.all('.yui3-charmtoken').size());
720+ var charmText = Y.one('.yui3-charmtoken').one('.title').get('text');
721+ assert.equal(charmText.replace(/\s+/g, ''), 'bar');
722+ });
723+});
724
725=== modified file 'test/test_browser_search_widget.js'
726--- test/test_browser_search_widget.js 2013-03-25 19:12:45 +0000
727+++ test/test_browser_search_widget.js 2013-04-22 13:35:38 +0000
728@@ -44,6 +44,7 @@
729 // now trigger the event and make sure that it fired to our custom
730 // watcher outside the widget.
731 triggered.should.eql(true);
732+ assert.equal('test', this.get('text'));
733 done();
734 });
735
736@@ -62,18 +63,7 @@
737
738 it('should supports clearing search string', function() {
739 var search = new Search({
740- term: 'test'
741- });
742- search.render(container);
743- container.one('input').get('value').should.eql('test');
744-
745- search.clearSearch();
746- container.one('input').get('value').should.eql('');
747- });
748-
749- it('should supports clearing search string', function() {
750- var search = new Search({
751- term: 'test'
752+ text: 'test'
753 });
754 search.render(container);
755 container.one('input').get('value').should.eql('test');
756@@ -109,5 +99,4 @@
757 toggle.simulate('click');
758 triggered.should.eql(true);
759 });
760-
761 });
762
763=== added file 'test/test_browser_view_utils.js'
764--- test/test_browser_view_utils.js 1970-01-01 00:00:00 +0000
765+++ test/test_browser_view_utils.js 2013-04-22 13:35:38 +0000
766@@ -0,0 +1,19 @@
767+'use strict';
768+
769+describe('api failure utility', function() {
770+ var Y;
771+
772+ before(function(done) {
773+ Y = YUI(GlobalConfig).use('subapp-browser-view-utils', function(Y) {
774+ done();
775+ });
776+ });
777+
778+ beforeEach(function() {});
779+
780+ afterEach(function() {});
781+
782+ it('exists', function() {
783+ assert.isFunction(Y.juju.browser.views.utils.apiFailure);
784+ });
785+});

Subscribers

People subscribed via source and target branches