Skip to content

HTTPS clone URL

Subversion checkout URL

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