понедельник, 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