summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2015-10-08 14:28:46 +0200
committerDylan William Hardison <dylan@hardison.net>2015-10-08 14:29:01 +0200
commitd6f47aa5f07a11a8771ce95f156b5394e67285a8 (patch)
treeaffa3ce076aacf5a7813e6e10415831d224b18f9
parent4ce3037df61ddee7eb20e744853d0b3e3990dcac (diff)
downloadbugzilla-d6f47aa5f07a11a8771ce95f156b5394e67285a8.tar.gz
bugzilla-d6f47aa5f07a11a8771ce95f156b5394e67285a8.tar.xz
Bug 1200765 - Make login UX mobile friendly to assist mobile authentication workflow
-rw-r--r--.htaccess1
-rw-r--r--Bugzilla/Template.pm5
-rw-r--r--skins/standard/global.css18
-rw-r--r--skins/standard/mobile.css66
-rw-r--r--template/en/default/account/auth/login.html.tmpl95
-rw-r--r--template/en/default/global/header.html.tmpl8
-rw-r--r--template/en/default/mfa/totp/verify.html.tmpl24
7 files changed, 157 insertions, 60 deletions
diff --git a/.htaccess b/.htaccess
index ab9b053da..b5ec2536f 100644
--- a/.htaccess
+++ b/.htaccess
@@ -91,3 +91,4 @@ RewriteRule ^rest/(.*)$ rest.cgi/$1 [NE]
RewriteRule ^(?:latest|1\.2|1\.3)/(.*)$ extensions/BzAPI/bin/rest.cgi/$1 [NE]
RewriteRule ^bzapi/(.*)$ extensions/BzAPI/bin/rest.cgi/$1 [NE]
RewriteRule ^data/assets/ZeroClipboard.swf(.*)$ extensions/BugModal/web/ZeroClipboard/ZeroClipboard.swf$1 [NE]
+RewriteRule ^login$ index.cgi?GoAheadAndLogIn=1 [NE]
diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm
index bc0d77084..b03698477 100644
--- a/Bugzilla/Template.pm
+++ b/Bugzilla/Template.pm
@@ -1117,6 +1117,11 @@ sub create {
return \@optional;
},
'default_authorizer' => sub { return Bugzilla::Auth->new() },
+
+ # It is almost always better to do mobile feature detection, client side in js.
+ # However, we need to set the meta[name=viewport] server-side or the behavior is
+ # not as predictable. It is possible other parts of the frontend may use this feature too.
+ 'is_mobile_browser' => sub { return Bugzilla->cgi->user_agent =~ /Mobi/ },
},
};
# Use a per-process provider to cache compiled templates in memory across
diff --git a/skins/standard/global.css b/skins/standard/global.css
index 81736f052..3790539e6 100644
--- a/skins/standard/global.css
+++ b/skins/standard/global.css
@@ -724,3 +724,21 @@ input.required, select.required, span.required_explanation {
background-repeat: no-repeat !important;
background-position: right 8px center !important;
}
+
+#login .field-login, #login .field-password {
+ line-height: 32px;
+ display: block;
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+#login .field-login label, #login .field-password label {
+ clear: left;
+ width: 7em;
+ display: inline-block;
+ font-weight: bold;
+}
+
+#login .field-restrict, #login .field-remember {
+ margin-left: 7em;
+}
diff --git a/skins/standard/mobile.css b/skins/standard/mobile.css
new file mode 100644
index 000000000..61179e93d
--- /dev/null
+++ b/skins/standard/mobile.css
@@ -0,0 +1,66 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This Source Code Form is "Incompatible With Secondary Licenses", as
+ * defined by the Mozilla Public License, v. 2.0.
+ */
+
+@media
+only screen and (max-device-width : 720px) {
+ #header, #footer {
+ display: none;
+ }
+ .cookie-notify {
+ display: none;
+ }
+
+ #login .field-login label, #login .field-password label {
+ display: block;
+ }
+
+ #login .field-login, #login .field-password {
+ line-height: auto;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ }
+
+ #login .field-restrict, #login .field-remember {
+ margin-left: 0px;
+ }
+ #login .field-submit {
+ padding-top: 4px;
+ }
+
+ h1 {
+ font-size: 1.5em;
+ }
+
+ .verify-totp input[type="text"] {
+ font-size: 28px;
+ }
+
+ .verify-totp input[type="submit"] {
+ font-size: 1em;
+ }
+}
+
+@media
+only screen and (-webkit-min-device-pixel-ratio: 2),
+only screen and (min--moz-device-pixel-ratio: 2),
+only screen and (-o-min-device-pixel-ratio: 2/1),
+only screen and (min-device-pixel-ratio: 2),
+only screen and (min-resolution: 192dpi),
+only screen and (min-resolution: 2dppx) {
+ #privacy_policy {
+ font-size: small;
+ }
+
+ body {
+ font-size: medium;
+ }
+
+ label.checkbox-note {
+ font-size: small;
+ }
+}
diff --git a/template/en/default/account/auth/login.html.tmpl b/template/en/default/account/auth/login.html.tmpl
index 922a55bd4..33aeaeaea 100644
--- a/template/en/default/account/auth/login.html.tmpl
+++ b/template/en/default/account/auth/login.html.tmpl
@@ -30,8 +30,9 @@
[% PROCESS global/variables.none.tmpl %]
[% PROCESS global/header.html.tmpl
- title = "Log in to $terms.Bugzilla",
- onload = "document.forms['login'].Bugzilla_login.focus()"
+ title = "Log in to $terms.Bugzilla",
+ onload = "document.forms['login'].Bugzilla_login.focus()"
+ allow_mobile = 1
%]
[% USE Bugzilla %]
@@ -40,59 +41,55 @@
I need an email address and password to continue.
</p>
-<form name="login" action="[% target FILTER html %]" method="POST"
-[%- IF Bugzilla.cgi.param("data") %] enctype="multipart/form-data"[% END %]>
- <table>
- <tr>
- <th align="right"><label for="Bugzilla_login">Email Address:</label></th>
- <td>
- <input size="35" id="Bugzilla_login" name="Bugzilla_login"
- [%- ' type="email"' UNLESS Param('emailsuffix') %]>
- [% Param('emailsuffix') FILTER html %]
- </td>
- </tr>
- <tr>
- <th align="right"><label for="Bugzilla_password">Password:</label></th>
- <td>
- <input type="password" size="35" id="Bugzilla_password" name="Bugzilla_password">
- </td>
- </tr>
+<div id="login" class="login-form">
+ <form name="login" action="[% target FILTER html %]" method="POST"
+ [%- IF Bugzilla.cgi.param("data") %] enctype="multipart/form-data"[% END %]>
+ <div class="field-login">
+ <label for="Bugzilla_login">Email Address:</label>
+ <input id="Bugzilla_login" name="Bugzilla_login"
+ [%- ' type="email"' UNLESS Param('emailsuffix') %]>
+ [% Param('emailsuffix') FILTER html %]
+ </div>
+
+ <div class="field-password">
+ <label for="Bugzilla_password">Password:</label>
+ <input type="password" id="Bugzilla_password" name="Bugzilla_password">
+ </div>
[% IF Param('rememberlogin') == 'defaulton' ||
- Param('rememberlogin') == 'defaultoff' %]
- <tr>
- <th>&nbsp;</th>
- <td>
- <input type="checkbox" id="Bugzilla_remember" name="Bugzilla_remember" value="on"
- [%+ "checked" IF Param('rememberlogin') == "defaulton" %]>
- <label for="Bugzilla_remember">Remember my email address</label>
- </td>
- </tr>
+ Param('rememberlogin') == 'defaultoff' %]
+ <div class="field-remember">
+ <input type="checkbox" id="Bugzilla_remember" name="Bugzilla_remember" value="on"
+ [%+ "checked" IF Param('rememberlogin') == "defaulton" %]>
+ <label for="Bugzilla_remember" class="checkbox-note">
+ Remember my email address
+ </label>
+ </div>
[% END %]
- <tr>
- <th>&nbsp;</th>
- <td>
- <input type="checkbox" id="Bugzilla_restrictlogin" name="Bugzilla_restrictlogin"
- checked="checked">
- <label for="Bugzilla_restrictlogin">Restrict this session to this IP address
- (using this option improves security)</label>
- </td>
- </tr>
- </table>
+ [% PROCESS "global/hidden-fields.html.tmpl"
+ exclude="^Bugzilla_(login|password|restrictlogin)$" %]
- [% PROCESS "global/hidden-fields.html.tmpl"
- exclude="^Bugzilla_(login|password|restrictlogin)$" %]
+ <div class="field-restrict">
+ <input type="checkbox" id="Bugzilla_restrictlogin" name="Bugzilla_restrictlogin"
+ checked="checked">
+ <label for="Bugzilla_restrictlogin" class="checkbox-note">
+ Restrict this session to this IP address
+ (using this option improves security)</label>
+ </div>
- <input type="hidden" name="Bugzilla_login_token"
- value="[% get_login_request_token() FILTER html %]">
- <input type="submit" name="GoAheadAndLogIn" value="Log in" id="log_in">
+ <div class="field-submit">
+ <input type="hidden" name="Bugzilla_login_token"
+ value="[% get_login_request_token() FILTER html %]">
+ <input type="submit" name="GoAheadAndLogIn" value="Log in" id="log_in">
+ </div>
- <p>
- (Note: you should make sure cookies are enabled for this site.
- Otherwise, you will be required to log in frequently.)
- </p>
-</form>
+ <p class="cookie-notify">
+ (Note: you should make sure cookies are enabled for this site.
+ Otherwise, you will be required to log in frequently.)
+ </p>
+ </form>
+</div>
[% Hook.process('additional_methods') %]
@@ -117,7 +114,7 @@
If you have an account, but have forgotten your password,
enter your email address below and submit a request
to change your password.<br>
- <input size="35" name="loginname">
+ <input name="loginname">
<input type="hidden" id="token" name="token" value="[% issue_hash_token(['reqpw']) FILTER html %]">
<input type="submit" id="request" value="Reset Password">
</form>
diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl
index 3f70b9453..23634ed43 100644
--- a/template/en/default/global/header.html.tmpl
+++ b/template/en/default/global/header.html.tmpl
@@ -37,6 +37,7 @@
# atomlink: Atom link URL, May contain HTML
# generate_api_token: generate a token which can be used to make authenticated webservice calls
# no_body: if true the body element will not be generated
+ # allow_mobile: allow special CSS and viewport for detected mobile useragents
#%]
[% IF message %]
@@ -103,6 +104,10 @@
[%# Add our required jQuery plugins %]
[% jquery.push("cookie", "devbridgeAutocomplete") %]
+[% IF allow_mobile && is_mobile_browser %]
+ [% style_urls.push("skins/standard/mobile.css") %]
+[% END %]
+
[%# We should be able to set the default value of the header variable
# to the value of the title variable using the DEFAULT directive,
# but that doesn't work if a caller sets header to the empty string
@@ -260,6 +265,9 @@
[%# Required for the 'Autodiscovery' feature in Firefox 2 and IE 7. %]
<link rel="search" type="application/opensearchdescription+xml"
title="[% terms.BugzillaTitle %]" href="./search_plugin.cgi">
+ [% IF allow_mobile && is_mobile_browser %]
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ [% END %]
[% Hook.process("additional_header") %]
</head>
diff --git a/template/en/default/mfa/totp/verify.html.tmpl b/template/en/default/mfa/totp/verify.html.tmpl
index ad75dc6bc..7314d909a 100644
--- a/template/en/default/mfa/totp/verify.html.tmpl
+++ b/template/en/default/mfa/totp/verify.html.tmpl
@@ -8,6 +8,7 @@
[% INCLUDE global/header.html.tmpl
title = "Account Verification"
+ allow_mobile = 1
%]
<h1>Account Verification</h1>
@@ -16,16 +17,17 @@
<b>[% reason FILTER html %]</b> requires verification.<br>
Please enter your verification code from your TOTP application:
</p>
-
-<form method="POST" action="[% postback.action FILTER none %]">
- [% FOREACH field IN postback.fields.keys %]
- <input type="hidden" name="[% field FILTER html %]" value="[% postback.fields.item(field) FILTER html %]">
- [% END %]
- <input type="text" name="code" id="code"
- placeholder="123456" maxlength="9" pattern="\d{6,9}" size="10"
- autocomplete="off" required autofocus><br>
- <br>
- <input type="submit" value="Submit">
-</form>
+<div class="verify-totp">
+ <form method="POST" action="[% postback.action FILTER none %]">
+ [% FOREACH field IN postback.fields.keys %]
+ <input type="hidden" name="[% field FILTER html %]" value="[% postback.fields.item(field) FILTER html %]">
+ [% END %]
+ <input type="text" name="code" id="code"
+ placeholder="123456" maxlength="9" pattern="\d{6,9}" size="10"
+ autocomplete="off" required autofocus><br>
+ <br>
+ <input type="submit" value="Submit">
+ </form>
+</div>
[% INCLUDE global/footer.html.tmpl %]