📜 ⬆️ ⬇️

Using URI-Fragment Addressing in RIA Applications Based on ExtJS and Mootools

URI-fragments (they are fragment identifiers, hash, bookmarks, anchors) have recently become actively used in interactive web applications as a convenient means for specifying direct links to various interface elements and application status. The most striking example of the use of fragment-addressing is GMail. As you may have noticed, the Inbox, Sent, Drafts folders have links ending in #inbox, #sent, #drafts. Switching between them does not reload the entire page (only the list of letters is updated), but at the same time, when opening each of them in a separate window / tab, we immediately get to the page you are looking for.

This article is dedicated to the implementation of such a convenient navigation mechanism using JavaScript.

As it was…

')
In classical HTML, URI fragments were used to create simplest navigation inside a large document. In the right places of the document, it was possible to insert tags of the form (so-called anchor) and refer to them using the links of the form Go Here. When clicking on such a link, the browser scrolled the document to the right place, without reloading the page. It was also possible to open the site.com/path/to/doc.html#go-here link in a new window, and after loading the document the browser automatically displayed it from the position of the anchor. Naturally, anchors worked only in those browsers that supported this feature, because processing of fragments entirely and completely shifted to the client side. URI fragments were not even transmitted (and are not transmitted now) to the web server.

... and now


As you can see, the fragments have two important advantages:


Today, in the era of the victorious march of DHTML and AJAX technologies, fragments have gained new life thanks to these two remarkable properties. URI-Fragment addressing allows you to build RIA applications that work entirely on AJAX, without reloading the page, while at the same time preserving some of the usual features of ordinary web applications that we are used to. Namely, the preservation of a certain state (open letter / photo / document) in a link, the transfer of this link to another user, who, having opened it, will see the same thing as you.

A practical example.


One of my clients ordered a photo gallery for his site in the form of a Javascript slideshow. Switching between photos should not cause a page reload, but at the same time, he asked for the opportunity to copy and send someone a link to a specific photo. This problem was quite easily solved by me using fragment-addressing.

Links to photos were site.com/gallery/name-of-gallery/#photo_id , where photo_id is the image code. The Forward-Back buttons as well as the thumbnails in the carousel were the usual links to snippets with the codes of the corresponding photos. The slideshow component and the carousel from the miniature intercepted the URI fragment change event and reacted accordingly (the slideshow showed the desired photo, and the carousel scrolled to it and highlighted it with a frame). Also, immediately after creation, each of these components checked the current fragment and made the transition to the photo.

image

This principle of the organization of the application is very convenient. Its components do not need to "cling" to event handlers for each other to track state changes. It is enough for everyone to immediately follow the changes in the URI fragment and perform the necessary actions. Instead of a system with many “many to many connections”, we get a system with centralized control, which is much easier to develop and debug.

In extjs


The ExtJS framework provides a convenient Ext.History singleton for working with fragment-addressing. Before you start using it, you must


Below is a sample code:
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  1. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  2. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  3. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  4. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  5. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  6. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  7. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  8. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  9. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  10. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  11. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  12. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  13. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  14. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  15. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  16. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  17. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  18. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
  19. Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .
Ext.getBody().createChild({ tag: 'form' , action: '#' , cls: 'x-hidden' , id: 'history-form' , children: [{ tag: 'div' , children: [{ tag: 'input' , id: Ext.History.fieldId, type: 'hidden' }, { tag: 'iframe' , id: Ext.History.iframeId }] }] }); Ext.History.init(); * This source code was highlighted with Source Code Highlighter .


Detailed documentation on the singleton can be found at http://www.extjs.com/deploy/dev/docs/?class=Ext.History . I will give a description of the most frequently used features. In the terminology of Ext.History, fragments are called tokens:



Example of use:

  1. < script type = ” text / javascript ” >
  2. Ext.onReady ( function () {
  3. <ExtHistory initialization (see code above)>
  4. var showToken = function (token) {
  5. if (Ext.isString (token) && token! = '' ) Ext.Msg.alert ( 'Token changed' , String.format ( 'New token: {0}' , token));
  6. },
  7. t = Ext.History.getToken ();
  8. Ext.History.on ( 'change' , showToken);
  9. Ext.get ( 'settoken4' ) .on ( 'click' , Ext.History.add.createDelegate (Ext.History, [ 'token4' ], false ));
  10. showToken (t);
  11. });
  12. </ script >
  13. <a href = "# token1"> token 1 </ a > | <a href = "# token2"> token 2 </ a > | <a href = "# token3"> token 3 </ a >
  14. < input type = "button" value = "Set Token 4" id = "settoken4" />
* This source code was highlighted with Source Code Highlighter .


The official demo can be viewed at the link.

http://www.extjs.com/deploy/dev/examples/history/history.html

and the example of the code shown here is here . You can also download the source code of the example ( alternative link without ExtJS distribution).

In motools


In the standard delivery of MooTools, there was no class for working with fragment-addressing, I did not find any plug-ins and decided to use Ext.History’s singleton. It took quite a bit of time to adapt it under MooTools. I also added a little singleton - I integrated the creation of the help form into the init () method and initialize the singleton automatically when the js file is connected

Mootolls Singleton I called the HistoryManager. Methods and events are completely identical to Ext.History methods and events.

Example of use:
  1. < script type = "text / javascript" >
  2. window.addEvent ( 'domready' , function () {
  3. var showToken = function (token) {
  4. if ($ type (token) == 'string' && token! = '' ) alert ( 'New token: {t}' .substitute ({t: token}));
  5. },
  6. t = HistoryManager.getToken ();
  7. HistoryManager.addEvent ( 'change' , showToken);
  8. $ ( 'settoken4' ) .addEvent ( 'click' , HistoryManager.add.bind (HistoryManager, [ 'token4' ]));
  9. showToken (t);
  10. });
  11. </ script >
  12. </ head >
  13. < body >
  14. <a href = "# token1"> token 1 </ a > | <a href = "# token2"> token 2 </ a > | <a href = "# token3"> token 3 </ a >
  15. < input type = "button" value = "Set Token 4" id = "settoken4" />
* This source code was highlighted with Source Code Highlighter .


An example of the code shown here can be viewed here , photo gallery demo - here . You can also download the source code of the sample ( an alternative link without ExtJS distribution) and a photo gallery .

PS If you need to translate Ext.History to Prototype or jQuery - contact, help.

UPD: Thanks for the karma, moved to JavaScript

Source: https://habr.com/ru/post/88213/


All Articles