Refactor options page and style using bootstrap

This commit is contained in:
lilia 2014-10-14 00:41:18 -07:00
parent 81e4af5827
commit 2bd77693e1
6 changed files with 8676 additions and 227 deletions

View file

@ -17,39 +17,126 @@
font-family: Ubuntu, Segoe, 'Lucidia Grande', sans-serif; font-family: Ubuntu, Segoe, 'Lucidia Grande', sans-serif;
} }
html { .paper {
margin: 12px 100px 0 100px; } background-color: #fafafa;
@include box-shadow(5px 0 5px -2px #ddd, -5px 0 5px -2px #ddd);
}
h1 { h1 {
font-size: 30pt; font-size: 30pt;
font-weight: normal; font-weight: normal;
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px solid #e0e0e0; } }
h2 { h2 {
font-size: 12pt; font-size: 12pt;
font-weight: normal; } font-weight: normal;
}
.left-column { .left-column {
float: left; float: left;
width: 45%; width: 45%;
text-align: center; } }
.right-column { .right-column {
float: right; float: right;
width: 50%; width: 50%;
text-align: center; } }
.hidden { .hidden {
display: none; } display: none;
}
#textsecure-icon { #textsecure-icon {
width: 50px; width: 50px;
height: 50px; } height: 50px;
}
#phonenumberspan { #setup-qr {
display: block; max-width: 256px;
margin: .5em auto 1em auto; } margin-top: 1em;
}
#countrycode { #verifyCode,
text-align: right; } #code,
#number {
box-sizing: border-box;
width: 100%;
display: block;
text-align: center;
margin-bottom: 0.5em;
}
#request-voice,
#request-sms {
box-sizing: border-box;
}
#request-sms {
width: 57%;
float: right;
}
#request-voice {
width: 40%;
float: left;
}
#regionCode {
width: 100%;
margin-bottom: 1em;
}
#number-container {
position: relative;
margin-bottom: 0.5em;
}
#number-container::after {
visibility: hidden;
content: ' ';
display: inline-block;
border-radius: 1.5em;
width: 1.5em;
height: 1.5em;
line-height: 1.5em;
color: #ffffff;
position: absolute;
top: 0;
left: 100%;
margin: 3px 8px;
text-align: center;
}
#number-container.valid::after {
visibility: visible;
content: '✓';
background-color: #0f9d58;
color: #ffffff;
}
#number-container.invalid::after {
visibility: visible;
content: '!';
background-color: #f44336;
color: #ffffff;
}
#error {
color: white;
font-weight: bold;
padding: 0.5em;
text-align: center;
}
#error { background-color: #f44336; }
#error:before {
content: '\26a0';
padding-right: 0.5em;
}
.narrow {
box-sizing: border-box;
margin: 0 auto 5px;
width: 275px;
max-width: 100%;
}
#single-device form {
margin: 2em 0;
}
#log, #listener { height: 0; }

