понедельник, 12 ноября 2012 г.

ExtJS и сохранение паролей в браузере

В ExtJS значительно осложнена возможность восстановления работы механизма сохранения паролей в браузерах из-за того, что:

1) форма для ввода логина и пароля подставляется на страницу динамически,
2) форма формируется без тэга <form>,
3) в полях формы принудительно проставлен атрибут autocomplete="off".

По этим причинам необходимо:
1) в HTML-коде иметь статическую форму с полями ввода логина и пароля,
2) при динамическом формировании формы подставить в неё отсутствующий тэг <form>,
3) в полях формы принудительно изменить атрибут autocomplete c "off" на "on".

Применительно к исходному варианту эти изменения будут выглядеть так:

<!DOCTYPE html>
<html>
<head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
                <title>Форма авторизации</title>
                <link rel="stylesheet" type="text/css" href="http://somesite.com/static/js/ext-4.1.1a/resources/css/ext-all.css">
                <script type="text/javascript" src="http://somesite.com/static/js/ext-4.1.1a/ext-all-debug.js"></script>
                <script type="text/javascript">

                          // Изменяем в полях формы атрибут autocomplete c "off" на "on".
                               Ext.define('ACField', {
                                               extend: 'Ext.form.field.Text',
                              
                                               initComponent: function() {
                                                               Ext.each(this.fieldSubTpl, function(oneTpl, idx, allItems) {
                                                                              if (Ext.isString(oneTpl)) {
                                                                                              allItems[idx] = oneTpl.replace('autocomplete="off"', 'autocomplete="on"');
                                                                              }
                                                               });
                                                               this.callParent(arguments);
                                               }
                               });

                               Ext.application({
                                               requires : [ 'Ext.window.Window' ],
                                               name : 'Login',
                              
                                               launch : function() {
                                                               Ext.create('Ext.window.Window', {
                                                                              title : 'Hello',
                                                                              autoShow : true,
                                                                              closable : false,
                                                                              items : [ {
                                                                                              xtype : 'form',
                                                                                              border : 0,
                                                                                              bodyPadding : 8,
                                                                                              width: 260, // Устанавливаем ширину формы. Иначе будет искажение.
                                                                                              autoEl: {
                                                                                                              tag: 'form' // Восстанавливаем тэг <form>
                                                                                              },
                                                                                              items : [
                                                                                                              Ext.create('ACField',{
                                                                                                                             xtype : 'textfield',
                                                                                                                             name : 'login',
                                                                                                                             fieldLabel : 'Login',
                                                                                                                             inputId: 'login',  // Связываем поле статической и динамической формы.
                                                                                                                             anchor: '100%'   // Устанавливаем ширину поля ввода формы. Иначе будет искажение.
                                                                                                              }),
                                                                                                              Ext.create('ACField',{
                                                                                                                             xtype : 'textfield',
                                                                                                                             name : 'password',
                                                                                                                             fieldLabel : 'Password',
                                                                                                                             inputType : 'password',
                                                                                                                             inputId: 'password',  // Связываем поле статической и динамической формы.
                                                                                                                             anchor: '100%'          // Устанавливаем ширину поля ввода формы. Иначе будет искажение.
                                                                                                              })
                                                                                              ],
                                                                                              buttons : [ {
                                                                                                              text : 'Login',
                                                                                                              handler : function() {
                                                                                                                             this.up('form').getForm().submit({
                                                                                                                                             method: 'POST',
                                                                                                                                             standardSubmit : true
                                                                                                                             });
                                                                                                              }
                                                                                              } ]
                                                                              } ]
                                                               });
                                               }
                               });

                </script>
</head>
<body>

<!-- Статическая форма.  -->
    <form method="post">
        <input class="x-hidden" type="text" id="login" name="login" />
        <input class="x-hidden" type="password" id="password" name="password" />
    </form>

</body>
</html>


За основу я взял данный пример:

