Removed: KnockoutJS 'hasFocus:' because HTML5 has autofocus=""

Knoin.js now searches for [autofocus] and handles it
This commit is contained in:
djmaze 2020-08-22 01:03:03 +02:00
parent 226f77e392
commit 996723a486
18 changed files with 60 additions and 113 deletions

View file

@ -51,4 +51,9 @@ export class AbstractViewNext {
cancelCommand() {} // eslint-disable-line no-empty-function cancelCommand() {} // eslint-disable-line no-empty-function
closeCommand() {} // eslint-disable-line no-empty-function closeCommand() {} // eslint-disable-line no-empty-function
querySelector(selectors) {
return this.viewModelDom[0].querySelector(selectors);
}
} }

View file

@ -246,6 +246,9 @@ export function showScreenPopup(ViewModelClassToShow, params = []) {
ModalView.__vm.onShow && ModalView.__vm.onShow(...params); ModalView.__vm.onShow && ModalView.__vm.onShow(...params);
const af = ModalView.__dom[0].querySelector('[autofocus]');
af && af.focus();
vmRunHook('view-model-on-show', ModalView, params || []); vmRunHook('view-model-on-show', ModalView, params || []);
} }
} }
@ -374,6 +377,9 @@ export function screenOnRoute(screenName, subPart) {
ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger()); ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger());
} }
const af = ViewModelClass.__dom[0].querySelector('[autofocus]');
af && af.focus();
ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200); ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200);
vmRunHook('view-model-on-show', ViewModelClass); vmRunHook('view-model-on-show', ViewModelClass);

View file

