mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
1633 lines
41 KiB
JavaScript
Executable File
1633 lines
41 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Section class
|
|
class Section {
|
|
|
|
// Public
|
|
|
|
// Constructor
|
|
constructor(display, sections, settings, message, focus, application, unlocked, automaticLock, scroll, wallets, node, wakeLock, transactions, prices, clipboard) {
|
|
|
|
// Set display
|
|
this.display = display;
|
|
|
|
// Set sections
|
|
this.sections = sections;
|
|
|
|
// Set settings
|
|
this.settings = settings;
|
|
|
|
// Set message
|
|
this.message = message;
|
|
|
|
// Set focus
|
|
this.focus = focus;
|
|
|
|
// Set application
|
|
this.application = application;
|
|
|
|
// Set unlocked
|
|
this.unlocked = unlocked;
|
|
|
|
// Set automatic lock
|
|
this.automaticLock = automaticLock;
|
|
|
|
// Set scroll
|
|
this.scroll = scroll;
|
|
|
|
// Set wallets
|
|
this.wallets = wallets;
|
|
|
|
// Set node
|
|
this.node = node;
|
|
|
|
// Set wake lock
|
|
this.wakeLock = wakeLock;
|
|
|
|
// Set transactions
|
|
this.transactions = transactions;
|
|
|
|
// Set prices
|
|
this.prices = prices;
|
|
|
|
// Set clipboard
|
|
this.clipboard = clipboard;
|
|
|
|
// Set elements states
|
|
this.elementsStates = [];
|
|
|
|
// Set restoring state
|
|
this.restoringState = false;
|
|
|
|
// Register section
|
|
this.sections.registerSection(this);
|
|
|
|
// Set last scroll position
|
|
this.lastScrollPosition = 0;
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Document key down event
|
|
$(document).on("keydown", function(event) {
|
|
|
|
// Check if key tab is pressed
|
|
if(event["which"] === "\t".charCodeAt(0)) {
|
|
|
|
// Enable tabbing to all not disabled section navigation buttons
|
|
self.display.find("div.navigation").find("button:not(.disabled)").enableTab();
|
|
|
|
// Disable tabbing to all disabled section navigation buttons
|
|
self.display.find("div.navigation").find("button.disabled").disableTab();
|
|
}
|
|
});
|
|
|
|
// Section navigation back button click event
|
|
this.display.find("div.navigation").find("button.back").on("click", function() {
|
|
|
|
// Show previous section
|
|
self.sections.showPreviousSection().catch(function(error) {
|
|
|
|
});
|
|
});
|
|
|
|
// Section navigation forward button click event
|
|
this.display.find("div.navigation").find("button.forward").on("click", function() {
|
|
|
|
// Show next section and catch errors
|
|
self.sections.showNextSection().catch(function(error) {
|
|
|
|
});
|
|
});
|
|
|
|
// Display scroll stopped event
|
|
this.display.scrollStopped(function(event) {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state in stack and catch errors
|
|
self.sections.updateStateInStack(self).catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Display button, input, select, and anchor focus event
|
|
}).on("focus", "button, input, select, a", function() {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state and catch errors
|
|
self.updateState().catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Display button, input, select, and anchor blur event
|
|
}).on("blur", "button, input, select, a", function() {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if automatic lock isn't locking, the document has focus, and the is shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.automaticLock.isLocking() === false && document.hasFocus() === true && self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state and catch errors
|
|
self.updateState().catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Display button click event
|
|
}).on("click", "button", function() {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state and catch errors
|
|
self.updateState().catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Display input and select input event
|
|
}).on("input", "input, select", function() {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state and catch errors
|
|
self.updateState().catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Display option enable event
|
|
}).on(Common.ENABLE_EVENT, "option", function() {
|
|
|
|
// Get option
|
|
var option = $(this);
|
|
|
|
// Check if option is selected
|
|
if(option.is(":selected") === true) {
|
|
|
|
// Disable option
|
|
option.disable();
|
|
}
|
|
|
|
// Display option language change event
|
|
}).on(Language.CHANGE_EVENT, "option", function() {
|
|
|
|
// Get option's parent
|
|
var parent = $(this).parent();
|
|
|
|
// Get parent's value
|
|
var value = parent.children(":selected").val();
|
|
|
|
// Clear parent's value and set it back to the value
|
|
parent.val("").val(value);
|
|
});
|
|
|
|
// Display input select event
|
|
this.display.find("select").on("input", function(event) {
|
|
|
|
// Check if not restoring state
|
|
if(self.restoringState === false) {
|
|
|
|
// Check if shown and wallets display isn't showing or wallets expand button is hidden
|
|
if(self.isShown() === true && (self.unlocked.walletsDisplay.children("div").hasClass("hide") === true || self.unlocked.walletsDisplay.find("button.expand").is(":hidden") === true)) {
|
|
|
|
// Update state and catch errors
|
|
self.updateState().catch(function(error) {
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
// Enable select's options
|
|
$(this).children("option").enable();
|
|
});
|
|
|
|
// Display dotted text language change event
|
|
this.display.find("span.dots").parent().on(Language.CHANGE_EVENT, function() {
|
|
|
|
// Get text
|
|
var text = $(this).children("p");
|
|
|
|
// Check if text exists
|
|
if(text["length"] !== 0) {
|
|
|
|
// Update text's dots
|
|
Section.updateDots(text);
|
|
}
|
|
});
|
|
|
|
// Window resize event
|
|
$(window).on("resize", function() {
|
|
|
|
// Go through all dotted text in the display
|
|
self.display.find("span.dots").siblings("p").each(function() {
|
|
|
|
// Get text
|
|
var text = $(this);
|
|
|
|
// Update text's dots
|
|
Section.updateDots(text);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Get name
|
|
getName() {
|
|
|
|
// Return name
|
|
return "";
|
|
}
|
|
|
|
// Show
|
|
show(minimal = false, showErrors = true, enableAfterInitializing = true, state = Section.NO_STATE, updateStack = true, saveCurrentDisplay = false, isTemporary = false) {
|
|
|
|
// Get unlocked display
|
|
var unlockedDisplay = $("div.unlocked");
|
|
|
|
// Check if not minimal
|
|
if(minimal === false) {
|
|
|
|
// Get changing temporary
|
|
var changingTemporary = (unlockedDisplay.hasClass("minimal") === true && isTemporary === false) || (unlockedDisplay.hasClass("minimal") === false && isTemporary === true);
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Show loading
|
|
this.application.showLoading();
|
|
|
|
// Save focus and blur
|
|
this.focus.save(true);
|
|
|
|
// Disable unlocked
|
|
this.unlocked.disable();
|
|
|
|
// Prevent automatic lock
|
|
this.automaticLock.prevent();
|
|
}
|
|
|
|
// Check if not temporary
|
|
if(isTemporary === false) {
|
|
|
|
// Hide wallets
|
|
this.unlocked.hideWallets(false);
|
|
}
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Show section display
|
|
var showSectionDisplay = function() {
|
|
|
|
// Process error
|
|
var processError = function(error) {
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Allow automatic lock
|
|
self.automaticLock.allow();
|
|
|
|
// Check if automatic lock is locking
|
|
if(self.automaticLock.isLocking() === true) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Check if showing errors
|
|
if(showErrors === true) {
|
|
|
|
// Return showing message and allow showing messages
|
|
return self.message.show(self.getInitializeErrorHeader(), Message.createText(error), false, function() {
|
|
|
|
// Hide loading
|
|
self.application.hideLoading();
|
|
|
|
}, Language.getDefaultTranslation('OK'), Message.NO_BUTTON, true, Message.VISIBLE_STATE_UNLOCKED).then(function(messageResult) {
|
|
|
|
// Check if message was displayed
|
|
if(messageResult !== Message.NOT_DISPLAYED_RESULT) {
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Hide loading
|
|
self.application.hideLoading();
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Restore focus and don't blur
|
|
self.focus.restore(false);
|
|
}
|
|
|
|
// Set unlocked's wallet buttons aren't clicked
|
|
self.unlocked.walletsDisplay.find("div.list").find("button.clicked").removeClass("clicked");
|
|
|
|
// Update unlocked's wallets order buttons
|
|
self.unlocked.updateWalletsOrderButtons();
|
|
|
|
// Set that unlocked's menu display buttons aren't clicked
|
|
self.unlocked.menuDisplay.find("button").removeClass("clicked");
|
|
|
|
// Hide message
|
|
self.message.hide();
|
|
}
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Hide loading
|
|
self.application.hideLoading();
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Restore focus and don't blur
|
|
self.focus.restore(false);
|
|
}
|
|
|
|
// Reject error
|
|
reject(error);
|
|
}
|
|
};
|
|
|
|
// Return initializing
|
|
return self.initialize(state, false).then(function() {
|
|
|
|
// Check if updating the stack
|
|
if(updateStack === true) {
|
|
|
|
// Check if not saving the current display
|
|
if(saveCurrentDisplay === false) {
|
|
|
|
// Clear the stack
|
|
self.sections.clearStack();
|
|
}
|
|
|
|
// Return pushing state to stack
|
|
return self.sections.pushStateToStack(self).then(function() {
|
|
|
|
// Update navigation
|
|
self.updateNavigation();
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true)
|
|
|
|
// Hide loading
|
|
self.application.hideLoading();
|
|
|
|
// Check if is temporary
|
|
if(isTemporary === true) {
|
|
|
|
// Make unlocked display have a minimal interface
|
|
unlockedDisplay.addClass("minimal");
|
|
|
|
// Show unlocked display's sections display
|
|
unlockedDisplay.find("div.sections").children("div").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Make unlocked display not have a minimal interface
|
|
unlockedDisplay.removeClass("minimal");
|
|
}
|
|
|
|
// Check if not changing temporary
|
|
if(changingTemporary === false) {
|
|
|
|
// Show display
|
|
self.display.removeClass("hide");
|
|
|
|
// Trigger shown event
|
|
$(self).trigger(Section.SHOWN_EVENT);
|
|
|
|
// Display transition end or timeout event
|
|
self.display.transitionEndOrTimeout(function() {
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Allow automatic lock
|
|
self.automaticLock.allow();
|
|
|
|
// Check if automatic lock is locking
|
|
if(self.automaticLock.isLocking() === true) {
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Delete focus
|
|
self.focus.delete();
|
|
|
|
// Trigger focus event
|
|
$(self).trigger(Section.FOCUS_EVENT);
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Show display without transitioning
|
|
self.display.removeClass("hide").addClass("noTransition");
|
|
|
|
// Show unlocked display's children if it was temporarily hidden
|
|
unlockedDisplay.children().removeClass("temporaryHide");
|
|
|
|
// Trigger resize event
|
|
$(window).trigger("resize");
|
|
|
|
// Trigger shown event
|
|
$(self).trigger(Section.SHOWN_EVENT);
|
|
|
|
// Trigger unlocked show event
|
|
$(self.unlocked).trigger(Unlocked.SHOW_EVENT);
|
|
|
|
// Unlocked display's children transition end or timeout event
|
|
unlockedDisplay.children().transitionEndOrTimeout(function() {
|
|
|
|
// Allow display to transition
|
|
self.display.removeClass("noTransition");
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Allow automatic lock
|
|
self.automaticLock.allow();
|
|
|
|
// Check if automatic lock is locking
|
|
if(self.automaticLock.isLocking() === true) {
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Delete focus
|
|
self.focus.delete();
|
|
|
|
// Trigger focus event
|
|
$(self).trigger(Section.FOCUS_EVENT);
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Process error
|
|
processError(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return saving the stack
|
|
return self.sections.saveStack().then(function() {
|
|
|
|
// Update navigation
|
|
self.updateNavigation();
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true)
|
|
|
|
// Hide loading
|
|
self.application.hideLoading();
|
|
|
|
// Check if is temporary
|
|
if(isTemporary === true) {
|
|
|
|
// Make unlocked display have a minimal interface
|
|
unlockedDisplay.addClass("minimal");
|
|
|
|
// Show unlocked display's sections display
|
|
unlockedDisplay.find("div.sections").children("div").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Make unlocked display not have a minimal interface
|
|
unlockedDisplay.removeClass("minimal");
|
|
}
|
|
|
|
// Check if not changing temporary
|
|
if(changingTemporary === false) {
|
|
|
|
// Show display
|
|
self.display.removeClass("hide");
|
|
|
|
// Trigger shown event
|
|
$(self).trigger(Section.SHOWN_EVENT);
|
|
|
|
// Display transition end or timeout event
|
|
self.display.transitionEndOrTimeout(function() {
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Allow automatic lock
|
|
self.automaticLock.allow();
|
|
|
|
// Check if automatic lock is locking
|
|
if(self.automaticLock.isLocking() === true) {
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Delete focus
|
|
self.focus.delete();
|
|
|
|
// Trigger focus event
|
|
$(self).trigger(Section.FOCUS_EVENT);
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Show display without transitioning
|
|
self.display.removeClass("hide").addClass("noTransition");
|
|
|
|
// Show unlocked display's children
|
|
unlockedDisplay.children().removeClass("temporaryHide");
|
|
|
|
// Trigger resize event
|
|
$(window).trigger("resize");
|
|
|
|
// Trigger shown event
|
|
$(self).trigger(Section.SHOWN_EVENT);
|
|
|
|
// Trigger unlocked show event
|
|
$(self.unlocked).trigger(Unlocked.SHOW_EVENT);
|
|
|
|
// Unlocked display's children transition end or timeout event
|
|
unlockedDisplay.children().transitionEndOrTimeout(function() {
|
|
|
|
// Allow display to transition
|
|
self.display.removeClass("noTransition");
|
|
|
|
// Check if enabling after initializing
|
|
if(enableAfterInitializing === true) {
|
|
|
|
// Allow automatic lock
|
|
self.automaticLock.allow();
|
|
|
|
// Check if automatic lock is locking
|
|
if(self.automaticLock.isLocking() === true) {
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Enable unlocked
|
|
self.unlocked.enable();
|
|
|
|
// Delete focus
|
|
self.focus.delete();
|
|
|
|
// Trigger focus event
|
|
$(self).trigger(Section.FOCUS_EVENT);
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Process error
|
|
processError(error);
|
|
});
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Process error
|
|
processError(error);
|
|
});
|
|
};
|
|
|
|
// Get shown display
|
|
var shownDisplay = self.display.parent().children(":not(.hide)");
|
|
|
|
// Check if shown display doesn't exist
|
|
if(shownDisplay["length"] === 0) {
|
|
|
|
// Check if not changing temporary
|
|
if(changingTemporary === false) {
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if unlocked display's children is visible
|
|
if(unlockedDisplay.children().is(":visible") === true) {
|
|
|
|
// Temporarily hide unlocked display's children and transition end or timeout event
|
|
unlockedDisplay.children().addClass("temporaryHide").transitionEndOrTimeout(function() {
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Temporarily hide unlocked display's children
|
|
unlockedDisplay.children().addClass("temporaryHide");
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if not changing temporary
|
|
if(changingTemporary === false) {
|
|
|
|
// Check if shown display is visible
|
|
if(shownDisplay.is(":visible") === true) {
|
|
|
|
// Hide shown display and transition end or timeout event
|
|
shownDisplay.addClass("hide").transitionEndOrTimeout(function() {
|
|
|
|
// Get current section
|
|
var currentSection = self.sections.getSection(shownDisplay);
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Check if current section exists
|
|
if(currentSection !== Sections.NO_SECTION) {
|
|
|
|
// Reset the current section
|
|
currentSection.reset();
|
|
}
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Hide shown display
|
|
shownDisplay.addClass("hide");
|
|
|
|
// Get current section
|
|
var currentSection = self.sections.getSection(shownDisplay);
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Check if current section exists
|
|
if(currentSection !== Sections.NO_SECTION) {
|
|
|
|
// Reset the current section
|
|
currentSection.reset();
|
|
}
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if unlocked display's children is visible
|
|
if(unlockedDisplay.children().is(":visible") === true) {
|
|
|
|
// Temporarily hide unlocked display's children and transition end or timeout event
|
|
unlockedDisplay.children().addClass("temporaryHide").transitionEndOrTimeout(function() {
|
|
|
|
// Hide shown display without transitioning
|
|
shownDisplay.addClass("hide noTransition");
|
|
|
|
// Get current section
|
|
var currentSection = self.sections.getSection(shownDisplay);
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Allow shown display to transition
|
|
shownDisplay.removeClass("noTransition");
|
|
|
|
// Check if current section exists
|
|
if(currentSection !== Sections.NO_SECTION) {
|
|
|
|
// Reset the current section
|
|
currentSection.reset();
|
|
}
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
|
|
}, "opacity");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Temporarily hide unlocked display's children
|
|
unlockedDisplay.children().addClass("temporaryHide");
|
|
|
|
// Hide shown display
|
|
shownDisplay.addClass("hide");
|
|
|
|
// Get current section
|
|
var currentSection = self.sections.getSection(shownDisplay);
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Check if current section exists
|
|
if(currentSection !== Sections.NO_SECTION) {
|
|
|
|
// Reset the current section
|
|
currentSection.reset();
|
|
}
|
|
|
|
// Show section display
|
|
showSectionDisplay();
|
|
|
|
}, Section.SHOW_CURRENT_SECTION_DELAY_MILLISECONDS);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return initializing
|
|
return self.initialize(state, true).then(function() {
|
|
|
|
// Check if updating the stack
|
|
if(updateStack === true) {
|
|
|
|
// Check if not saving the current display
|
|
if(saveCurrentDisplay === false) {
|
|
|
|
// Clear the stack
|
|
self.sections.clearStack();
|
|
}
|
|
|
|
// Return pushing state to stack
|
|
return self.sections.pushStateToStack(self).then(function() {
|
|
|
|
// Update navigation
|
|
self.updateNavigation();
|
|
|
|
// Check if is temporary
|
|
if(isTemporary === true) {
|
|
|
|
// Make unlocked display have a minimal interface
|
|
unlockedDisplay.addClass("minimal");
|
|
|
|
// Show unlocked display's sections display
|
|
unlockedDisplay.find("div.sections").children("div").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Make unlocked display not have a minimal interface
|
|
unlockedDisplay.removeClass("minimal");
|
|
}
|
|
|
|
// Show display
|
|
self.display.removeClass("hide");
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return saving the stack
|
|
return self.sections.saveStack().then(function() {
|
|
|
|
// Update navigation
|
|
self.updateNavigation();
|
|
|
|
// Check if is temporary
|
|
if(isTemporary === true) {
|
|
|
|
// Make unlocked display have a minimal interface
|
|
unlockedDisplay.addClass("minimal");
|
|
|
|
// Show unlocked display's sections display
|
|
unlockedDisplay.find("div.sections").children("div").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Make unlocked display not have a minimal interface
|
|
unlockedDisplay.removeClass("minimal");
|
|
}
|
|
|
|
// Show display
|
|
self.display.removeClass("hide");
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reset
|
|
self.reset();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
// Get display
|
|
getDisplay() {
|
|
|
|
// Return display
|
|
return this.display;
|
|
}
|
|
|
|
// Get state
|
|
getState() {
|
|
|
|
// Check if shown
|
|
if(this.isShown() === true) {
|
|
|
|
// Update last scroll position
|
|
this.lastScrollPosition = this.display.scrollTop();
|
|
}
|
|
|
|
// Return state
|
|
return {
|
|
|
|
// Scroll position
|
|
[Section.STATE_SCROLL_POSITION_NAME]: this.lastScrollPosition,
|
|
|
|
// Elements states
|
|
[Section.STATE_ELEMENTS_STATES_NAME]: this.elementsStates
|
|
};
|
|
}
|
|
|
|
// Shown event
|
|
static get SHOWN_EVENT() {
|
|
|
|
// Return shown event
|
|
return "SectionShownEvent";
|
|
}
|
|
|
|
// Focus event
|
|
static get FOCUS_EVENT() {
|
|
|
|
// Return focus event
|
|
return "SectionFocusEvent";
|
|
}
|
|
|
|
// Protected
|
|
|
|
// Get sections
|
|
getSections() {
|
|
|
|
// Return sections
|
|
return this.sections;
|
|
}
|
|
|
|
// Get settings
|
|
getSettings() {
|
|
|
|
// Return settings
|
|
return this.settings;
|
|
}
|
|
|
|
// Get message
|
|
getMessage() {
|
|
|
|
// Return message
|
|
return this.message;
|
|
}
|
|
|
|
// Get focus
|
|
getFocus() {
|
|
|
|
// Return focus
|
|
return this.focus;
|
|
}
|
|
|
|
// Get application
|
|
getApplication() {
|
|
|
|
// Return application
|
|
return this.application;
|
|
}
|
|
|
|
// Get unlocked
|
|
getUnlocked() {
|
|
|
|
// Return unlocked
|
|
return this.unlocked;
|
|
}
|
|
|
|
// Get automatic lock
|
|
getAutomaticLock() {
|
|
|
|
// Return automatic lock
|
|
return this.automaticLock;
|
|
}
|
|
|
|
// Get scroll
|
|
getScroll() {
|
|
|
|
// Return scroll
|
|
return this.scroll;
|
|
}
|
|
|
|
// Get wallets
|
|
getWallets() {
|
|
|
|
// Return wallets
|
|
return this.wallets;
|
|
}
|
|
|
|
// Get node
|
|
getNode() {
|
|
|
|
// Return node
|
|
return this.node;
|
|
}
|
|
|
|
// Get wake lock
|
|
getWakeLock() {
|
|
|
|
// Return wake lock
|
|
return this.wakeLock;
|
|
}
|
|
|
|
// Get transactions
|
|
getTransactions() {
|
|
|
|
// Return transactions
|
|
return this.transactions;
|
|
}
|
|
|
|
// Get prices
|
|
getPrices() {
|
|
|
|
// Return prices
|
|
return this.prices;
|
|
}
|
|
|
|
// Get clipboard
|
|
getClipboard() {
|
|
|
|
// Return clipboard
|
|
return this.clipboard;
|
|
}
|
|
|
|
// Is shown
|
|
isShown() {
|
|
|
|
// Return if display is shown
|
|
return this.display.hasClass("hide") === false;
|
|
}
|
|
|
|
// Reset
|
|
reset() {
|
|
|
|
// Clear restoring state
|
|
this.restoringState = false;
|
|
|
|
// Blur display's focused element
|
|
this.display.find(":focus").blur();
|
|
|
|
// Hide navigation buttons
|
|
this.display.find("div.navigation").find("button").addClass("hide");
|
|
|
|
// Reset display scroll position
|
|
this.display.scrollTop(0);
|
|
}
|
|
|
|
// Initialize
|
|
initialize(state) {
|
|
|
|
// Set restoring state
|
|
this.restoringState = true;
|
|
|
|
// Get elements states from the state
|
|
this.elementsStates = (state !== Section.NO_STATE && Section.STATE_ELEMENTS_STATES_NAME in state === true) ? state[Section.STATE_ELEMENTS_STATES_NAME] : [];
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Turn off section shown section event
|
|
$(this).off(Section.SHOWN_EVENT + ".section");
|
|
|
|
// Turn off section focus section event
|
|
$(this).off(Section.FOCUS_EVENT + ".section");
|
|
|
|
// Section shown section event
|
|
$(this).one(Section.SHOWN_EVENT + ".section", function() {
|
|
|
|
// Get display's scroll position from the state
|
|
self.display.scrollTop((state !== Section.NO_STATE && Section.STATE_SCROLL_POSITION_NAME in state === true) ? state[Section.STATE_SCROLL_POSITION_NAME] : 0);
|
|
|
|
// Get elements
|
|
var elements = self.display.find("button, input, select, a");
|
|
|
|
// Go through all elements states
|
|
for(var i = 0; i < self.elementsStates["length"]; ++i) {
|
|
|
|
// Get element's state
|
|
var elementsState = self.elementsStates[i];
|
|
|
|
// Get element
|
|
var element = elements.eq(i);
|
|
|
|
// Check if element has the correct tag
|
|
if(element.prop("tagName") === elementsState["Tag"]) {
|
|
|
|
// Check element's tag
|
|
switch(elementsState["Tag"]) {
|
|
|
|
// Button
|
|
case "BUTTON":
|
|
|
|
// Check if element's state's value exists
|
|
if(elementsState["Value"] !== Section.NO_VALUE) {
|
|
|
|
// Check if element's state's value is true
|
|
if(elementsState["Value"] === true) {
|
|
|
|
// Set element's value
|
|
element.addClass("enabled");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set element's value
|
|
element.removeClass("enabled");
|
|
}
|
|
}
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Input
|
|
case "INPUT":
|
|
|
|
// Check if element's state's value exists
|
|
if(elementsState["Value"] !== Section.NO_VALUE) {
|
|
|
|
// Set element's value
|
|
element.val(elementsState["Value"]);
|
|
}
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Select
|
|
case "SELECT":
|
|
|
|
// Check if element's state's value exists
|
|
if(elementsState["Value"] !== Section.NO_VALUE) {
|
|
|
|
// Set element's value
|
|
element.val(elementsState["Value"]);
|
|
}
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Section section focus event
|
|
}).one(Section.FOCUS_EVENT + ".section", function() {
|
|
|
|
// Get elements
|
|
var elements = self.display.find("button, input, select, a");
|
|
|
|
// Set focused element exists
|
|
var focusedElementExists = false;
|
|
|
|
// Go through all elements states
|
|
for(var i = 0; i < self.elementsStates["length"]; ++i) {
|
|
|
|
// Get element's state
|
|
var elementsState = self.elementsStates[i];
|
|
|
|
// Get element
|
|
let element = elements.eq(i);
|
|
|
|
// Check if element has the correct tag
|
|
if(element.prop("tagName") === elementsState["Tag"]) {
|
|
|
|
// Check if element's state is focused and it can be tabbed to
|
|
if(elementsState["Focused"] === true && element.attr("tabindex") !== Common.NO_TAB_INDEX) {
|
|
|
|
// Check if element is visible
|
|
if(element.is(":visible") === true) {
|
|
|
|
// Focus on element
|
|
element.focus();
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Check if element isn't focused
|
|
if(element.is(":focus") === false) {
|
|
|
|
// Focus on element
|
|
element.focus();
|
|
|
|
// Get display's scroll position from the state
|
|
self.display.scrollTop((state !== Section.NO_STATE && Section.STATE_SCROLL_POSITION_NAME in state === true) ? state[Section.STATE_SCROLL_POSITION_NAME] : 0);
|
|
}
|
|
}, 0);
|
|
|
|
// Set focused element exists
|
|
focusedElementExists = true;
|
|
}
|
|
}
|
|
|
|
// Check element's tag
|
|
switch(elementsState["Tag"]) {
|
|
|
|
// Input
|
|
case "INPUT":
|
|
|
|
// Check if element's state's value exists
|
|
if(elementsState["Value"] !== Section.NO_VALUE) {
|
|
|
|
// Trigger input event on the element
|
|
element.trigger("input", [
|
|
|
|
// Is focus event
|
|
true,
|
|
|
|
// Force input
|
|
true
|
|
]);
|
|
}
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Check if element's state's selection start exists
|
|
if(elementsState["Selection Start"] !== Section.NO_VALUE) {
|
|
|
|
// Set element's selection start
|
|
element.get(0)["selectionStart"] = elementsState["Selection Start"];
|
|
}
|
|
|
|
// Check if element's state's selection end exists
|
|
if(elementsState["Selection End"] !== Section.NO_VALUE) {
|
|
|
|
// Set element's selection end
|
|
element.get(0)["selectionEnd"] = elementsState["Selection End"];
|
|
}
|
|
|
|
// Check if element's state's selection direction exists
|
|
if(elementsState["Selection Direction"] !== Section.NO_VALUE) {
|
|
|
|
// Set element's selection direction
|
|
element.get(0)["selectionDirection"] = elementsState["Selection Direction"];
|
|
}
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
}
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Select
|
|
case "SELECT":
|
|
|
|
// Check if element's state's value exists
|
|
if(elementsState["Value"] !== Section.NO_VALUE) {
|
|
|
|
// Trigger input event on the element
|
|
element.trigger("input");
|
|
}
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check if focused element exists
|
|
if(focusedElementExists === true) {
|
|
|
|
// Get display's scroll position from the state
|
|
self.display.scrollTop((state !== Section.NO_STATE && Section.STATE_SCROLL_POSITION_NAME in state === true) ? state[Section.STATE_SCROLL_POSITION_NAME] : 0);
|
|
}
|
|
|
|
// Clear restoring state
|
|
self.restoringState = false;
|
|
});
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Resolve
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
// Get initialize error header
|
|
getInitializeErrorHeader() {
|
|
|
|
// Return initialize error header
|
|
return "";
|
|
}
|
|
|
|
// Update state
|
|
updateState() {
|
|
|
|
// Update elements states
|
|
this.updateElementsStates();
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return updating state in stack
|
|
return self.sections.updateStateInStack(self).then(function() {
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Private
|
|
|
|
// Update navigation
|
|
updateNavigation() {
|
|
|
|
// Check if a previous section exists
|
|
if(this.sections.getStackIndex() - 1 > 0) {
|
|
|
|
// Show navigation back button
|
|
this.display.find("div.navigation").find("button.back").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Hide navigation back button
|
|
this.display.find("div.navigation").find("button.back").addClass("hide");
|
|
}
|
|
|
|
// Check if a next section exists
|
|
if(this.sections.getStackIndex() < this.sections.getStackLength()) {
|
|
|
|
// Show navigation forward button
|
|
this.display.find("div.navigation").find("button.forward").removeClass("hide");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Hide navigation forward button
|
|
this.display.find("div.navigation").find("button.forward").addClass("hide");
|
|
}
|
|
}
|
|
|
|
// Update elements states
|
|
updateElementsStates() {
|
|
|
|
// Clear elements states
|
|
this.elementsStates = [];
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Go through all applicable elements in the display
|
|
this.display.find("button, input, select, a").each(function() {
|
|
|
|
// Get element
|
|
var element = $(this);
|
|
|
|
// Initialize element's state
|
|
var elementsState = {
|
|
|
|
// Tag
|
|
"Tag": element.prop("tagName"),
|
|
|
|
// Focused
|
|
"Focused": element.is(":focus")
|
|
};
|
|
|
|
// Check element's tag
|
|
switch(element.prop("tagName")) {
|
|
|
|
// Button
|
|
case "BUTTON":
|
|
|
|
// Set element's state's value
|
|
elementsState["Value"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.hasClass("enabled") : Section.NO_VALUE;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Input
|
|
case "INPUT":
|
|
|
|
// Set element's state's value
|
|
elementsState["Value"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.val() : Section.NO_VALUE;
|
|
|
|
// Set element's state's selection start
|
|
elementsState["Selection Start"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.get(0)["selectionStart"] : Section.NO_VALUE;
|
|
|
|
// Set element's state's selection end
|
|
elementsState["Selection End"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.get(0)["selectionEnd"] : Section.NO_VALUE;
|
|
|
|
// Set element's state's selection direction
|
|
elementsState["Selection Direction"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.get(0)["selectionDirection"] : Section.NO_VALUE;
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Select
|
|
case "SELECT":
|
|
|
|
// Set element's state's value
|
|
elementsState["Value"] = (element.attr(Common.DATA_ATTRIBUTE_PREFIX + "private") === Common.NO_ATTRIBUTE) ? element.children(":selected").val() : Section.NO_VALUE;
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
|
|
// Append element's state to list
|
|
self.elementsStates.push(elementsState);
|
|
});
|
|
}
|
|
|
|
// Update dots
|
|
static updateDots(text) {
|
|
|
|
// Set text's width to overflow
|
|
text.addClass("overflow");
|
|
|
|
// Get the width of its child
|
|
var width = Math.ceil(text.children("span").get(0).getBoundingClientRect()["width"]) + "px";
|
|
|
|
// Set text's width and minimum width to the width of its child
|
|
text.css("width", width);
|
|
text.css("min-width", width);
|
|
|
|
// Prevent text's width from overflowing
|
|
text.removeClass("overflow");
|
|
|
|
// Get dots
|
|
var dots = text.siblings("span.dots");
|
|
|
|
// Show dots
|
|
dots.removeClass("hide");
|
|
|
|
// Check if dot's width is too small
|
|
if(dots.get(0).getBoundingClientRect()["width"] < parseFloat(dots.css("font-size")) * Section.SETTINGS_DOTS_MINIMUM_WIDTH) {
|
|
|
|
// Hide dots
|
|
dots.addClass("hide");
|
|
}
|
|
}
|
|
|
|
// Show current section delay milliseconds
|
|
static get SHOW_CURRENT_SECTION_DELAY_MILLISECONDS() {
|
|
|
|
// Return show current section delay milliseconds
|
|
return 150;
|
|
}
|
|
|
|
// No state
|
|
static get NO_STATE() {
|
|
|
|
// Return no state
|
|
return null;
|
|
}
|
|
|
|
// Settings dots minimum width
|
|
static get SETTINGS_DOTS_MINIMUM_WIDTH() {
|
|
|
|
// Return settings dots minimum width
|
|
return parseFloat("1.7em");
|
|
}
|
|
|
|
// State scroll position name
|
|
static get STATE_SCROLL_POSITION_NAME() {
|
|
|
|
// Return state scroll position name
|
|
return "Scroll Position";
|
|
}
|
|
|
|
// State elements states name
|
|
static get STATE_ELEMENTS_STATES_NAME() {
|
|
|
|
// Return state elements states name
|
|
return "Elements States";
|
|
}
|
|
|
|
// No value
|
|
static get NO_VALUE() {
|
|
|
|
// Return no value
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's section
|
|
globalThis["Section"] = Section;
|