Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
274
gaia/dev_apps/mobile-wallet/js/pin/pin_view.js
Executable file
274
gaia/dev_apps/mobile-wallet/js/pin/pin_view.js
Executable file
|
|
@ -0,0 +1,274 @@
|
|||
'use strict';
|
||||
|
||||
/* globals addMixin, ObserverSubjectMixin, DebugMixin */
|
||||
/* exported PinView */
|
||||
|
||||
(function(exports) {
|
||||
// number of pin input attempts which should
|
||||
// trigger the pin warning display
|
||||
const PIN_ATTEMPTS_WARNING = 2;
|
||||
const PIN_INCORRECT_TIMEOUT = 1000; //ms
|
||||
const PIN_DEFAULT_LEN = 4;
|
||||
|
||||
const PIN_REQ_DEF = 'request-default-pin';
|
||||
const PIN_REQ_BEFORE_CHANGE = 'request-pin-before-change';
|
||||
const PIN_REQ_PUK = 'request-puk';
|
||||
const PIN_REQ_NEW_PIN = 'request-new-pin';
|
||||
const PIN_REQ_REPEAT_NEW_PIN = 'request-repeat-new-pin';
|
||||
|
||||
const PIN_ENTRY_TEXT_MAP = {};
|
||||
|
||||
PIN_ENTRY_TEXT_MAP[PIN_REQ_DEF] = {
|
||||
entry: 'Please enter your PIN',
|
||||
error: 'Incorrect PIN'
|
||||
};
|
||||
|
||||
PIN_ENTRY_TEXT_MAP[PIN_REQ_BEFORE_CHANGE] = {
|
||||
entry: 'Please enter current PIN',
|
||||
error: 'Incorrect PIN'
|
||||
},
|
||||
|
||||
PIN_ENTRY_TEXT_MAP[PIN_REQ_PUK] = {
|
||||
entry: 'Please enter your PUK',
|
||||
error: 'Incorrect PUK'
|
||||
};
|
||||
|
||||
PIN_ENTRY_TEXT_MAP[PIN_REQ_NEW_PIN] = {
|
||||
entry: 'Please enter new PIN',
|
||||
error: 'New PIN mismatch',
|
||||
};
|
||||
|
||||
PIN_ENTRY_TEXT_MAP[PIN_REQ_REPEAT_NEW_PIN] = {
|
||||
entry: 'Please confirm new PIN',
|
||||
error: ''
|
||||
};
|
||||
|
||||
var PinView = function(id, defPinLen, templateId) {
|
||||
this._id = id;
|
||||
this._defaultPinLen = defPinLen || PIN_DEFAULT_LEN;
|
||||
this._maxPinLen = this._defaultPinLen;
|
||||
|
||||
addMixin(this, ObserverSubjectMixin);
|
||||
addMixin(this, DebugMixin);
|
||||
|
||||
if(templateId) {
|
||||
this._el = document.querySelector('#' + templateId).cloneNode(true);
|
||||
this._el.id = this._id;
|
||||
} else {
|
||||
this._el = document.querySelector('#' + this._id);
|
||||
}
|
||||
|
||||
this._init();
|
||||
};
|
||||
|
||||
PinView.prototype = {
|
||||
REQUEST_PIN: PIN_REQ_DEF,
|
||||
REQUEST_BEFORE_CHANGE: PIN_REQ_BEFORE_CHANGE,
|
||||
REQUEST_PUK: PIN_REQ_PUK,
|
||||
REQUEST_NEW_PIN: PIN_REQ_NEW_PIN,
|
||||
REQUEST_CONFIRM: PIN_REQ_REPEAT_NEW_PIN,
|
||||
|
||||
_el: null,
|
||||
_id: null,
|
||||
_visible: false,
|
||||
|
||||
_pinInputEl: null,
|
||||
_inputedPin: '',
|
||||
|
||||
// we have a default PIN length but we can do one time request for PINs
|
||||
// of different length (i.e. PUK)
|
||||
_defaultPinLen: 0,
|
||||
_maxPinLen: 0,
|
||||
|
||||
_inputBlocked: false,
|
||||
|
||||
isVisible() {
|
||||
return this._visible;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this._visible = true;
|
||||
this._el.classList.remove('hide');
|
||||
this._clearPin();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._visible = false;
|
||||
this._el.classList.add('hide');
|
||||
},
|
||||
|
||||
_init: function() {
|
||||
this._pinInputEl = this._el.querySelector('.pin-input');
|
||||
|
||||
var keyHandler = this._keyHandler.bind(this);
|
||||
var keypad = this._el.querySelector('.pin-keypad');
|
||||
keypad.addEventListener('touchstart', keyHandler, true);
|
||||
|
||||
this._updatePinInput();
|
||||
},
|
||||
|
||||
_keyHandler: function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
var key = event.target.dataset.value;
|
||||
if(!key || this._inputBlocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(key) {
|
||||
case 'clear': this._clearPin(); break;
|
||||
case 'backspace': this._backspacePin(); break;
|
||||
default: this._appendPin(key);
|
||||
}
|
||||
},
|
||||
|
||||
_clearPin: function() {
|
||||
this._inputedPin = '';
|
||||
this._updatePinInput();
|
||||
},
|
||||
|
||||
_backspacePin: function() {
|
||||
if(!this._inputedPin.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._inputedPin = this._inputedPin.slice(0, -1);
|
||||
this._updatePinInput();
|
||||
},
|
||||
|
||||
_appendPin: function(digit) {
|
||||
if(this._inputedPin.length >= this._maxPinLen) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._inputedPin += digit;
|
||||
this._updatePinInput();
|
||||
|
||||
if(this._inputedPin.length === this._maxPinLen) {
|
||||
if(this._maxPinLen !== this._defaultPinLen) {
|
||||
this._maxPinLen = this._defaultPinLen;
|
||||
}
|
||||
this._notify({ action: 'pin-inputed', pin: this._inputedPin });
|
||||
}
|
||||
},
|
||||
|
||||
_updatePinInput: function() {
|
||||
var inputedDigits = this._inputedPin.length;
|
||||
var fragment = document.createDocumentFragment();
|
||||
for(var i = 0; i < this._maxPinLen; i++) {
|
||||
var pinDigit = document.createElement('div');
|
||||
if(i < inputedDigits) {
|
||||
pinDigit.classList.add('pin-digit-entered');
|
||||
}
|
||||
fragment.appendChild(pinDigit);
|
||||
}
|
||||
this._pinInputEl.innerHTML = '';
|
||||
this._pinInputEl.appendChild(fragment);
|
||||
},
|
||||
|
||||
_updatePinInputTexts: function _updatePinInputTexts(reqType) {
|
||||
reqType = (reqType in PIN_ENTRY_TEXT_MAP) ? reqType : PIN_REQ_DEF;
|
||||
this._el.querySelector('.pin-entry-text')
|
||||
.textContent = PIN_ENTRY_TEXT_MAP[reqType].entry;
|
||||
this._el.querySelector('.pin-entry-error-text')
|
||||
.textContent = PIN_ENTRY_TEXT_MAP[reqType].error;
|
||||
},
|
||||
|
||||
requestPin: function(attemptsLeft, showPinIncorrect, reqType, pinLen) {
|
||||
this.debug('requestPIN, tries: ' + attemptsLeft + ', type: ' + reqType);
|
||||
this._maxPinLen = pinLen || this._maxPinLen;
|
||||
this._clearPin();
|
||||
|
||||
this._updatePinInputTexts(reqType);
|
||||
this._showByClass('pin-unblocked');
|
||||
|
||||
if(showPinIncorrect) {
|
||||
this._showPinIncorrect();
|
||||
if(reqType !== PIN_REQ_NEW_PIN) {
|
||||
this._showWarning(attemptsLeft);
|
||||
}
|
||||
} else if(attemptsLeft <= PIN_ATTEMPTS_WARNING) {
|
||||
this._showWarning(attemptsLeft);
|
||||
} else {
|
||||
this._clearWarning();
|
||||
}
|
||||
},
|
||||
|
||||
cancelPinRequest: function() {
|
||||
this._maxPinLen = this._defaultPinLen;
|
||||
this._notify({});
|
||||
},
|
||||
|
||||
blockPin: function() {
|
||||
window.navigator.vibrate([200, 100, 200, 100, 200]);
|
||||
this._showByClass('pin-blocked');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var unblockBtn = this._el.querySelector('.pin-unblock-btn');
|
||||
var onclick = () => {
|
||||
unblockBtn.removeEventListener('click', onclick);
|
||||
resolve();
|
||||
};
|
||||
|
||||
unblockBtn.addEventListener('click', onclick);
|
||||
});
|
||||
},
|
||||
|
||||
blockPuk: function() {
|
||||
window.navigator.vibrate([200, 100, 200, 100, 200]);
|
||||
this._showByClass('puk-blocked');
|
||||
return new Promise(()=>{});
|
||||
},
|
||||
|
||||
showEnableFailed: function(tries, defaultPin) {
|
||||
window.navigator.vibrate([200, 100, 200, 100, 200]);
|
||||
this._showByClass('pin-enable-error');
|
||||
this._el.querySelector('.pin-default-val').textContent = defaultPin;
|
||||
if(tries || tries === 0) {
|
||||
this._el.querySelector('.pin-enable-warning').classList.remove('hide');
|
||||
var att = (tries === 1) ? ' entry attempt' : ' entry attempts';
|
||||
this._el.querySelector('.pin-enable-attempt').textContent = tries + att;
|
||||
} else {
|
||||
this._el.querySelector('.pin-enable-warning').classList.add('hide');
|
||||
}
|
||||
},
|
||||
|
||||
_showByClass: function(clss) {
|
||||
var nodesList = this._el.querySelectorAll('article');
|
||||
Array.prototype.slice.call(nodesList).forEach(el => {
|
||||
if(el.classList.contains(clss)) {
|
||||
el.classList.remove('hide');
|
||||
} else {
|
||||
el.classList.add('hide');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_showWarning: function(attemptsLeft) {
|
||||
this._el.querySelector('.pin-warning').classList.remove('hide');
|
||||
var warning = attemptsLeft + ' attempt';
|
||||
warning = (attemptsLeft !== 1) ? (warning + 's') : warning;
|
||||
warning += ' remaining';
|
||||
this._el.querySelector('.pin-attempts').textContent = warning;
|
||||
},
|
||||
|
||||
_togglePinIncorrect: function(show) {
|
||||
this._inputBlocked = show;
|
||||
this._el.querySelector('.pin-entry').classList.toggle('hide');
|
||||
this._el.querySelector('.pin-incorrect').classList.toggle('hide');
|
||||
},
|
||||
|
||||
_showPinIncorrect: function() {
|
||||
window.navigator.vibrate([200, 100, 200]);
|
||||
this._togglePinIncorrect(true);
|
||||
setTimeout(() => this._togglePinIncorrect(false), PIN_INCORRECT_TIMEOUT);
|
||||
},
|
||||
|
||||
_clearWarning: function() {
|
||||
this._el.querySelector('.pin-warning').classList.add('hide');
|
||||
}
|
||||
};
|
||||
|
||||
exports.PinView = PinView;
|
||||
}((typeof exports === 'undefined') ? window : exports));
|
||||
Loading…
Reference in a new issue