@ -75,6 +75,9 @@
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
} }
.inputEmail, .inputPassword {
padding-right: 35px;
}
} }
.languageLabel { .languageLabel {

View file

@ -37,7 +37,7 @@ class LoginAdminView extends AbstractViewNext {
this.loginErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 }); this.loginErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
this.passwordErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 }); this.passwordErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
this.loginFocus = ko.observable(false); // this.loginFocus = ko.observable(false);
this.formHidden = ko.observable(false); this.formHidden = ko.observable(false);
@ -96,14 +96,9 @@ class LoginAdminView extends AbstractViewNext {
onShow() { onShow() {
routeOff(); routeOff();
setTimeout(() => {
this.loginFocus(true);
}, 100);
} }
onHide() { onHide() {
this.loginFocus(false);
} }
onBuild() { onBuild() {

View file

@ -16,7 +16,6 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
super(); super();
this.key = ko.observable(''); this.key = ko.observable('');
this.key.focus = ko.observable(false);
this.key.error = ko.observable(false); this.key.error = ko.observable(false);
this.key.errorMessage = ko.observable(''); this.key.errorMessage = ko.observable('');
@ -95,10 +94,6 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
onShow() { onShow() {
this.clearPopup(); this.clearPopup();
} }
onShowWithDelay() {
this.key.focus(true);
}
} }
export { AddOpenPgpKeyPopupView, AddOpenPgpKeyPopupView as default }; export { AddOpenPgpKeyPopupView, AddOpenPgpKeyPopupView as default };

View file

@ -18,9 +18,6 @@ class AskPopupView extends AbstractViewNext {
this.yesButton = ko.observable(''); this.yesButton = ko.observable('');
this.noButton = ko.observable(''); this.noButton = ko.observable('');
this.yesFocus = ko.observable(false);
this.noFocus = ko.observable(false);
this.fYesAction = null; this.fYesAction = null;
this.fNoAction = null; this.fNoAction = null;
@ -34,9 +31,6 @@ class AskPopupView extends AbstractViewNext {
this.yesButton(i18n('POPUPS_ASK/BUTTON_YES')); this.yesButton(i18n('POPUPS_ASK/BUTTON_YES'));
this.noButton(i18n('POPUPS_ASK/BUTTON_NO')); this.noButton(i18n('POPUPS_ASK/BUTTON_NO'));
this.yesFocus(false);
this.noFocus(false);
this.fYesAction = null; this.fYesAction = null;
this.fNoAction = null; this.fNoAction = null;
} }
@ -87,17 +81,17 @@ class AskPopupView extends AbstractViewNext {
onShowWithDelay() { onShowWithDelay() {
if (this.bFocusYesOnShow) { if (this.bFocusYesOnShow) {
this.yesFocus(true); this.querySelector('.buttonYes').focus();
} }
} }
onBuild() { onBuild() {
key('tab, shift+tab, right, left', KeyState.PopupAsk, () => { key('tab, shift+tab, right, left', KeyState.PopupAsk, () => {
if (this.yesFocus()) { let btn = this.querySelector('.buttonYes');
this.noFocus(true); if (btn.matches(':focus')) {
} else { btn = this.querySelector('.buttonNo');
this.yesFocus(true);
} }
btn.focus();
return false; return false;
}); });

View file

@ -61,7 +61,6 @@ class DomainPopupView extends AbstractViewNext {
this.smtpServerFocus = ko.observable(false); this.smtpServerFocus = ko.observable(false);
this.name = ko.observable(''); this.name = ko.observable('');
this.name.focused = ko.observable(false);
this.imapServer = ko.observable(''); this.imapServer = ko.observable('');
this.imapPort = ko.observable('' + IMAP_DEFAULT_PORT); this.imapPort = ko.observable('' + IMAP_DEFAULT_PORT);
@ -379,12 +378,6 @@ class DomainPopupView extends AbstractViewNext {
} }
} }
onShowWithDelay() {
if (!this.name() && !bMobileDevice) {
this.name.focused(true);
}
}
clearForm() { clearForm() {
this.edit(false); this.edit(false);
@ -396,7 +389,6 @@ class DomainPopupView extends AbstractViewNext {
this.savingError(''); this.savingError('');
this.name(''); this.name('');
this.name.focused(false);
this.imapServer(''); this.imapServer('');
this.imapPort('' + IMAP_DEFAULT_PORT); this.imapPort('' + IMAP_DEFAULT_PORT);

View file

@ -25,7 +25,6 @@ class DomainAliasPopupView extends AbstractViewNext {
this.savingError = ko.observable(''); this.savingError = ko.observable('');
this.name = ko.observable(''); this.name = ko.observable('');
this.name.focused = ko.observable(false);
this.alias = ko.observable(''); this.alias = ko.observable('');
@ -64,18 +63,11 @@ class DomainAliasPopupView extends AbstractViewNext {
this.clearForm(); this.clearForm();
} }
onShowWithDelay() {
if (!this.name() && !bMobileDevice) {
this.name.focused(true);
}
}
clearForm() { clearForm() {
this.saving(false); this.saving(false);
this.savingError(''); this.savingError('');
this.name(''); this.name('');
this.name.focused(false);
this.alias(''); this.alias('');
} }

View file

@ -27,7 +27,6 @@ class IdentityPopupView extends AbstractViewNext {
this.email = ko.observable('').validateEmail(); this.email = ko.observable('').validateEmail();
this.email.focused = ko.observable(false); this.email.focused = ko.observable(false);
this.name = ko.observable(''); this.name = ko.observable('');
this.name.focused = ko.observable(false);
this.replyTo = ko.observable('').validateSimpleEmail(); this.replyTo = ko.observable('').validateSimpleEmail();
this.replyTo.focused = ko.observable(false); this.replyTo.focused = ko.observable(false);
this.bcc = ko.observable('').validateSimpleEmail(); this.bcc = ko.observable('').validateSimpleEmail();

View file

@ -14,13 +14,10 @@ class WelcomePagePopupView extends AbstractViewNext {
super(); super();
this.welcomePageURL = ko.observable(''); this.welcomePageURL = ko.observable('');
this.closeFocused = ko.observable(false);
} }
clearPopup() { clearPopup() {
this.welcomePageURL(''); this.welcomePageURL('');
this.closeFocused(false);
} }
/** /**
@ -33,10 +30,6 @@ class WelcomePagePopupView extends AbstractViewNext {
this.welcomePageURL(sUrl); this.welcomePageURL(sUrl);
} }
onShowWithDelay() {
this.closeFocused(true);
}
onHide() { onHide() {
Promises.welcomeClose(); Promises.welcomeClose();
} }

View file

@ -47,7 +47,6 @@ class LoginUserView extends AbstractViewNext {
this.additionalCode = ko.observable(''); this.additionalCode = ko.observable('');
this.additionalCode.error = ko.observable(false); this.additionalCode.error = ko.observable(false);
this.additionalCode.errorAnimation = ko.observable(false).extend({ falseTimeout: 500 }); this.additionalCode.errorAnimation = ko.observable(false).extend({ falseTimeout: 500 });
this.additionalCode.focused = ko.observable(false);
this.additionalCode.visibility = ko.observable(false); this.additionalCode.visibility = ko.observable(false);
this.additionalCodeSignMe = ko.observable(false); this.additionalCodeSignMe = ko.observable(false);
@ -75,8 +74,8 @@ class LoginUserView extends AbstractViewNext {
(this.additionalCode.visibility() && this.additionalCode.errorAnimation()) (this.additionalCode.visibility() && this.additionalCode.errorAnimation())
); );
this.emailFocus = ko.observable(false); // this.emailFocus = ko.observable(false);
this.passwordFocus = ko.observable(false); // this.passwordFocus = ko.observable(false);
this.email.subscribe(() => { this.email.subscribe(() => {
this.emailError(false); this.emailError(false);
@ -152,32 +151,24 @@ class LoginUserView extends AbstractViewNext {
this.emailError(false); this.emailError(false);
this.passwordError(false); this.passwordError(false);
this.emailError(!this.email().trim()); let error;
this.passwordError(!this.password().trim());
if (this.additionalCode.visibility()) { if (this.additionalCode.visibility()) {
this.additionalCode.error(false); this.additionalCode.error(false);
this.additionalCode.error(!this.additionalCode().trim()); if (!this.additionalCode().trim()) {
this.additionalCode.error(true);
error = '.inputAdditionalCode';
} }
if (
this.emailError() ||
this.passwordError() ||
(this.additionalCode.visibility() && this.additionalCode.error())
) {
switch (true) {
case this.emailError():
this.emailFocus(true);
break;
case this.passwordError():
this.passwordFocus(true);
break;
case this.additionalCode.visibility() && this.additionalCode.error():
this.additionalCode.focused(true);
break;
// no default
} }
if (!this.password().trim()) {
this.passwordError(true);
error = '#RainLoopPassword';
}
if (!this.email().trim()) {
this.emailError(true);
error = '#RainLoopEmail';
}
if (error) {
this.querySelector(error).focus();
return false; return false;
} }
@ -210,7 +201,7 @@ class LoginUserView extends AbstractViewNext {
this.additionalCode.visibility(true); this.additionalCode.visibility(true);
this.submitRequest(false); this.submitRequest(false);
setTimeout(() => this.additionalCode.focused(true), 100); setTimeout(() => this.querySelector('.inputAdditionalCode').focus(), 100);
} else if (oData.Admin) { } else if (oData.Admin) {
getApp().redirectToAdminPanel(); getApp().redirectToAdminPanel();
} else { } else {
@ -262,23 +253,6 @@ class LoginUserView extends AbstractViewNext {
routeOff(); routeOff();
} }
onShowWithDelay() {
if (this.email() && this.password()) {
this.passwordFocus(true);
} else if (!this.email()) {
this.emailFocus(true);
} else if (!this.password()) {
this.passwordFocus(true);
} else {
this.emailFocus(true);
}
}
onHide() {
this.emailFocus(false);
this.passwordFocus(false);
}
onBuild() { onBuild() {
const signMeLocal = Local.get(ClientSideKeyName.LastSignMe), const signMeLocal = Local.get(ClientSideKeyName.LastSignMe),
signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(); signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase();
@ -339,9 +313,7 @@ class LoginUserView extends AbstractViewNext {
selectLanguageOnTab(bShift) { selectLanguageOnTab(bShift) {
if (!bShift) { if (!bShift) {
setTimeout(() => { // setTimeout(() => this.emailFocus(true), 50);
this.emailFocus(true);
}, 50);
return false; return false;
} }

View file

@ -11,9 +11,9 @@
<div class="input-append"> <div class="input-append">
<input type="text" class="input-block-level inputLogin checkAutocomplete" <input type="text" class="input-block-level inputLogin checkAutocomplete"
name="RainLoopAdminLogin" id="RainLoopAdminLogin" name="RainLoopAdminLogin" id="RainLoopAdminLogin"
style="padding-right: 35px;" autofocus=""
autocomplete="username" autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_LOGIN" autocomplete="username" autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_LOGIN"
data-bind="textInput: login, hasFocus: loginFocus, disable: submitRequest" /> data-bind="textInput: login, disable: submitRequest" />
<span class="add-on"> <span class="add-on">
<i class="icon-user"></i> <i class="icon-user"></i>
</span> </span>
@ -23,7 +23,6 @@
<div class="input-append"> <div class="input-append">
<input type="password" class="input-block-level inputPassword checkAutocomplete" <input type="password" class="input-block-level inputPassword checkAutocomplete"
placeholder="Password" name="RainLoopAdminPassword" id="RainLoopAdminPassword" placeholder="Password" name="RainLoopAdminPassword" id="RainLoopAdminPassword"
style="padding-right: 35px;"
autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_PASSWORD" autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_PASSWORD"
data-bind="textInput: password, disable: submitRequest" /> data-bind="textInput: password, disable: submitRequest" />
<span class="add-on" tabindex="-1" data-tooltip-join="left" data-bind="command: submitCommand, tooltip: 'LOGIN/BUTTON_LOGIN'"> <span class="add-on" tabindex="-1" data-tooltip-join="left" data-bind="command: submitCommand, tooltip: 'LOGIN/BUTTON_LOGIN'">
@ -45,3 +44,4 @@
</div> </div>
<div class="loginAfter"></div> <div class="loginAfter"></div>
<div> <div>

View file

@ -13,8 +13,8 @@
&nbsp; &nbsp;
<span style="color: #aaa">(<span data-i18n="POPUPS_DOMAIN/NAME_HELPER"></span>)</span> <span style="color: #aaa">(<span data-i18n="POPUPS_DOMAIN/NAME_HELPER"></span>)</span>
<br /> <br />
<input type="text" class="span4" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" <input type="text" class="span4" autofocus="" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: name, hasfocus: name.focused" /> data-bind="textInput: name" />
<div data-bind="visible: '' !== savingError()"> <div data-bind="visible: '' !== savingError()">
<span class="error-desc" data-bind="text: savingError"></span> <span class="error-desc" data-bind="text: savingError"></span>
</div> </div>

View file

@ -10,12 +10,12 @@
<br /> <br />
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn buttonYes" data-bind="click: yesClick, hasFocus: yesFocus"> <button class="btn buttonYes" data-bind="click: yesClick">
<i class="icon-ok"></i> <i class="icon-ok"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span data-bind="text: yesButton"></span> <span data-bind="text: yesButton"></span>
</button> </button>
<button class="btn buttonNo" data-bind="click: noClick, hasFocus: noFocus"> <button class="btn buttonNo" data-bind="click: noClick">
<i class=" icon-remove"></i> <i class=" icon-remove"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span data-bind="text: noButton"></span> <span data-bind="text: noButton"></span>

View file

@ -11,7 +11,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn" data-bind="command: cancelCommand, hasFocus: closeFocused"> <button class="btn" autofocus="" data-bind="command: cancelCommand">
<i class="icon-remove"></i> <i class="icon-remove"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n" data-i18n="POPUPS_WELCOME_PAGE/BUTTON_CLOSE"></span> <span class="i18n" data-i18n="POPUPS_WELCOME_PAGE/BUTTON_CLOSE"></span>

View file

@ -32,9 +32,10 @@
data-bind="css: {'error': emailError, 'animated': emailErrorAnimation}"> data-bind="css: {'error': emailError, 'animated': emailErrorAnimation}">
<div class="input-append"> <div class="input-append">
<input type="email" class="i18n input-block-level inputEmail checkAutocomplete" <input type="email" class="i18n input-block-level inputEmail checkAutocomplete"
name="RainLoopEmail" id="RainLoopEmail" style="padding-right: 35px;" autocomplete="email" name="RainLoopEmail" id="RainLoopEmail"
autocorrect="off" autocapitalize="off" spellcheck="false" autofocus=""
data-bind="textInput: email, hasFocus: emailFocus, disable: submitRequest" autocomplete="email" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: email, disable: submitRequest"
data-i18n="[placeholder]LOGIN/LABEL_EMAIL" /> data-i18n="[placeholder]LOGIN/LABEL_EMAIL" />
<span class="add-on"> <span class="add-on">
<i class="icon-mail"></i> <i class="icon-mail"></i>
@ -44,9 +45,9 @@
<div class="controls" data-bind="css: {'error': passwordError, 'animated': passwordErrorAnimation}"> <div class="controls" data-bind="css: {'error': passwordError, 'animated': passwordErrorAnimation}">
<div class="input-append"> <div class="input-append">
<input type="password" class="i18n input-block-level inputPassword checkAutocomplete" <input type="password" class="i18n input-block-level inputPassword checkAutocomplete"
name="RainLoopPassword" id="RainLoopPassword" style="padding-right: 35px;" name="RainLoopPassword" id="RainLoopPassword"
autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false" autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: password, hasFocus: passwordFocus, disable: submitRequest" data-bind="textInput: password, disable: submitRequest"
data-i18n="[placeholder]LOGIN/LABEL_PASSWORD" /> data-i18n="[placeholder]LOGIN/LABEL_PASSWORD" />
<span class="add-on" tabindex="-1" data-tooltip-join="left" <span class="add-on" tabindex="-1" data-tooltip-join="left"
data-bind="command: submitCommand, tooltip: 'LOGIN/BUTTON_SIGN_IN'"> data-bind="command: submitCommand, tooltip: 'LOGIN/BUTTON_SIGN_IN'">
@ -62,7 +63,7 @@
<div class="input-append"> <div class="input-append">
<input type="text" class="i18n input-block-level inputAdditionalCode" autocomplete="off" <input type="text" class="i18n input-block-level inputAdditionalCode" autocomplete="off"
autocorrect="off" autocapitalize="off" spellcheck="false" style="padding-right: 35px;" autocorrect="off" autocapitalize="off" spellcheck="false" style="padding-right: 35px;"
data-bind="textInput: additionalCode, hasFocus: additionalCode.focused, disable: submitRequest" data-bind="textInput: additionalCode, disable: submitRequest"
data-i18n="[placeholder]LOGIN/LABEL_VERIFICATION_CODE" /> data-i18n="[placeholder]LOGIN/LABEL_VERIFICATION_CODE" />
<span class="add-on"> <span class="add-on">
<i class="icon-key"></i> <i class="icon-key"></i>

View file

@ -11,7 +11,7 @@
<div class="alert" data-bind="visible: key.error() && key.errorMessage(), text: key.errorMessage"></div> <div class="alert" data-bind="visible: key.error() && key.errorMessage(), text: key.errorMessage"></div>
<div class="form-horizontal"> <div class="form-horizontal">
<div class="control-group" data-bind="css: {'error': key.error}"> <div class="control-group" data-bind="css: {'error': key.error}">
<textarea class="inputKey input-xxlarge" rows="14" autocomplete="off" data-bind="value: key, hasfocus: key.focus"></textarea> <textarea class="inputKey input-xxlarge" rows="14" autofocus="" autocomplete="off" data-bind="value: key"></textarea>
</div> </div>
</div> </div>
</div> </div>

View file

@ -18,7 +18,7 @@
<div class="control-group" data-bind="visible: !owner(), css: {'error': email.hasError}"> <div class="control-group" data-bind="visible: !owner(), css: {'error': email.hasError}">
<label class="i18n control-label" data-i18n="POPUPS_IDENTITY/LABEL_EMAIL"></label> <label class="i18n control-label" data-i18n="POPUPS_IDENTITY/LABEL_EMAIL"></label>
<div class="controls"> <div class="controls">
<input type="email" class="inputEmail input-xlarge" <input type="email" class="inputEmail input-xlarge" autofocus=""
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: email, onEnter: addOrEditIdentityCommand, hasfocus: email.focused" /> data-bind="value: email, onEnter: addOrEditIdentityCommand, hasfocus: email.focused" />
</div> </div>
@ -34,7 +34,7 @@
<div class="controls"> <div class="controls">
<input type="text" class="inputName input-xlarge" <input type="text" class="inputName input-xlarge"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: name, onEnter: addOrEditIdentityCommand, hasfocus: name.focused" /> data-bind="value: name, onEnter: addOrEditIdentityCommand" />
</div> </div>
</div> </div>
<div class="control-group" data-bind="visible: showReplyTo, css: {'error': replyTo.hasError}"> <div class="control-group" data-bind="visible: showReplyTo, css: {'error': replyTo.hasError}">