2114
js-deps/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -117,13 +117,19 @@ window.textsecure.api = function() {
}); });
}; };
self.requestVerificationCode = function(number) { function requestVerificationCode(number, transport) {
return doAjax({ return doAjax({
call : 'accounts', call : 'accounts',
httpType : 'GET', httpType : 'GET',
urlParameters : '/sms/code/' + number, urlParameters : '/' + transport + '/code/' + number,
}); });
}; };
self.requestVerificationSMS = function(number) {
return requestVerificationCode(number, 'sms');
};
self.requestVerificationVoice = function(number) {
return requestVerificationCode(number, 'voice');
};
self.confirmCode = function(number, code, password, self.confirmCode = function(number, code, password,
signaling_key, registrationId, single_device) { signaling_key, registrationId, single_device) {

View file

@ -15,182 +15,193 @@
*/ */
;(function() { ;(function() {
function updateNumberColors() { function validateNumber() {
try { try {
if($('#number').val() != "" && $('#regionCode').val() != "") var regionCode = $('#regionCode').val();
libphonenumber.util.verifyNumber($('#number').val(), $('#regionCode').val()); var number = $('#number').val();
$('#countrycode').removeClass('invalid');
$('#number').removeClass('invalid');
} catch (numberInvalidError) {
console.log(numberInvalidError);
$('#countrycode').addClass('invalid');
$('#number').addClass('invalid');
}
}
function isCodeValid() { var parsedNumber = libphonenumber.util.verifyNumber(number, regionCode);
var verificationCode = $('#code').val().replace(/\D/g, '');
return verificationCode.length == 6;
}
$('#code').on('change', function() { $('#regionCode').val(libphonenumber.util.getRegionCodeForNumber(parsedNumber));
if (!isCodeValid()) $('#number-container').removeClass('invalid');
$('#code').addClass('invalid'); $('#number-container').addClass('valid');
else $('#request-sms, #request-voice').removeAttr('disabled');
$('#code').removeClass('invalid'); return parsedNumber;
});
var single_device = false;
$('#init-go-single-client').click(function() {
try {
var parsedNumber = libphonenumber.util.verifyNumber($('#number').val(), $('#regionCode').val());
} catch(e) { } catch(e) {
alert("Please enter a valid phone number first."); $('#number-container').removeClass('valid');
return false; $('#request-sms, #request-voice').prop('disabled', 'disabled');
} }
};
$('#init-go').text('Setup'); function validateCode() {
$('#countrycode').prop('disabled', 'disabled'); var verificationCode = $('#code').val().replace(/\D/g, '');
$('#number').prop('disabled', 'disabled'); if (verificationCode.length == 6) {
$('#init-go-single-client').prop('disabled', 'disabled'); return verificationCode;
$('#init-setup-verification').show();
single_device = true;
textsecure.api.requestVerificationCode(parsedNumber).catch(function(error) {
//TODO: No alerts
if (error.humanReadable)
alert(error.humanReadable);
else
alert(error); // XXX
});
});
$('#init-go').click(function() {
var parsedNumber = libphonenumber.util.verifyNumber($('#number').val(), $('#regionCode').val());
if (!isCodeValid()) {
updateCodeColor();
return;
} }
};
$('#init-setup').hide(); function displayError(error) {
$('#verify1').hide(); $('#error').hide().text(error).fadeIn();
$('#verify2done').text(''); };
$('#verify3done').text('');
$('#verify4done').text('');
$('#verify5').hide();
$('#verify').show();
textsecure.registerSingleDevice(parsedNumber, $('#code').val(), function(step) {
switch(step) {
case 1:
$('#verify2done').text('done');
break;
case 2:
$('#verify3done').text('done');
break;
case 3:
$('#complete-number').text(parsedNumber);
$('#verify').hide();
$('#setup-complete').show();
registrationDone();
}
}).catch(function(error) {
//TODO: No alerts...
if (error.humanError)
alert(error.humanError);
else
alert(error); //XXX
});
});
textsecure.registerOnLoadFunction(function() { textsecure.registerOnLoadFunction(function() {
$(function() { $(function() {
if (!isRegistrationDone()) { if (isRegistrationDone()) {
$('#init-setup').show(); $('#complete-number').text(textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0]);//TODO: no
$('#setup-complete').show();
} else {
$('#choose-setup').show();
$('#number').keyup(validateNumber);
$('#regionCode').change(validateNumber);
var countrys = libphonenumber.util.getAllRegionCodes(); $.each(libphonenumber.util.getAllRegionCodes(), function (regionCode, countryName) {
$.each(countrys, function (regionCode, countryName) { $('#regionCode').append(
$('#regionCode').append($('<option>', { $('<option>', { value: regionCode, text: countryName })
value: regionCode, );
text : countryName
}));
}); });
$('#regionCode').change(function(){ $('#code').on('change', function() {
$('#countrycode').val(libphonenumber.util.getCountryCodeForRegion(this.value)); if (!validateCode())
updateNumberColors(); $('#code').addClass('invalid');
else
$('#code').removeClass('invalid');
}); });
$('#countrycode').keyup(function(){ $('#request-voice').click(function() {
$('#regionCode').val(libphonenumber.util.getRegionCodeForCountryCode($('#countrycode').val())); var number = validateNumber();
updateNumberColors(); if (number) {
textsecure.api.requestVerificationVoice(number).catch(displayError);
$('#step2').fadeIn();
} else {
$('#number-container').addClass('invalid');
}
}); });
$('#number').change(updateNumberColors); $('#request-sms').click(function() {
var number = validateNumber();
if (number) {
textsecure.api.requestVerificationSMS(number).catch(displayError);
$('#step2').fadeIn();
} else {
$('#number-container').addClass('invalid');
}
});
// handle form data cached by the browser (after a page ref $('#new-account').click(function(){
$('#regionCode').val(libphonenumber.util.getRegionCodeForCountryCode($('#countrycode').val())); $('#choose-setup').fadeOut(function() {
updateNumberColors(); $('#single-device').fadeIn();
});
textsecure.crypto.prepareTempWebsocket().then(function(cryptoInfo) { $('#single-device .back').click(function() {
var qrCode = new QRCode(document.getElementById('setup-qr')); $('#single-device').fadeOut(function() {
var socket = textsecure.api.getTempWebsocket(); $('#choose-setup').fadeIn();
$('#number').removeClass('invalid');
});
});
socket.onmessage = function(message) { $('#single-device form').submit(function(e) {
if (message.uuid) { e.preventDefault();
qrCode.makeCode('textsecure-device-init:/' + $('#error').hide();
'?channel_uuid=' + message.uuid + var number = validateNumber();
'&channel_server=' + textsecure.api.relay + var verificationCode = validateCode();
'&publicKey=' + btoa(getString(cryptoInfo.publicKey))); if (number && verificationCode) {
$('img').removeAttr('style'); $('#verify1').hide();
$('#left-connecting').hide();
$('#left-setup').show();
$('#left-reconnecting').hide();
} else {
$('#init-setup').hide();
$('#verify1done').text('');
$('#verify2done').text(''); $('#verify2done').text('');
$('#verify3done').text(''); $('#verify3done').text('');
$('#verify4done').text(''); $('#verify4done').text('');
$('#verify5done').text(''); $('#verify5').hide();
$('#verify').show(); $('#verify').show();
textsecure.registerSingleDevice(number, verificationCode, function(step) {
textsecure.registerSecondDevice(cryptoInfo, message.message, function(step) {
switch(step) { switch(step) {
case 1: case 1:
$('#verify1done').text('done');
break;
case 2:
$('#verify2done').text('done'); $('#verify2done').text('done');
break; break;
case 3: case 2:
$('#verify3done').text('done'); $('#verify3done').text('done');
break; break;
case 4: case 3:
//TODO: User needs to verify number before we continue $('#complete-number').text(number);
$('#complete-number').text(parsedNumber);
$('#verify4done').text('done');
case 5:
$('#verify').hide(); $('#verify').hide();
$('#setup-complete').show(); $('#setup-complete').show();
registrationDone(); registrationDone();
} }
}).catch(function(error) {
//TODO: No alerts...
if (error.humanError)
displayError(error.humanError);
else
displayError(error); //XXX
}); });
} }
}; });
});
socket.ondisconnect = function() {
$('#left-connecting').hide(); $('#new-device').click(function(){
$('#left-setup').hide(); $('#choose-setup').fadeOut(function() {
$('#left-reconnecting').show(); $('#multi-device').fadeIn();
}; });
$('#multi-device .back').click(function() {
$('#multi-device').fadeOut(function() {
$('#choose-setup').fadeIn();
$('#number').removeClass('invalid');
});
});
$('#multi-device .status').text("Connecting...");
$('#setup-qr').html('');
textsecure.crypto.prepareTempWebsocket().then(function(cryptoInfo) {
var qrCode = new QRCode(document.getElementById('setup-qr'));
var socket = textsecure.api.getTempWebsocket();
socket.onmessage = function(message) {
if (message.uuid) {
qrCode.makeCode('textsecure-device-init:/' +
'?channel_uuid=' + message.uuid +
'&channel_server=' + textsecure.api.relay +
'&publicKey=' + btoa(getString(cryptoInfo.publicKey)));
$('img').removeAttr('style');
$('#multi-device .status').text("Use your phone to scan the QR code.")
} else {
$('#init-setup').hide();
$('#verify1done').text('');
$('#verify2done').text('');
$('#verify3done').text('');
$('#verify4done').text('');
$('#verify5done').text('');
$('#verify').show();
textsecure.registerSecondDevice(cryptoInfo, message.message, function(step) {
switch(step) {
case 1:
$('#verify1done').text('done');
break;
case 2:
$('#verify2done').text('done');
break;
case 3:
$('#verify3done').text('done');
break;
case 4:
//TODO: User needs to verify number before we continue
$('#complete-number').text(parsedNumber);
$('#verify4done').text('done');
case 5:
$('#verify').hide();
$('#setup-complete').show();
registrationDone();
}
});
}
};
socket.ondisconnect = function() {
$('#multi-device .status').text("The push server disconnected, please wait while we reconnect...");
};
});
}); });
} else {
$('#complete-number').text(textsecure.utils.unencodeNumber(textsecure.storage.getUnencrypted("number_id"))[0]);//TODO: no
$('#setup-complete').show();
} }
}); });
}); });

View file

@ -1,91 +1,119 @@
<!--This program is free software: you can redistribute it and/or modify <!--This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>TextSecure Options</title> <title>TextSecure Options</title>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" href="css/options.css"> <link rel="stylesheet" href="css/options.css">
<link rel="stylesheet" href="css/forms.css"> <link rel="stylesheet" href="stylesheets/bootstrap.css">
<link rel="stylesheet" href="css/buttons.css">
</head> </head>
<body data-name="curve25519" data-tools="pnacl" data-configs="Debug Release" data-path="nacl/pnacl/{config}"> <body data-name="curve25519" data-tools="pnacl" data-configs="Debug Release" data-path="nacl/pnacl/{config}">
<div id="listener"></div> <div id="listener"></div>
<div id="log"></div> <div id="log"></div>
<h1><img id="textsecure-icon" src='icon.png'/> TextSecure</h1> <div class='container'>
<div id="init-setup" class="hidden"> <h1><img id="textsecure-icon" src='icon.png'/> TextSecure</h1>
<h2>Welcome to TextSecure. If you want to register as a secondary device, follow the instructions on the left, if you want to register as the only device, follow the instructions on the right</h2> <div id='choose-setup' class='collapse'>
<div class='row'>
<div class='col-xs-5 col-xs-offset-1'>
<p>I'm new to TextSecure</p>
</div>
<div class='col-xs-5'>
<p>I have TextSecure installed on my phone.</p>
</div>
</div>
<div class='row'>
<div class='col-xs-5 col-xs-offset-1'>
<p><button type='button' id='new-account' class='btn btn-default'>Register</button></p>
</div>
<div class='col-xs-5'>
<p><button type='button' id='new-device' class='btn btn-default'>Add a device</button></p>
</div>
</div>
</div>
<div id="init-setup">
<div id='multi-device' class='collapse'>
<button class='back btn btn-link'>Back</button>
<div class='narrow'>
<div class='status'></div>
<div id="setup-qr"></div>
</div>
</div>
<div id='single-device' class='row collapse'>
<div class='col-xs-offset-1 col-md-6'>
<button class='back btn btn-link'>Back</button>
<div class='narrow'>
<div id='step1'>
<div id='number-container'>
<input type="text" id="number" placeholder="Phone Number">
</div>
<div>
<select id="regionCode">
<option value="ZZ" selected>Country</option>
</select>
</div>
<div class='clearfix'>
<button id="request-sms" class="btn btn-default">Send SMS</button>
<button id="request-voice" class="btn btn-default">Call</button>
</div>
</div>
<form id="step2" class="collapse">
<input type="text" pattern="[0-9]{3}-?[0-9]{3}" title="Enter your 6-digit verification code. If you did not receive a code, click Call or Send SMS to request a new one" id="code" placeholder="Verification Code" autocomplete='off'>
<button id="verifyCode" class="btn btn-info">Submit</button>
<div id='error' class='collapse'></div>
</form>
</div>
</div>
</div>
</div>
<div id="verify" class="hidden">
<div id="verify1">Receiving identity key...<span id="verify1done"></span></div>
<div id="verify2">Verifying number and setup code...<span id="verify2done"></span></div>
<div id="verify3">Generating keys...<span id="verify3done"></span></div>
<div id="verify4">Registering...<span id="verify4done"></span></div>
<div id="verify5">Syncing with existing devices...<span id="verify5done"></span></div>
</div>
<div id="setup-complete" class="collapse">
<h3>You are registered on TextSecure with number <span id="complete-number"></span></h3>
</div>
</div>
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
<script type="text/javascript" src="js-deps/jquery.js"></script>
<script type="text/javascript" src="js-deps/bootstrap.js"></script>
<script type="text/javascript" src="js-deps/CryptoJS.js"></script>
<script type="text/javascript" src="js-deps/curve255.js"></script>
<script type="text/javascript" src="js-deps/Long.min.js"></script>
<script type="text/javascript" src="js-deps/ByteBuffer.min.js"></script>
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
<script type="text/javascript" src="js-deps/underscore.js"></script>
<script type="text/javascript" src="js-deps/backbone.js"></script>
<script type="text/javascript" src="js-deps/backbone.localStorage.js"></script>
<script type="text/javascript" src="js-deps/libphonenumber_api-compiled.js"></script>
<script type="text/javascript" src="js-deps/qrcode.min.js"></script>
<div id="left-connecting" class="left-column"> <script type="text/javascript" src="js/helpers.js"></script>
Please wait while we connect to the push server...
</div>
<div id="left-setup" class="left-column hidden">
Please scan the QR code below on the master device: <br>
<div id="setup-qr"></div>
</div>
<div id="left-reconnecting" class="left-column hidden">
The push server disconnected, please wait while we reconnect...
</div>
<div class="right-column">
<span>Please select your country or enter your country code below:</span>
<select id="regionCode">
<option value="ZZ" selected>Please choose your country.</option>
</select>
<span id="phonenumberspan">+ <input type="text" size="3" id="countrycode"> <input type="text" size="14" id="number"></span>
<button id="init-go-single-client" class="btn">Send single-client code</button>
<div id="init-setup-verification" class="hidden">
<p>Code: <input type="text" pattern="[0-9]{3}-?[0-9]{3}" title="Enter the 6-didgit verificaion code displayed on your phone." size="8" id="code" /></p>
<button id="init-go" class="btn">Sync</button>
</div>
</div>
</div>
<div id="verify" class="hidden">
<div id="verify1">Receiving identity key...<span id="verify1done"></span></div>
<div id="verify2">Verifying number and setup code...<span id="verify2done"></span></div>
<div id="verify3">Generating keys...<span id="verify3done"></span></div>
<div id="verify4">Registering...<span id="verify4done"></span></div>
<div id="verify5">Syncing with existing devices...<span id="verify5done"></span></div>
</div>
<div id="setup-complete" class="hidden">
<h2>You are now registered on TextSecure with number <span id="complete-number"></span></h2>
</div>
<script type="text/javascript" src="js-deps/nacl-common.js"></script>
<script type="text/javascript" src="js-deps/jquery.js"></script>
<script type="text/javascript" src="js-deps/CryptoJS.js"></script>
<script type="text/javascript" src="js-deps/curve255.js"></script>
<script type="text/javascript" src="js-deps/Long.min.js"></script>
<script type="text/javascript" src="js-deps/ByteBuffer.min.js"></script>
<script type="text/javascript" src="js-deps/ProtoBuf.min.js"></script>
<script type="text/javascript" src="js-deps/underscore.js"></script>
<script type="text/javascript" src="js-deps/backbone.js"></script>
<script type="text/javascript" src="js-deps/backbone.localStorage.js"></script>
<script type="text/javascript" src="js-deps/libphonenumber_api-compiled.js"></script>
<script type="text/javascript" src="js-deps/qrcode.min.js"></script>
<script type="text/javascript" src="js/helpers.js"></script>
<script type="text/javascript" src="js/libphonenumber-util.js"></script> <script type="text/javascript" src="js/libphonenumber-util.js"></script>
<script type="text/javascript" src="js/webcrypto.js"></script> <script type="text/javascript" src="js/webcrypto.js"></script>
<script type="text/javascript" src="js/crypto.js"></script> <script type="text/javascript" src="js/crypto.js"></script>
<script type="text/javascript" src="js/models/messages.js"></script> <script type="text/javascript" src="js/models/messages.js"></script>
<script type="text/javascript" src="js/models/threads.js"></script> <script type="text/javascript" src="js/models/threads.js"></script>
<script type="text/javascript" src="js/api.js"></script> <script type="text/javascript" src="js/api.js"></script>
<script type="text/javascript" src="js/sendmessage.js"></script> <script type="text/javascript" src="js/sendmessage.js"></script>
<script type="text/javascript" src="js/chromium.js"></script> <script type="text/javascript" src="js/chromium.js"></script>
<script type="text/javascript" src="js/options.js"></script> <script type="text/javascript" src="js/options.js"></script>
</body> </body>
</html> </html>

6203
stylesheets/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load diff