Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 889 lines (791 sloc) 32.674 kb
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
1 ==============
2 Binding Events
3 ==============
4
5 **Time Estimate:** 20 minutes
6
7 **Difficulty Level:** Advanced
8
9 Summary
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
10 =======
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
11
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
12 This example shows how to bind events to a mojit, configure code to run on the client, and make AJAX
13 calls to the YQL Web service. The application listens for events and then makes AJAX calls to
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
14 YQL to get Flickr photo information.
15
16 The following topics will be covered:
17
18 - configuring the application to run on the client
19 - getting Flickr data from the model with YQL
20 - binding events through the ``mojitProxy`` object
21 - making AJAX calls to YQL from the binder
22
23 Implementation Notes
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
24 ====================
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
25
26 Configuring the Application to Run on the Client
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
27 ------------------------------------------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
28
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
29 Mojito lets you configure applications to run on either the server or client side. This example uses
30 binders that are deployed to the client, so we need to configure Mojito to deploy the application
31 to the client, where it will be executed by the browser.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
32
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
33 To configure Mojito to run on the client, you simply set the ``"deploy"`` property to ``true`` in
34 ``application.json`` as seen below.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
35
36 .. code-block:: javascript
37
38 [
39 {
40 "settings": [ "master" ],
41 "specs": {
42 "frame": {
43 "type": "HTMLFrameMojit",
44 "config": {
45 "deploy": true,
46 "child": {
47 "type": "PagerMojit"
48 }
49 }
50 }
51 }
52 }
53 ]
54
55 Getting Data with YQL in the Model
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
56 ----------------------------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
57
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
58 In the mojit model, the `YUI YQL Query Utility <http://developer.yahoo.com/yui/3/yql/>`_ is used to
59 get Flickr photo information. To access the utility in your model, specify ``'yql'`` in the
60 ``requires`` array as seen in the code snippet below:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
61
62 .. code-block:: javascript
63
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
64 YUI.add('PagerMojitModel', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
65 ...
66 /* Code for PagerMojitModel */
67 ...
68 }, '0.0.1', {requires: ['yql']});
69
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
70 This code example uses the ``flickr.photos.search`` table to get information for photos that have a
71 title, description, or tags containing a string. For example, the YQL statement below returns Flickr
72 photo information for those photos that have a title, description, or tags containing the string
73 "Manhattan". Open the query in the YQL Console and click **TEST** to see the returned XML response.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
74
75 `select * from flickr.photos.search where text="Manhattan" <http://developer.yahoo.com/yql/console/#h=select%20*%20from%20flickr.photos.search%20where%20text%3D%22Manhattan%22>`_
76
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
77 The returned response contains photo information in the ``photo`` element. You extract the ``farm``,
78 ``server``, ``id``, and ``secret`` attributes from each photo element to create the photo URI as
79 seen here:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
80
81 ``http://farm + {farm} + static.flickr.com/ + {server} + / + {id} + _ + {secret} + .jpg``
82
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
83 In the ``model.js`` of ``PagerMojit`` shown below, the ``YQL`` function uses the YQL statement above
84 to get photo data, then parses the returned response to create the photo URIs. The model then wraps
85 the photo information in an object and stores those objects in the ``images`` array that is sent to
86 the controller through the ``callback`` function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
87
88 .. code-block:: javascript
89
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
90 YUI.add('PagerMojitModel', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
91 /**
92 * The PagerMojitModel module.
93 * @module PagerMojitModel
94 */
95 /**
96 * Constructor for the Model class.
97 * @class Model
98 * @constructor
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
99 **/
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
100 Y.namespace('mojito.models')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
101 init: function(config) {
102 this.config = config;
103 },
104 getData: function(query, start, count, callback) {
105 var q = null;
106 // Get Flickr API key: http://www.flickr.com/services/api/keys/apply/
107 var API_KEY = "{your_api_key}";
108 start = parseInt(start) || 0;
109 count = parseInt(count) || 10;
110 q = 'select * from flickr.photos.search(' + start + ',' + count + ') where text="%' + query + '%" and api_key="' + API_KEY+'"';
111 Y.YQL(q, function(rawData) {
112 if (!rawData.query.results) {
113 callback([]);
114 return;
115 }
116 var rawImages = rawData.query.results.photo, rawImage = null,images = [], image = null, i = 0;
117 for (; i<rawImages.length; i++) {
118 rawImage = rawImages[i];
119 image = {
120 title: rawImage.title,
121 location: 'http://farm' + rawImage.farm + '.static.flickr.com/' + rawImage.server + '/' + rawImage.id + '_' + rawImage.secret + '.jpg',
122 farm: rawImage.farm,
123 server: rawImage.server,
124 image_id: rawImage.id,
125 secret: rawImage.secret
126 };
127 if (!image.title) {
128 image.title = "Generic Title: " + query;
129 }
130 images.push(image);
131 }
132 callback(images);
133 });
134 }
135 };
136 }, '0.0.1', {requires: [ 'yql']});
137
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
138
139 For a more detailed explanation about how to use YQL in your Mojito application, see `Calling YQL
140 from a Mojit <calling_yql.html>`_. For more information about YQL, see the
141 `YQL Guide <http://developer.yahoo.com/yql/guide>`_.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
142
143 Binding Events
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
144 --------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
145
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
146 This section will discuss the basics of binding events in Mojito and then look at the binder used in
147 this code example.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
148
149 Binder Basics
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
150 #############
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
151
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
152 A mojit may have zero, one, or many binders within the ``binders`` directory. Each binder will be
153 deployed to the browser along with the rest of the mojit code, where the client-side Mojito runtime
154 will call it appropriately. On the client, the binder has a proxy object (``mojitProxy``) for
155 interacting with the mojit it represents as well as with other mojits on the page.
156 Methods can be called from the ``mojitProxy`` object that allow binders to listen for and fire
157 events.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
158
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
159 The binder consists of a constructor, an initializer, and a bind function. The following describes
160 each component and indicates when the ``mojitProxy`` object can be used.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
161
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
162 - **constructor** - creates the namespace for your binder that wraps the initialization code and
163 binder.
164 - **initializer** - is passed the ``mojitProxy`` where it can be stored and used to listen and fire
165 events with other binders. The ``mojitProxy`` is the only gateway back into the Mojito framework
166 for your binder.
167 - **bind** - is a function that is passed a ``Y.Node`` instance that wraps the DOM node representing
168 this mojit instance. The DOM event handlers for capturing user interactions should be attached in
169 this function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
170
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
171 The skeleton of the ``binders/index.js`` file below illustrates the basic structure of the binder.
172 For more information, see `Mojito Binders <../intro/mojito_binders.html>`_.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
173
174 .. code-block:: javascript
175
176 YUI.add('AwesomeMojitBinder', function(Y, NAME) {
177 // Binder constructor
178 Y.namespace('mojito.binders')[NAME] = {
179 init: function(mojitProxy) {
180 this.mojitProxy = mojitProxy;
181 },
182 // The bind function
183 bind: function(node) {
184 var thatNode = node;
185 }
186 };
187 Y.mojito.registerEventBinder('AwesomeMojit', Binder);
188 }, '0.0.1', {requires: ['mojito']});
189
190 Examining the PageMojitBinder
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
191 #############################
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
192
193 This code example uses the binder ``PageMojitBinder`` to perform the following:
194
195 - attach ``onClick`` handlers to ``prev`` and ``next`` links
196 - invoke the ``index`` method of the controller through the ``mojitProxy`` object
197 - create an overlay with Flickr photo information received from YQL
198
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
199 The ``binders/index.js`` for this code example is long and fairly involved, so we will dissect and
200 analyze the code. Let's begin by looking at the ``bind`` function of ``index.js``, which allows
201 mojits to attach DOM event handlers.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
202
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
203 In this code snippet of ``binders/index.js``, the ``bind`` function contains the nested
204 ``updateDOM`` function that updates node content and attaches event handlers. Using the
205 ``mojitProxy`` object, the nested ``flipper`` function calls the ``index`` function of the
206 controller. The callback ``updateDOM`` is passed to ``index`` to update the content.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
207
208 .. code-block:: javascript
209
210 ...
211 bind: function(node) {
212 var thatNode = node;
213 // Define the action when user click on prev/next.
214 var flipper = function(event) {
215 var target = event.target;
216 // Get the link to the page.
217 var page = parsePage(target.get('href'));
218 var updateDOM = function(markup) {
219 thatNode.set('innerHTML', markup);
220 thatNode.all('#nav a').on('click', flipper, this);
221 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
222 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
223 };
224 this.mojitProxy.invoke('index',
225 {
226 params: {page: page},
227 }, updateDOM
228 );
229 };
230 ...
231
232
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
233 The event handler for mouseovers and mouseouts are handled by the ``showOverlay`` function, which
234 creates the overlay containing photo information. In the code snippet below, ``showOverlay`` makes
235 an AJAX call to YQL to get photo data that is placed in an unordered list for the overlay.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
236
237 .. code-block:: javascript
238
239 ...
240 bind: function(node) {
241 ...
242 var showOverlay = function(event) {
243 var target = event.target;
244 var href = target.get('href');
245 var imageId = parseImageId(href);
246 if (target.hasClass('overlayed')) {
247 target.removeClass('overlayed');
248 thatNode.one('#display').setContent('');
249 } else {
250 Y.log('HREF: ' + href);
251 Y.log('IMAGE ID: ' + imageId);
252 target.addClass('overlayed');
253 // Query for the image metadata
254 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '"';
255 thatNode.one('#display').setContent('Loading ...');
256 Y.YQL(query, function(raw) {
257 if (!raw.query.results.photo) {
258 Y.log('No results found for photoId: ' + imageId);
259 return;
260 }
261 var props = raw.query.results.photo;
262 var snippet = '<ul style="list-style-type: square;">';
263 for (var key in props) {
264 if (typeof(props[key]) == 'object') {
265 continue;
266 }
267 snippet += '<li>' + key + ': ' + props[key] + '</li>';
268 }
269 snippet += '</ul>';
270 thatNode.one('#display').setContent(snippet);
271 });
272 }
273 };
274 ...
275 }
276 ...
277
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
278 Thus far, we've looked at the event handlers, but not the actual binding of the handlers to nodes.
279 At the end of the ``bind`` function, you'll see three important lines (shown below) that
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
280 bind the ``flipper`` and ``showOutlay`` functions to handle click and mouseover events.
281
282 .. code-block:: javascript
283
284 ...
285 bind: function(node) {
286 ...
287 // Bind all the image links to showOverlay
288 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
289 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
290 // Bind the prev + next links to flipper
291 thatNode.all('#nav a').on('click', flipper, this);
292 }
293 ...
294
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
295 After a little analysis, the full ``binders/index.js`` below should be easier to understand. The
296 binder attaches event handlers to nodes, invokes a function in the controller, and updates the
297 content in the template. The binder also has a couple of helper functions for parsing and requires
298 the IO and YQL modules, which are specified in the ``requires`` array.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
299
300 .. code-block:: javascript
301
302 YUI.add('PagerMojitBinder', function(Y, NAME) {
303 Y.namespace('mojito.binders')[NAME] = {
304 init: function(mojitProxy) {
305 this.mojitProxy = mojitProxy;
306 },
307 /**
308 * The binder method, invoked to allow the mojit
309 * to attach DOM event handlers.
310 * @param node {Node} The DOM node to which this
311 * mojit is attached.
312 */
313 bind: function(node) {
314 var thatNode = node;
315 Y.log('NODE: ' + Y.dump(this.node));
316 // define the action when user click on prev/next
317 var flipper = function(event) {
318 var target = event.target;
319 // get the link to the page
320 var page = parsePage(target.get('href'));
321 Y.log('PAGE: ' + page);
322 var updateDOM = function(markup) {
323 thatNode.set('innerHTML', markup);
324 thatNode.all('#nav a').on('click', flipper, this);
325 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
326 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
327 };
328 this.mojitProxy.invoke('index',
329 {
330 params: {page: page}
331 }, updateDOM
332 );
333 };
334 var showOverlay = function(event) {
335 var target = event.target;
336 var href = target.get('href');
337 var imageId = parseImageId(href);
338 if (target.hasClass('overlayed')) {
339 target.removeClass('overlayed');
340 thatNode.one('#display').setContent('');
341 } else {
342 Y.log('HREF: ' + href);
343 Y.log('IMAGE ID: ' + imageId);
344 target.addClass('overlayed');
345 // Query for the image metadata
346 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '"';
347 thatNode.one('#display').setContent('Loading ...');
348 Y.YQL(query, function(raw) {
349 if (!raw.query.results.photo) {
350 Y.log('No results found for photoId: ' + imageId);
351 return;
352 }
353 var props = raw.query.results.photo;
354 var snippet = '<ul style="list-style-type: square;">';
355 for (var key in props) {
356 if (typeof(props[key]) == 'object') {
357 continue;
358 }
359 snippet += '<li>' + key + ': ' + props[key] + '</li>';
360 }
361 snippet += '</ul>';
362 thatNode.one('#display').setContent(snippet);
363 });
364 }
365 };
366 // Bind all the image links to showOverlay
367 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
368 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
369 // Bind the prev + next links to flipper
370 thatNode.all('#nav a').on('click', flipper, this);
371 }
372 };
373 function parseImageId(link) {
374 var matches = link.match(/com\/(\d+)\/(\d+)_([0-9a-z]+)\.jpg$/);
375 return matches[2];
376 }
377 function parsePage(link) {
378 var matches = link.match(/page=(\d+)/);
379 return matches[1];
380 }
381 }, '0.0.1', {requires: ['mojito', 'yql', 'io', 'dump', 'mojito-client']});
382
383 Using Paging
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
384 ------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
385
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
386 The paging for this code example relies on the application configuration to set route paths and the
387 controller to create links to access previous and next pages.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
388
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
389 The ``routes.json`` file below configures two route paths for HTTP GET calls made on the root path.
390 The ``perpage`` configuration, however, requires a query string with the ``page`` parameter,
391 which is used for paging. The ``page`` parameter has the value ``:page``, which is a variable that
392 is assigned a value by the controller that we're going to look shortly.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
393
394 .. code-block:: javascript
395
396 [
397 {
398 "settings": ["master"],
399 "root": {
400 "verbs": ["get"],
401 "path": "/",
402 "call": "frame.index"
403 },
404 "perpage": {
405 "verbs": ["get"],
406 "path": "/?page=:page",
407 "call": "frame.index"
408 }
409 }
410 ]
411
412 The controller for ``PagerMojit`` performs several functions:
413
414 - uses the ``Params`` addon to get the ``page`` parameter from the query string
415 - calculates the index of the first photo on the page
416 - calls the ``getData`` function in the model to get photo data
417 - creates URLs for the **next** and **prev** links
418
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
419 The `Params addon <../../api/classes/Params.common.html>`_ allows you to access variables from the
420 query string parameters, the POST request bodies, or the routing systems URLs. In this code example,
421 you use the ``getFromMerged`` method, which merges the parameters from the query string, POST request
422 body, and the routing system URLs to give you access to all of the parameters. In the code snippet
423 taken from ``controller.server.js`` below, the ``getFromMerged`` method is used to get the value for
424 the ``page`` parameter and then calculate the index of the first photo to display:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
425
426 .. code-block:: javascript
427
428 ...
429 index: function(actionContext) {
430 var page = actionContext.params.getFromMerged('page');
431 var start;
432 page = parseInt(page) || 1;
433 if ((!page) || (page<1)) {
434 page = 1;
435 }
436 // Page param is 1 based, but the model is 0 based
437 start = (page - 1) * PAGE_SIZE;
438 ...
439 }
440 ...
441
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
442 To get the photo data, the controller depends on the model to call YQL to query the Flickr API.
443 Using ``actionContext.models.{model_name}`` lets you get a reference to the model.
444 In this example controller, the model of the ``PagerMojit`` is accessed through
445 ``actionContext.models.PageMojit``, allowing you to call ``getData`` and get the returned data from
446 YQL in the callback function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
447
448 .. code-block:: javascript
449
450 ...
451 index: function(actionContext) {
452 ...
453 var model = actionContext.models.PagerMojit;
454 // Data is an array of images
455 model.getData('mojito', start, PAGE_SIZE, function(data) {
456 Y.log('DATA: ' + Y.dump(data));
457 var theData = {
458 data: data, // images
459 hasLink: false,
460 prev: {
461 title: "prev" // opportunity to localize
462 },
463 next: {
464 link: createLink(actionContext, {page: page+1}),
465 title: "next"
466 },
467 query: 'mojito'
468 };
469 if (page > 1) {
470 theData.prev.link = createLink(actionContext, {page: page-1});
471 theData.hasLink = true;
472 }
473 actionContext.done(theData);
474 });
475 }
476 ...
477 };
478 ...
479
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
480 The URLs for the **prev** and **next** links are created by passing the mojit instance, the method,
481 and the query string parameters to the ``make`` method from the ``Url`` addon. The code snippet
482 below creates the query string parameters with the
483 `YUI QueryString module <http://yuilibrary.com/yui/docs/api/modules/querystring.html>`_. If the
484 query string created by ``Y.QueryString.stringify`` is "page=2" , ``actionContext.url.make`` would
485 return the URL ``{domain_name}:8666/?page=2``.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
486
487 .. code-block:: javascript
488
489 ...
490 function createLink(actionContext, params) {
491 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
492 for (var k in params) {
493 mergedParams[k] = params[k];
494 }
495 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
496 }
497 ...
498
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
499 Stitching the above code snippets together, we have the ``controller.server.js`` below. The
500 ``index`` function relies on the model for data and the ``createLink`` function to create URLs for
501 the **next** and **prev** links.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
502
503 .. code-block:: javascript
504
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
505 YUI.add('PagerMojit', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
506 /**
507 * The PagerMojit module.
508 * @module PagerMojit */
509 var PAGE_SIZE = 10;
510 /**
511 * Constructor for the Controller class.
512 * @class Controller
513 * @constructor
514 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
515 Y.namespace('mojito.controllers')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
516 init: function(config) {
517 this.config = config;
518 },
519 index: function(actionContext) {
520 var page = actionContext.params.getFromMerged('page');
521 var start;
522 page = parseInt(page) || 1;
523 if ((!page) || (page<1)) {
524 page = 1;
525 }
526 // Page param is 1 based, but the model is 0 based
527 start = (page - 1) * PAGE_SIZE;
528 var model = actionContext.models.PagerMojit;
529 // Data is an array of images
530 model.getData('mojito', start, PAGE_SIZE, function(data) {
531 Y.log('DATA: ' + Y.dump(data));
532 var theData = {
533 data: data, // images
534 hasLink: false,
535 prev: {
536 title: "prev" // opportunity to localize
537 },
538 next: {
539 link: createLink(actionContext, {page: page+1}),
540 title: "next"
541 },
542 query: 'mojito'
543 };
544 if (page > 1) {
545 theData.prev.link = createLink(actionContext, {page: page-1});
546 theData.hasLink = true;
547 }
548 actionContext.done(theData);
549 });
550 }
551 };
552 // generate the link to the next page based on:
553 // - mojit id
554 // - action
555 // - params
556 function createLink(actionContext, params) {
557 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
558 for (var k in params) {
559 mergedParams[k] = params[k];
560 }
561 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
562 }
563 }, '0.0.1', {requires: ['dump']});
564
565 Setting Up this Example
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
566 =======================
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
567
568 To set up and run ``binding_events``:
569
570 #. Create your application.
571
572 ``$ mojito create app binding_events``
573 #. Change to the application directory.
574 #. Create your mojit.
575
576 ``$ mojito create mojit PagerMojit``
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
577 #. To configure you application to run on the client and use ``HTMLFrameMojit``, replace the code in
578 ``application.json`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
579
580 .. code-block:: javascript
581
582 [
583 {
584 "settings": [ "master" ],
585 "specs": {
586 "frame": {
587 "type": "HTMLFrameMojit",
588 "config": {
589 "deploy": true,
590 "child": {
591 "type": "PagerMojit"
592 }
593 }
594 }
595 }
596 }
597 ]
598
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
599 #. To configure routing to call the ``index`` action from the instance of the ``HTMLFrameMojit``,
600 replace the code in ``routes.json`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
601
602 .. code-block:: javascript
603
604 [
605 {
606 "settings": ["master"],
607 "root": {
608 "verbs": ["get"],
609 "path": "/",
610 "call": "frame.index"
611 },
612 "perpage": {
613 "verbs": ["get"],
614 "path": "/?page=:page",
615 "call": "frame.index"
616 }
617 }
618 ]
619
620 #. Change to ``mojits/PageMojit``.
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
621 #. To have the controller get data from the model and create links for paging, replace the code in
622 ``controller.server.js``
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
623 with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
624
625 .. code-block:: javascript
626
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
627 YUI.add('PagerMojit', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
628 var PAGE_SIZE = 10;
629 /**
630 * Constructor for the Controller class.
631 * @class Controller
632 * @constructor
633 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
634 Y.namespace('mojito.controllers')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
635 init: function(config) {
636 this.config = config;
637 },
638 index: function(actionContext) {
639 var page = actionContext.params.getFromMerged('page');
640 var start;
641 page = parseInt(page) || 1;
642 if ((!page) || (page<1)) {
643 page = 1;
644 }
645 // Page param is 1 based, but the model is 0 based
646 start = (page - 1) * PAGE_SIZE;
647 var model = actionContext.models.PagerMojit;
648 // Data is an array of images
649 model.getData('mojito', start, PAGE_SIZE, function(data) {
650 Y.log('DATA: ' + Y.dump(data));
651 var theData = {
652 data: data, // images
653 hasLink: false,
654 prev: {
655 title: "prev" // opportunity to localize
656 },
657 next: {
658 link: createLink(actionContext, {page: page+1}),
659 title: "next"
660 },
661 query: 'mojito'
662 };
663 if (page > 1) {
664 theData.prev.link = createLink(actionContext, {page: page-1});
665 theData.hasLink = true;
666 }
667 actionContext.done(theData);
668 });
669 }
670 };
671 // Generate the link to the next page based on:
672 // - mojit id
673 // - action
674 // - params
675 function createLink(actionContext, params) {
676 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
677 for (var k in params) {
678 mergedParams[k] = params[k];
679 }
680 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
681 }
682 }, '0.0.1', {requires: ['dump']});
683
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
684 #. To get Flickr photo information using YQL, replace the code in ``model.server.js`` with the
685 following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
686
687 .. code-block:: javascript
688
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
689 YUI.add('PagerMojitModel', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
690 /**
691 * The PagerMojitModel module.
692 * @module PagerMojitModel
693 */
694 /**
695 * Constructor for the Model class.
696 * @class Model
697 * @constructor
698 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
699 Y.namespace('mojito.models')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
700 init: function(config) {
701 this.config = config;
702 },
703 getData: function(query, start, count, callback) {
704 var q = null;
705 // Get Flickr API key: http://www.flickr.com/services/api/keys/apply/
706 var API_KEY = "{your_api_key}";
707 start = parseInt(start) || 0;
708 count = parseInt(count) || 10;
709 q = 'select * from flickr.photos.search(' + start + ',' + count + ') where text="%' + query + '%" and api_key="' + API_KEY+'"';
710 Y.YQL(q, function(rawData) {
711 if (!rawData.query.results) {
712 callback([]);
713 return;
714 }
715 var rawImages = rawData.query.results.photo, rawImage = null,images = [], image = null, i = 0;
716 for (; i<rawImages.length; i++) {
717 rawImage = rawImages[i];
718 image = {
719 title: rawImage.title,
720 location: 'http://farm' + rawImage.farm + '.static.flickr.com/' + rawImage.server + '/' + rawImage.id + '_' + rawImage.secret + '.jpg',
721 farm: rawImage.farm,
722 server: rawImage.server,
723 image_id: rawImage.id,
724 secret: rawImage.secret
725 };
726 if (!image.title) {
727 image.title = "Generic Title: " + query;
728 }
729 images.push(image);
730 }
731 callback(images);
732 });
733 }
734 };
735 }, '0.0.1', {requires: ['yql']});
736
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
737 #. To create the binder for click events and invoke the ``index`` function of the controller,
738 replace the code in ``binders/index.js``
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
739 with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
740
741 .. code-block:: javascript
742
743 YUI.add('PagerMojitBinder', function(Y, NAME) {
744 /**
745 * The PagerMojitBinder module.
746 * @module PagerMojitBinder
747 */
748 /**
749 * Constructor for the Binder class.
750 *
751 * @param mojitProxy {Object} The proxy to allow
752 * the binder to interact with its owning mojit.
753 * @class Binder
754 * @constructor
755 */
756 Y.namespace('mojito.binders')[NAME] = {
757 /**
758 * Binder initialization method, invoked
759 * after all binders on the page have
760 * been constructed.
761 */
762 init: function(mojitProxy) {
763 this.mojitProxy = mojitProxy;
764 },
765 /**
766 * The binder method, invoked to allow the mojit
767 * to attach DOM event handlers.
768 * @param node {Node} The DOM node to which this
769 * mojit is attached.
770 */
771 bind: function(node) {
772 var thatNode = node;
773 Y.log('NODE: ' + Y.dump(this.node));
774 // define the action when user click on prev/next
775 var flipper = function(event) {
776 var target = event.target;
777 // get the link to the page
778 var page = parsePage(target.get('href'));
779 Y.log('PAGE: ' + page);
780 var updateDOM = function(markup) {
781 thatNode.set('innerHTML', markup);
782 thatNode.all('#nav a').on('click', flipper, this);
783 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
784 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
785 };
786 this.mojitProxy.invoke('index',
787 {
788 params: {page: page}
789 }, updateDOM
790 );
791 };
792 var showOverlay = function(event) {
793 var target = event.target;
794 var href = target.get('href');
795 var imageId = parseImageId(href);
796 if (target.hasClass('overlayed')) {
797 target.removeClass('overlayed');
798 thatNode.one('#display').setContent('');
799 } else {
800 Y.log('HREF: ' + href);
801 Y.log('IMAGE ID: ' + imageId);
802 target.addClass('overlayed');
803 // Query for the image metadata
804 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '"';
805 thatNode.one('#display').setContent('Loading ...');
806 Y.YQL(query, function(raw) {
807 if (!raw.query.results.photo) {
808 Y.log('No results found for photoId: ' + imageId);
809 return;
810 }
811 var props = raw.query.results.photo;
812 var snippet = '<ul style="list-style-type: square;">';
813 for (var key in props) {
814 if (typeof(props[key]) == 'object') {
815 continue;
816 }
817 snippet += '<li>' + key + ': ' + props[key] + '</li>';
818 }
819 snippet += '</ul>';
820 thatNode.one('#display').setContent(snippet);
821 });
822 }
823 };
824 // Bind all the image links to showOverlay
825 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
826 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
827 // Bind the prev + next links to flipper
828 thatNode.all('#nav a').on('click', flipper, this);
829 }
830 };
831 function parseImageId(link) {
832 var matches = link.match(/com\/(\d+)\/(\d+)_([0-9a-z]+)\.jpg$/);
833 return matches[2];
834 }
835 function parsePage(link) {
836 var matches = link.match(/page=(\d+)/);
837 return matches[1];
838 }
839 }, '0.0.1', {requires: ['yql', 'io', 'dump']});
840
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view tem...
zhouyaoji authored
841 #. To display links to photos and associated photo data in the rendered template, replace the code
842 in ``views/index.hb.html`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
843
844 .. code-block:: html
845
846 <div id="{{mojit_view_id}}" class="mojit" style="position: relative; width: 960px">
847 <h3>Query Term: {{query}}</h3>
848 <div id="nav" style="clear: both;">
849 {{#hasLink}}
850 {{#prev}}
851 <a href="{{{link}}}">{{title}}</a>
852 {{/prev}}
853 {{/hasLink}}
854 {{^hasLink}}
855 {{#prev}}{{title}}{{/prev}}
856 {{/hasLink}}
857 {{#next}}
858 <a href="{{{link}}}">{{title}}</a>
859 {{/next}}
860 </div>
861 <div id="master" style="width: 30%; float: left;">
862 <ul>
863 {{#data}}
864 <li><a href="{{location}}" data-id="{{image_id}}">{{title}}</a></li>
865 {{/data}}
866 </ul>
867 </div>
868 <div style="width: 50%; float: right">
869 <!-- load image here dynamically -->
870 <div id="display" style="margin: 0 auto;">
871 &nbsp;
872 </div>
873 </div>
874 </div>
875
876 #. From the application directory, run the server.
877
878 ``$ mojito start``
879 #. To view your application, go to the URL:
880
881 http://localhost:8666
882
883 Source Code
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax for ...
zhouyaoji authored
884 ===========
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
885
886 - `Application Configuration <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/application.json>`_
887 - `Mojit Binder <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/mojits/PagerMojit/binders/index.js>`_
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
888 - `Binding Events Application <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/>`_
Something went wrong with that request. Please try again.