<!DOCTYPE html>
<html>
<head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
                <title>Форма авторизации</title>
                <link rel="stylesheet" type="text/css" href="http://finprojects.rbc.ru/static/js/ext-4.1.1a/resources/css/ext-all.css">
                <script type="text/javascript" src="http://finprojects.rbc.ru/static/js/ext-4.1.1a/ext-all-debug.js"></script>
                <script type="text/javascript">
               
                               Ext.define('ACField', {
                                               extend: 'Ext.form.field.Text',
                              
                                               initComponent: function() {
                                                               Ext.each(this.fieldSubTpl, function(oneTpl, idx, allItems) {
                                                                              if (Ext.isString(oneTpl)) {
                                                                                              allItems[idx] = oneTpl.replace('autocomplete="off"', 'autocomplete="on"');
                                                                              }
                                                               });
                                                               this.callParent(arguments);
                                               }
                               });
                              
                               Ext.onReady(function() {
                                               new Ext.panel.Panel({
                                                               renderTo: Ext.getBody(),
                                                               width: 300,
                                                               height: 100,
                                                               autoEl: {
                                                                              tag: 'form',
                                                                              action: '/j_spring_security_check',
                                                                              method: 'post'
                                                               }, 
                                                               items:[
                                                                              Ext.create('ACField',{
                                                                                              fieldLabel: 'Username',
                                                                                              name:'j_username',
                                                                                              inputId: 'username',
                                                                                              allowBlank:false,
                                                                                              selectOnFocus:true
                                                                              }),
                                                                              Ext.create('ACField',{
                                                                                              fieldLabel:'Password',
                                                                                              name:'j_password',
                                                                                              inputId: 'password',
                                                                                              xtype:'textfield',
                                                                                              allowBlank:false,
                                                                                              inputType:'password'
                                                                              })
                                                               ],
                                                               buttons: [{
                                                                              xtype: 'button',
                                                                              text: 'Log in',
                                                                              type: 'submit',
                                                                              preventDefault: false
                                                               }]
                                               });
                               });
               
                </script>
</head>
<body>
<div id="login-panel">
    <form id="loginForm" method="post" action="/j_spring_security_check">
        <input class="x-hidden" type="text" id="username" name="j_username" />
        <input class="x-hidden" type="password" id="password" name="j_password" />
    </form>
</div>
</body>
</html>


Однако, даже подобные поправки на практике сработают не во всех браузерах.

Подробнее об этом можно прочитать в обсуждениях данной темы, перейдя по этим ссылкам:

http://www.sencha.com/forum/showthread.php?60807-Remember-password-in-browser
http://www.sencha.com/forum/showthread.php?6450-Saved-user-credentials-and-dynamic-forms-possible
http://stackoverflow.com/questions/2620927/how-to-trigger-saved-password-autofill-in-browsers
http://stackoverflow.com/questions/11965919/browser-does-not-remember-password-during-login
http://stackoverflow.com/questions/6532757/ajax-login-forms-working-with-browser-password-remember-features
http://stackoverflow.com/questions/2944322/extjs-login-with-remember-me-functionality
http://www.howtogeek.com/62980/how-to-force-your-browser-to-remember-passwords/
http://forums.ext.net/showthread.php?11919-CLOSED-Remember-User-name-and-Password

вторник, 9 октября 2012 г.

Sencha Touch

Sencha Touch - это HTML 5 фреймворк, созданный специально для мобильных устройств. Он может использоваться разработчиками для создания пользовательских интерфейсов для мобильных приложений, которые будут выглядеть как нативные приложения. Sencha Touch полностью базируется на стандартах HTML 5, CSS 3 и JavaScript. Основной целью применения данного фреймворка является быстрое создание мобильных приложений для устройств, использующих операционные системы Android, iOS, Blackberry и Kindle Fire. Будучи JavaScript-фреймворком Sencha Touch состоит из UI-виджетов и Data-библиотек. Используя Data-библиотеки ваше приложение может получать данные с сервера, используя AJAX-запросы и JSONP.

ExtJS Каркас

// Вкладки и каркас

var tabpanel = Ext.create('Ext.tab.Panel', {
    items: [
        {
            title: 'Отчеты',
            layout: 'border',
            items: [
                {
                    xtype: 'panel',
                    region: 'north',
                    border: false,
                    items: [toolbar]
                },
                {
                    xtype: 'panel',
                    region: 'center',
                    layout: 'border',
                    width: '50%',
                    border: false,
                    items: [
                        {
                            xtype: 'panel',
                            region: 'center',
                            layout: 'fit',
                            items: [user_table]
                        },
                        {
                            xtype: 'panel',
                            region: 'south',
                            bodyStyle: 'background-color: #dfe8f5;',
                            split: true,
                            items: [user_data_form]
                        }
                    ]
                },
                {
                    xtype: 'panel',
                    region: 'east',
                    layout: 'border',
                    width: '50%',
                    border: false,
                    split: true,
                    items: [
                        {
                            xtype: 'panel',
                            region: 'center',
                            layout: 'fit',
                            items: [comments_table]
                        },
                        {
                            xtype: 'panel',
                            region: 'south',
                            bodyStyle: 'background-color: #dfe8f5;',
                            split: true,
                            items: [comment_data_form]
                        }
                    ]
                }
            ]
        },
        {
            title: 'Демонстрационная вкладка',
            html: 'Просто демонстрационный текст.'
        }
    ]
});

Ext.onReady(function(){
                   
    Ext.QuickTips.init();

    Ext.create('Ext.Viewport', {
        layout:'fit',
        items: [tabpanel]
    });

});