// Use strict "use strict"; // Classes // Send payment section class class SendPaymentSection extends Section { // Public // Constructor constructor(display, sections, settings, message, focus, application, unlocked, automaticLock, scroll, wallets, node, wakeLock, transactions, prices, clipboard) { // Delegate constructor super(display, sections, settings, message, focus, application, unlocked, automaticLock, scroll, wallets, node, wakeLock, transactions, prices, clipboard); // Set wallet key path this.walletKeyPath = WalletSection.NO_WALLET_KEY_PATH; // Set amount last changed this.amountLastChanged = true; // Set allow changing base fee to setting's default value this.allowChangingBaseFee = SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_DEFAULT_VALUE; // Set step var step = Consensus.VALUE_NUMBER_BASE.toFixed()["length"] - 1; // Set amount input's and base fee's step and min to the step this.getDisplay().find("input.amount").attr("step", (new BigNumber(10)).exponentiatedBy(-step).toFixed()).attr("min", (new BigNumber(10)).exponentiatedBy(-step).toFixed()); this.getDisplay().find("input.baseFee").attr("step", (new BigNumber(10)).exponentiatedBy(-step).toFixed()).attr("min", (new BigNumber(10)).exponentiatedBy(-step).toFixed()); // Set self var self = this; // Once database is initialized Database.onceInitialized(function() { // Return promise return new Promise(function(resolve, reject) { // Return creating settings return Promise.all([ // Allow changing base fee setting self.getSettings().createValue(SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_NAME, SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_DEFAULT_VALUE) ]).then(function() { // Initialize settings var settings = [ // Allow changing base fee setting SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_NAME ]; // Return getting settings' values return Promise.all(settings.map(function(setting) { // Return getting setting's value return self.getSettings().getValue(setting); })).then(function(settingValues) { // Set allow changing base fee to setting's value self.allowChangingBaseFee = settingValues[settings.indexOf(SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_NAME)]; // Resolve resolve(); // Catch errors }).catch(function(error) { // Reject reject(); }); // Catch errors }).catch(function(error) { // Reject reject(); }); }); }); // Settings change event $(this.settings).on(Settings.CHANGE_EVENT, function(event, setting) { // Check what setting was changes switch(setting[Settings.DATABASE_SETTING_NAME]) { // Allow changing base fee setting case SendPaymentSection.SETTINGS_ALLOW_CHANGING_BASE_FEE_NAME: // Set allow changing base fee to setting's value self.allowChangingBaseFee = setting[Settings.DATABASE_VALUE_NAME]; // Break break; } }); // Value display text on language change event self.getDisplay().find("input.value").parent().siblings("p").on(Language.CHANGE_EVENT, function() { // Check if shown if(self.isShown() === true) { // Update value currency self.updateValueCurrency(); // Update value input self.updateValueInput(); } }); // Prices change event $(this.getPrices()).on(Prices.CHANGE_EVENT, function(event, prices) { // Check if shown if(self.isShown() === true) { // Update value currency self.updateValueCurrency(); // Update value input self.updateValueInput(); } }); // Input input event this.getDisplay().find("input").on("input", function(event, isFocusEvent, forceInput) { // Get input var input = $(this); // Check if input has focus or forcing input if(input.is(":focus") === true || forceInput === true) { // Check if not focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Set amount last changed self.amountLastChanged = true; } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Set amount last changed self.amountLastChanged = false; } } // Get input's display var display = input.closest("div").parent().closest("div"); // Get input's value var value = input.val(); // Check if value doesn't exist, input doesn't have focus, and forcing input if(value["length"] === 0 && input.is(":focus") === false && forceInput === true) { // Set that display doesn't show an error display.removeClass("error"); // Check if amount was changed if(input.hasClass("amount") === true) { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } // Otherwise else { // Check type switch(display.find("div.value").attr(Common.DATA_ATTRIBUTE_PREFIX + "type")) { // Number case "number": // Check if value is in scientific notation if(value.indexOf("e") !== Common.INDEX_NOT_FOUND) { // Get value's parts var parts = value.split("e"); // Get parts as a number var number = (new BigNumber(parts[0])).multipliedBy((new BigNumber(Common.DECIMAL_NUMBER_BASE)).exponentiatedBy((parts["length"] >= 2) ? parts[1] : 0)); // Set input's value to the number input.val(number.toFixed()); // Update value value = (new BigNumber(input.val())).toFixed(); } // Check if value isn't a number if(Common.isNumberString(value) === false) { // Set that display shows an error display.addClass("error"); // Check if not a focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } // Return return; } // Get value as a number value = new BigNumber(value); // Check if has a step and the input isn't for the value var step = input.attr("step"); if(step !== Common.NO_ATTRIBUTE && input.hasClass("value") === false) { // Get step as a number step = new BigNumber(step); // Check if value isn't evenly divisible by the step if(value.modulo(step).isInteger() === false) { // Set that display shows an error display.addClass("error"); // Check if not a focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } // Return return; } } // Check if has a minimum value var minimumValue = input.attr("min"); if(minimumValue !== Common.NO_ATTRIBUTE) { // Get minimum value as a number minimumValue = new BigNumber(minimumValue); // Check if value is less than the minimum value if(value.isLessThan(minimumValue) === true) { // Set that display shows an error display.addClass("error"); // Check if not a focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } // Return return; } } // Check if has a maximum value var maximumValue = input.attr("max"); if(maximumValue !== Common.NO_ATTRIBUTE) { // Get maximum value as a number maximumValue = new BigNumber(maximumValue); // Check if value is greater than the maximum value if(value.isGreaterThan(maximumValue) === true) { // Set that display shows an error display.addClass("error"); // Check if not a focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } // Return return; } } // Break break; // URL case "url": // Check if recipient address wasn't changed, or value doesn't exist, or not sending as file if(input.hasClass("recipientAddress") === false || value["length"] !== 0 || self.getDisplay().find("button.sendAsFile").hasClass("enabled") === false) { // Check if value isn't a valid URL if(Common.isValidUrl(value) === false) { // Set that display shows an error display.addClass("error"); // Return return; } } // Break break; } // Set that display doesn't shows an error display.removeClass("error"); // Check if not a focus event if(isFocusEvent !== true) { // Check if amount was changed if(input.hasClass("amount") === true) { // Get currency var currency = self.getUnlocked().getDisplayedCurrency(); // Get price in the currency var price = self.getPrices().getPrice(currency); // Check if price exists if(price !== Prices.NO_PRICE_FOUND) { // Set value input's value to the value multipled by the price and have it not show an error self.getDisplay().find("input.value").val(value.multipliedBy(price).toFixed()).closest("div").parent().closest("div").removeClass("error"); } // Otherwise else { // Clear value input and have it not show an error self.getDisplay().find("input.value").val("").closest("div").parent().closest("div").removeClass("error"); } } // Otherwise check if value was changed else if(input.hasClass("value") === true) { // Get currency var currency = self.getUnlocked().getDisplayedCurrency(); // Get price in the currency var price = self.getPrices().getPrice(currency); // Check if price exists if(price !== Prices.NO_PRICE_FOUND) { // Check if price is zero if(price.isZero() === true) { // Set amount input's value to zero and have it show an error self.getDisplay().find("input.amount").val("0").closest("div").parent().closest("div").addClass("error"); } // Otherwise else { // Set amount input's value to the value divided by the price self.getDisplay().find("input.amount").val(Common.removeTrailingZeros(value.dividedBy(price).toFixed(Consensus.VALUE_NUMBER_BASE.toFixed()["length"] - 1, BigNumber.ROUND_UP))); // Check if amount input's value is zero if(self.getDisplay().find("input.amount").val() === "0") { // Have amount input show an error self.getDisplay().find("input.amount").closest("div").parent().closest("div").addClass("error"); } // Otherwise else { // Have amount input not show an error self.getDisplay().find("input.amount").closest("div").parent().closest("div").removeClass("error"); } } } // Otherwise else { // Clear amount input and have it not show an error self.getDisplay().find("input.amount").val("").closest("div").parent().closest("div").removeClass("error"); } } } } } // Input key down event }).on("keydown", function(event) { // Check if enter was pressed if(event["which"] === "\r".charCodeAt(0)) { // Get input var input = $(this); // Get input's display var display = input.closest("div").parent().closest("div"); // Check if display doesn't show an error if(display.hasClass("error") === false) { // Trigger click on send button self.getDisplay().find("button.send").trigger("click"); } } // Input key press event }).on("keypress", function(event) { // Get input var input = $(this); // Get input's display var display = input.closest("div").parent().closest("div"); // Check if type is a number if(display.find("div.value").attr(Common.DATA_ATTRIBUTE_PREFIX + "type") === "number") { // Check if key isn't a number, a period, or a comma if((event["which"] < "0".charCodeAt(0) || event["which"] > "9".charCodeAt(0)) && event["which"] !== ".".charCodeAt(0) && event["which"] !== ",".charCodeAt(0)) { // Prevent default event.preventDefault(); } } // Input blur event }).on("blur", function() { // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Get input var input = $(this); // Get input's display var display = input.closest("div").parent().closest("div"); // Check if value is empty if(input.val()["length"] === 0) { // Set that display doesn't shows an error display.removeClass("error"); } } // Input focus event }).on("focus", function(event) { // Get input var input = $(this); // Get input's display var display = input.closest("div").parent().closest("div"); // Check if display isn't disabled if(display.hasClass("disabled") === false) { // Trigger input event input.trigger("input", [ // Is focus event true ]); } }); // Recipient address input paste event this.getDisplay().find("input.recipientAddress").on("paste", function(event) { // Get input var input = $(this); // Check if input is empty or all of its contents are selected if(input.val()["length"] === 0 || (typeof getSelection !== "undefined" && input.val() === getSelection().toString())) { // Prevent default event.preventDefault(); // Get clipboard data var value = event["originalEvent"]["clipboardData"].getData("text/plain"); // Remove handled protocols from value value = ProtocolHandler.standardizeUrlProtocol(value); // Set recipient address to the value input.val(value).trigger("input", [ // Is focus event false, // Force input true ]); // Scroll to end of input input.scrollLeft(input.get(0)["scrollWidth"]); // Check if get selection is supported if(typeof getSelection !== "undefined") { // Check if selection exists if(getSelection()["rangeCount"] > 0) { // Collapse selection to end getSelection().collapseToEnd(); } } } }); // Scan QR code button click event this.getDisplay().find("button.scan").on("click", function() { // Get button var button = $(this); // Prevent showing messages self.getMessage().prevent(); // Save focus and blur self.getFocus().save(true); // Set that button is clicked button.addClass("clicked"); // Disable unlocked self.getUnlocked().disable(); // Show loading self.getApplication().showLoading(); // Set that button is loading button.addClass("loading"); // Show scan error var showScanError = function(message) { // Show message immediately and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Scan QR Code Error'), message, true, function() { // Hide loading self.getApplication().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) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } }); }; // Try try { // Prevent automatic lock self.getAutomaticLock().prevent(); // Request access to camera navigator["mediaDevices"].getUserMedia({ // Audio "audio": false, // Video "video": { // Facing mode "facingMode": "environment" } }).then(function(stream) { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Initialize cancel occurred var cancelOccurred = false; // Show message and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Scan QR Code'), Message.createCamera(), false, function() { // Hide loading self.getApplication().hideLoading(); // Message before show not cancelable send section event $(self.getMessage()).one(Message.BEFORE_SHOW_NOT_CANCELABLE_EVENT + ".sendPaymentSection", function() { // Set that message has a camera self.getMessage().hasCamera(); // Get camera var camera = self.getMessage().getCamera(); // Set camera's source to the stream camera["srcObject"] = stream; // Play video var playVideo = camera.play(); // Check if play video is a promise if(playVideo instanceof Promise === true) { // Catch errors playVideo.catch(function() { // Play video camera.play(); }); } // Message show send section event $(self.getMessage()).one(Message.SHOW_EVENT + ".sendPaymentSection", function() { // Prevent automatic lock self.getAutomaticLock().prevent(); // Keep device awake and catch errors self.getWakeLock().preventLock().catch(function(error) { }); // Decode QR code var decodeQrCode = function() { // Check if not canceled if(cancelOccurred === false) { // Get value from video's frame Camera.getValue(camera, camera["srcObject"].getVideoTracks()[0].getSettings()["width"], camera["srcObject"].getVideoTracks()[0].getSettings()["height"]).then(function(value) { // Check if not canceled if(cancelOccurred === false) { // Check if value exists if(value !== Camera.NO_VALUE && value["length"] !== 0) { // Initialize value processed var valueProcessed = false; // Check if value is JSON if(value[0] === "{") { // Initialize error occurred var errorOccurred = false; // Try try { // Parse value as json var parsedValue = JSON.parse(value); } // Catch errors catch(error) { // Set error occurred errorOccurred = true; } // Check if an error didn't occur if(errorOccurred === false) { // Check if parsed value's recipient address isn't valid if("Recipient Address" in parsedValue === false || typeof parsedValue["Recipient Address"] !== "string" || parsedValue["Recipient Address"]["length"] === 0) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise check if parsed value's amount isn't valid else if("Amount" in parsedValue === true && (Common.isNumberString(parsedValue["Amount"]) === false || Common.getNumberStringPrecision(parsedValue["Amount"]) > Extension.MAXIMUM_AMOUNT_PRECISION || parseFloat(Common.removeTrailingZeros(parsedValue["Amount"])) < Extension.MINIMUM_AMOUNT)) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise check if parsed value's message isn't valid else if("Message" in parsedValue === true && typeof parsedValue["Message"] !== "string") { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise else { // Set value to the recipient address value = parsedValue["Recipient Address"]; // Check if parsed value contains an amount if("Amount" in parsedValue === true) { // Set amount input's value to the amount self.getDisplay().find("input.amount").val((new BigNumber(parsedValue["Amount"])).toFixed()).trigger("input", [ // Is focus event false, // Force input true ]); } // Otherwise else { // Set amount input's value to the nothing self.getDisplay().find("input.amount").val("").trigger("input", [ // Is focus event false, // Force input true ]); } // Check if parsed value contains a message and message input isn't hidden if("Message" in parsedValue === true && self.getDisplay().find("input.message").closest("div").parent().closest("div").hasClass("hide") === false) { // Set message input's value to the message self.getDisplay().find("input.message").val(parsedValue["Message"]).trigger("input", [ // Is focus event false, // Force input true ]); } // Otherwise else { // Set message input's value to nothing self.getDisplay().find("input.message").val("").trigger("input", [ // Is focus event false, // Force input true ]); } // Set send as file button to off self.getDisplay().find("button.sendAsFile").removeClass("enabled"); // Set value processed to true valueProcessed = true; } } } // Check if value wasn't processed if(valueProcessed === false) { // Check wallet type switch(Consensus.getWalletType()) { // EPIC wallet case Consensus.EPIC_WALLET_TYPE: // Get value's components var valueComponents = value.split("*"); // Check if value has the expected number of components if(valueComponents["length"] === 3) { // Check if value's recipient address component isn't valid if(valueComponents[0]["length"] === 0) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise check if value's amount component isn't valid else if(Common.isNumberString(valueComponents[2]) === false || Common.getNumberStringPrecision(valueComponents[2]) > Extension.MAXIMUM_AMOUNT_PRECISION || parseFloat(Common.removeTrailingZeros(valueComponents[2])) < Extension.MINIMUM_AMOUNT) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise check if value's message component isn't valid else if(/^ID: .* [^ ]+: .+$/u.test(valueComponents[1]) !== true && /^.*#[^ ]+: .+$/u.test(valueComponents[1]) !== true) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('That QR code is invalid.'))); } } }); // Return return; } // Otherwise else { // Set value to the recipient address value = valueComponents[0]; // Set amount input's value to the amount self.getDisplay().find("input.amount").val((new BigNumber(valueComponents[2])).toFixed()).trigger("input", [ // Is focus event false, // Force input true ]); // Set message input's value to the message self.getDisplay().find("input.message").val(valueComponents[1].match((/^ID: .* [^ ]+: .+$/u.test(valueComponents[1]) === true) ? /^ID: (.*) [^ ]+: .+$/u : /^(.*)#[^ ]+: .+$/u)[1]).trigger("input", [ // Is focus event false, // Force input true ]); // Set send as file button to off self.getDisplay().find("button.sendAsFile").removeClass("enabled"); // Set value processed to true valueProcessed = true; } } // Break break; } } // Check wallet type switch(Consensus.getWalletType()) { // EPIC wallet case Consensus.EPIC_WALLET_TYPE: // Initialize error occurred var errorOccurred = false; // Try try { // Parse values as a URL var parsedUrl = new URL(value); } // Catch errors catch(error) { // Set error occurred errorOccurred = true; } // Check if an error didn't occur if(errorOccurred === false) { // Check if parsed URL's protocol isn't needed if(parsedUrl["protocol"] === "epic:") { // Remove protocol from value value = Common.ltrim(value).substring("epic:"["length"]); } } // Break break; } // Remove handled protocols from value value = ProtocolHandler.standardizeUrlProtocol(value); // Set recipient address to the value self.getDisplay().find("input.recipientAddress").val(value).trigger("input", [ // Is focus event false, // Force input true ]); // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Delete focus self.getFocus().delete(); // Hide message self.getMessage().hide(); } }); } // Otherwise else { // Decode QR code decodeQrCode(); } } // Otherwise else { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Enable automatic lock self.getAutomaticLock().allow(); }); } // Catch errors }).catch(function(error) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if not canceled if(cancelOccurred === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('An error occurred while trying to access your camera.'))); } } }); }); } // Otherwise else { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Enable automatic lock self.getAutomaticLock().allow(); }); } }; // Decode QR code decodeQrCode(); }); }); }, Language.getDefaultTranslation('Cancel'), Message.NO_BUTTON, true, Message.VISIBLE_STATE_UNLOCKED).then(function(messageResult) { // Turn off message before show not cancelable send section event $(self.getMessage()).off(Message.BEFORE_SHOW_NOT_CANCELABLE_EVENT + ".sendPaymentSection"); // Set cancel occurred cancelOccurred = true; // Check if message was displayed if(messageResult !== Message.NOT_DISPLAYED_RESULT) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide().then(function() { // Stop camera stream.getVideoTracks()[0].stop(); }); } // Otherwise else { // Stop camera stream.getVideoTracks()[0].stop(); } }); } // Catch errors }).catch(function(error) { // Request animation frame requestAnimationFrame(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if access to the camera was denied if(error["name"] === "NotAllowedError") { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('Access to your camera was denied.'))); } // Otherwise check if no camera was found else if(error["name"] === "NotFoundError") { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('No camera was found. Connect a camera to use this feature.'))); } // Otherwise check if browser doesn't allow using a camera else if(error["name"] === "NotSupportedError") { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('Your browser doesn\'t allow using a camera.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Update your browser to use this feature.'))); } // Otherwise an error occurred while trying to access the camera else { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('An error occurred while trying to access your camera.'))); } } }); }); } // Catch errors catch(error) { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Show scan error showScanError(Message.createText(Language.getDefaultTranslation('Your browser doesn\'t allow using a camera.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Update your browser to use this feature.'))); } } }); // All button click event this.getDisplay().find("button.all").on("click", function() { // Get button var button = $(this); // Prevent showing messages self.getMessage().prevent(); // Save focus and blur self.getFocus().save(true); // Set that button is clicked button.addClass("clicked"); // Disable unlocked self.getUnlocked().disable(); // Show loading self.getApplication().showLoading(); // Set that button is loading button.addClass("loading"); // Show all error var showAllError = function(error) { // Show message and allow showing messages self.getMessage().show(Language.getDefaultTranslation('All Error'), Message.createText(error), false, function() { // Hide loading self.getApplication().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) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } }); }; // Check if base fee can be changed and base fee doesn't exist if(self.allowChangingBaseFee === true && self.getDisplay().find("input.baseFee").val()["length"] === 0) { // Show all error showAllError(Language.getDefaultTranslation('Base fee is empty.')); } // Otherwise else { // Get base fee var baseFee = (self.allowChangingBaseFee === true) ? (new BigNumber(self.getDisplay().find("input.baseFee").val())).multipliedBy(Consensus.VALUE_NUMBER_BASE) : Api.DEFAULT_BASE_FEE; // Try try { // Get wallet with the wallet key path or the selected from wallet var wallet = self.getWallets().getWallet((self.walletKeyPath !== WalletSection.NO_WALLET_KEY_PATH) ? self.walletKeyPath : parseInt(self.getDisplay().find("select.fromWallet").children(":selected").val(), Common.DECIMAL_NUMBER_BASE)); } // Catch errors catch(error) { // Show all error showAllError(error); // Return return; } // Prevent automatic lock self.getAutomaticLock().prevent(); // Get fee for all amount with the base fee self.getWallets().getFee(wallet.getKeyPath(), Api.ALL_AMOUNT, baseFee).then(function(fee) { // Set timeout setTimeout(function() { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Get amount as the wallet's unspent amount without the fee var amount = wallet.getUnspentAmount().minus(fee[Api.FEE_FEE_INDEX]); // Set amount input's value to the amount self.getDisplay().find("input.amount").val(amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed()).trigger("input", [ // Is focus event false, // Force input true ]); // Hide loading self.getApplication().hideLoading(); // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Delete focus self.getFocus().delete(); // Allow showing messages self.getMessage().allow(); } }, SendPaymentSection.ALL_RESULT_DELAY_MILLISECONDS); // Catch errors }).catch(function(error) { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Show all error showAllError(error); } }); } }); // Default base fee button click event this.getDisplay().find("button.defaultBaseFee").on("click", function() { // Get button var button = $(this); // Prevent showing messages self.getMessage().prevent(); // Save focus and blur self.getFocus().save(true); // Set that button is clicked button.addClass("clicked"); // Disable unlocked self.getUnlocked().disable(); // Show loading self.getApplication().showLoading(); // Set that button is loading button.addClass("loading"); // Prevent automatic lock self.getAutomaticLock().prevent(); // Set timeout setTimeout(function() { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Set base fee to the default base fee self.getDisplay().find("input.baseFee").val(Api.DEFAULT_BASE_FEE.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed()).trigger("input", [ // Is focus event false, // Force input true ]); // Hide loading self.getApplication().hideLoading(); // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Delete focus self.getFocus().delete(); // Allow showing messages self.getMessage().allow(); } }, SendPaymentSection.DEFAULT_BASE_FEE_DELAY_MILLISECONDS); }); // Boolean buttons click event this.getDisplay().find("div[data-type=\"boolean\"]").find("button").on("click", function() { // Get button var button = $(this); // Prevent showing messages self.getMessage().prevent(); // Save focus and blur self.getFocus().save(true); // Set that button is clicked button.addClass("clicked"); // Disable unlocked self.getUnlocked().disable(); // Prevent automatic lock self.getAutomaticLock().prevent(); // Check if button is enabled if(button.hasClass("enabled") === true) // Set that button isn't enabled button.removeClass("enabled"); // Otherwise else // Set that button is enabled button.addClass("enabled"); // Update state and catch errors self.updateState().catch(function(error) { }); // Button transition end or timeout event button.transitionEndOrTimeout(function() { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Allow showing messages self.getMessage().allow(); } }, "background"); }); // Send button click event this.getDisplay().find("button.send").on("click", function() { // Get button var button = $(this); // Prevent showing messages self.getMessage().prevent(); // Save focus, blur, and get focused element var focusedElement = self.getFocus().save(true); // Check if focused element is the button if(focusedElement !== Focus.NO_FOCUS && focusedElement.is(button) === true) { // Set that button is clicked button.addClass("clicked"); } // Disable unlocked self.getUnlocked().disable(); // Show loading self.getApplication().showLoading(); // Set that button is loading button.addClass("loading"); // Set recipient address var recipientAddress = self.getDisplay().find("input.recipientAddress").val().trim(); // Set message var message = (self.getDisplay().find("input.message").val()["length"] !== 0) ? self.getDisplay().find("input.message").val() : SlateParticipant.NO_MESSAGE; // Set send as file var sendAsFile = self.getDisplay().find("button.sendAsFile").hasClass("enabled") === true; // Show send error var showSendError = function(message) { // Show message immediately and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Send Error'), message, true, function() { // Hide loading self.getApplication().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) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } }); }; // Check if not sending as file and recipient address doesn't exist if(sendAsFile === false && recipientAddress["length"] === 0) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Recipient address is empty.'))); } // Otherwise check if recipient address shows an error else if(self.getDisplay().find("input.recipientAddress").closest("div").parent().closest("div").hasClass("error") === true) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Recipient address is invalid.'))); } // Otherwise check if amount doesn't exist else if(self.getDisplay().find("input.amount").val()["length"] === 0) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Amount is empty.'))); } // Otherwise check if amount shows an error else if(self.getDisplay().find("input.amount").closest("div").parent().closest("div").hasClass("error") === true) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Amount is invalid.'))); } // Otherwise check if base fee can be changed and base fee doesn't exist else if(self.allowChangingBaseFee === true && self.getDisplay().find("input.baseFee").val()["length"] === 0) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Base fee is empty.'))); } // Otherwise check if base fee can be changed and base fee shows an error else if(self.allowChangingBaseFee === true && self.getDisplay().find("input.baseFee").closest("div").parent().closest("div").hasClass("error") === true) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Base fee is invalid.'))); } // Otherwise else { // Set amount var amount = (new BigNumber(self.getDisplay().find("input.amount").val())).multipliedBy(Consensus.VALUE_NUMBER_BASE); // Base fee var baseFee = (self.allowChangingBaseFee === true) ? (new BigNumber(self.getDisplay().find("input.baseFee").val())).multipliedBy(Consensus.VALUE_NUMBER_BASE) : Api.DEFAULT_BASE_FEE; // Check wallet type switch(Consensus.getWalletType()) { // MWC or GRIN wallet case Consensus.MWC_WALLET_TYPE: case Consensus.GRIN_WALLET_TYPE: // Clear send as MQS var sendAsMqs = false; // Break break; // EPIC wallet case Consensus.EPIC_WALLET_TYPE: // Set send as MQS to if the URL is an MQS address with host var sendAsMqs = Mqs.isValidAddressWithHost(recipientAddress, Consensus.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE) === true; // Break break; } // Check if not sending as file or as MQS if(sendAsFile === false && sendAsMqs === false) { // Check wallet type switch(Consensus.getWalletType()) { // MWC or EPIC wallet case Consensus.MWC_WALLET_TYPE: case Consensus.EPIC_WALLET_TYPE: // Initialize error occurred var errorOccurred = false; // Try try { // Get receiver's Tor address from recipient address Tor.getTorAddressFromUrl(recipientAddress); } // Catch errors catch(error) { // Set error occurred errorOccurred = true; } // Check if an error didn't occur if(errorOccurred === false) { // Set receiver URL to the recipient address with a Tor protocol and top-level domain added if needed var receiverUrl = ((Common.urlContainsProtocol(recipientAddress) === false) ? Common.HTTP_PROTOCOL + "//" : "") + recipientAddress + ((Common.urlContainsProtocol(recipientAddress) === false && Common.urlContainsTopLevelDomain(recipientAddress) === false) ? Tor.URL_TOP_LEVEL_DOMAIN : ""); } // Otherwise else { // Set receiver URL to recipient address var receiverUrl = recipientAddress; } // break break; // GRIN wallet case Consensus.GRIN_WALLET_TYPE: // Initialize error occurred var errorOccurred = false; // Try try { // Parse the recipient address as a Slatepack address var receiverPublicKey = Slatepack.slatepackAddressToPublicKey(recipientAddress); } // Catch errors catch(error) { // Set error occurred errorOccurred = true; } // Check if an error didn't occur if(errorOccurred === false) { // Set receiver URL to the receiver's public key as a Tor address with a Tor protocol and top-level domain added var receiverUrl = Common.HTTP_PROTOCOL + "//" + Tor.publicKeyToTorAddress(receiverPublicKey) + Tor.URL_TOP_LEVEL_DOMAIN; } // Otherwise else { // Set receiver URL to recipient address var receiverUrl = recipientAddress; } // Break break; } // Check if receiver URL doesn't have a protocol if(Common.urlContainsProtocol(receiverUrl) === false) { // Add protocol to receiver URL receiverUrl = Common.HTTP_PROTOCOL + "//" + receiverUrl; } // Try try { // Parse receiver URL var parsedUrl = new URL(Common.upgradeApplicableInsecureUrl(receiverUrl)); } // Catch errors catch(error) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Recipient address isn\'t supported.'))); // Return return; } } // Try try { // Get wallet with the wallet key path or the selected from wallet var wallet = self.getWallets().getWallet((self.walletKeyPath !== WalletSection.NO_WALLET_KEY_PATH) ? self.walletKeyPath : parseInt(self.getDisplay().find("select.fromWallet").children(":selected").val(), Common.DECIMAL_NUMBER_BASE)); } // Catch errors catch(error) { // Show send error showSendError(Message.createText(error)); // Return return; } // Check if not sending as file or as MQS if(sendAsFile === false && sendAsMqs === false) { // Check if wallet has an address suffix if(wallet.getAddressSuffix() !== Wallet.NO_ADDRESS_SUFFIX) { // Try try { // Parse wallet's address suffix as a URL var walletUrl = new URL(wallet.getAddressSuffix()); // Check if sending to self if(parsedUrl["origin"] === walletUrl["origin"] && Common.removeTrailingSlashes(Common.removeDuplicateSlashes(parsedUrl["pathname"])) === walletUrl["pathname"]) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('A wallet can\'t send payments to itself.'))); // Return return; } } // Catch errors catch(error) { // Check if sending to self if((parsedUrl["origin"] === HTTPS_SERVER_ADDRESS || parsedUrl["origin"] === TOR_SERVER_ADDRESS) && Common.removeTrailingSlashes(Common.removeDuplicateSlashes(parsedUrl["pathname"])) === "/wallet/" + wallet.getAddressSuffix()) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('A wallet can\'t send payments to itself.'))); // Return return; } } } } // Check if wallet isn't synced if(wallet.isSynced() === false) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('The wallet isn\'t synced.'))); } // Otherwise check if current height doesn't exist or the node isn't synced else if(self.getNode().getCurrentHeight().getHeight() === Node.UNKNOWN_HEIGHT || self.getNode().getCurrentHeight().getHeight().isEqualTo(Consensus.FIRST_BLOCK_HEIGHT) === true) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('The current height is unknown.'))); } // Otherwise else { // Prevent automatic lock self.getAutomaticLock().prevent(); // Get fee for the amount with the base fee self.getWallets().getFee(wallet.getKeyPath(), amount, baseFee).then(function(fee) { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Get fee fee = fee[Api.FEE_FEE_INDEX]; // Show message and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Confirm Payment Details'), Message.createText((wallet.getName() === Wallet.NO_NAME) ? ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('You\'ll be sending %1$c from Wallet %2$s to the following address for a fee of %3$c.') : Language.getDefaultTranslation('You\'ll be sending %1$c from Wallet %2$s for a fee of %3$c.')) : ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('You\'ll be sending %1$c from %2$y to the following address for a fee of %3$c.') : Language.getDefaultTranslation('You\'ll be sending %1$c from %2$y for a fee of %3$c.')), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Wallet key path or name (wallet.getName() === Wallet.NO_NAME) ? wallet.getKeyPath().toFixed() : wallet.getName(), [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + ((recipientAddress["length"] !== 0) ? Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(recipientAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() + Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('(?<=.) '))) + Message.createText(Language.getDefaultTranslation('Enter your password to continue sending the payment.')) + Message.createLineBreak() + Message.createLineBreak() + Message.createInput(Language.getDefaultTranslation('Password'), [], true) + Message.createLineBreak(), false, function() { // Hide loading self.getApplication().hideLoading(); }, Language.getDefaultTranslation('Cancel'), Language.getDefaultTranslation('Continue'), true, Message.VISIBLE_STATE_UNLOCKED).then(function(messageResult) { // Check if message was displayed if(messageResult !== Message.NOT_DISPLAYED_RESULT) { // Check if continuing if(messageResult === Message.SECOND_BUTTON_CLICKED_RESULT) { // Prevent showing messages self.getMessage().prevent(); // Try try { // Get password var password = self.getMessage().getInputText(); } // Catch errors catch(error) { // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Incorrect password.'))); // Return return; } // Disable message self.getMessage().disable(); // Check if password is incorrect if(self.getWallets().isPassword(password) === false) { // TODO Securely clear password // Show send error showSendError(Message.createText(Language.getDefaultTranslation('Incorrect password.'))); } // Otherwise else { // TODO Securely clear password // Initialize prevent cancel on hide var preventCancelOnHide = false; // Initialize canceled var canceled = false; // Set text var text = Message.createText((wallet.getName() === Wallet.NO_NAME) ? ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from Wallet %2$s to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from Wallet %2$s for a fee of %3$c.')) : ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from %2$y to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from %2$y for a fee of %3$c.')), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Wallet key path or name (wallet.getName() === Wallet.NO_NAME) ? wallet.getKeyPath().toFixed() : wallet.getName(), [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + ((recipientAddress["length"] !== 0) ? Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(recipientAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : "") + ((sendAsFile === false) ? Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('This may take several minutes to complete. The recipient must be online and listening at that address to receive this payment.')) + "" : ""); // Show message immediately and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Sending Payment'), Message.createPendingResult() + Message.createLineBreak() + text, true, function() { // Hide loading self.getApplication().hideLoading(); // Prevent automatic lock self.getAutomaticLock().prevent(); // Keep device awake and catch errors self.getWakeLock().preventLock().catch(function(error) { }); // Message show send section event $(self.getMessage()).one(Message.SHOW_EVENT + ".sendPaymentSection", function() { // Set timeout setTimeout(function() { // Send var send = function() { // Return promise return new Promise(function(resolve, reject) { // Return obtaining wallet's exclusive transactions lock return self.getTransactions().obtainWalletsExclusiveTransactionsLock(wallet.getKeyPath()).then(function() { // Return getting fee return self.getWallets().getFee(wallet.getKeyPath(), amount, baseFee, function() { // Return if canceled return canceled === true; }, true).then(function(currentFee) { // Check if fee didn't change if(currentFee[Api.FEE_FEE_INDEX].isEqualTo(fee) === true) { // Set prevent cancel on hide preventCancelOnHide = true; // Initialize message shown var messageShown = false; // Initialize last message type var lastMessageType = SendPaymentSection.NO_LAST_MESSAGE_TYPE; // Initialize second button var secondButton = Message.NO_BUTTON; // Initialize URL var url = SendPaymentSection.NO_URL; // Initialize sender address var senderAddress = SendPaymentSection.NO_SENDER_ADDRESS; // Message replace send section event $(self.getMessage()).on(Message.REPLACE_EVENT + ".sendPaymentSection", function(event, messageType, messageData) { // Check if not canceled if(canceled === false) { // Initialize message is loading var messageIsLoading = false; // Check if message type changed if(lastMessageType !== messageType) { // Clear message shown messageShown = false; // Check message type switch(messageType) { // Application hardware wallet unlock message case Application.HARDWARE_WALLET_UNLOCK_MESSAGE: // Check if second button isn't no button if(secondButton !== Message.NO_BUTTON) { // Set message is loading messageIsLoading = true; } // Break break; // Application hardware wallet disconnect message case Application.HARDWARE_WALLET_DISCONNECT_MESSAGE: // Set text text = Message.createText((wallet.getName() === Wallet.NO_NAME) ? ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from Wallet %2$s to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from Wallet %2$s for a fee of %3$c.')) : ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from %2$y to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from %2$y for a fee of %3$c.')), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Wallet key path or name (wallet.getName() === Wallet.NO_NAME) ? wallet.getKeyPath().toFixed() : wallet.getName(), [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + ((recipientAddress["length"] !== 0) ? Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(recipientAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : "") + ((senderAddress !== SendPaymentSection.NO_SENDER_ADDRESS) ? ((recipientAddress["length"] !== 0) ? Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('(?<=.) '))) + ((senderAddress !== Slate.NO_SENDER_ADDRESS) ? Message.createText(Language.getDefaultTranslation('The sender payment proof address you\'re using for the transaction is the following payment proof address.')) + Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(senderAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('The transaction won\'t have a payment proof.'))) : "") + ((sendAsFile === false) ? Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('This may take several minutes to complete. The recipient must be online and listening at that address to receive this payment.')) + "" : ""); // Set second button secondButton = Message.NO_BUTTON; // Cancel message replace self.getMessage().cancelReplace(); // Return return; // API finalize transaction message case Api.FINALIZE_TRANSACTION_MESSAGE: // Get address and kernel features from the message data var receiverAddress = messageData[Api.FINALIZE_TRANSACTION_MESSAGE_RECEIVER_ADDRESS_INDEX]; var kernelFeatures = messageData[Api.FINALIZE_TRANSACTION_MESSAGE_KERNEL_FEATURES_INDEX]; // Check if receiver address doesn't exist if(receiverAddress === Slate.NO_RECEIVER_ADDRESS) { // Check if wallet isn't a hardware wallet if(wallet.getHardwareType() === Wallet.NO_HARDWARE_TYPE) { // Set text text = ((wallet.getName() === Wallet.NO_NAME) ? Message.createText(Language.getDefaultTranslation('Finalize the transaction for Wallet %1$s to continue sending the payment.'), [wallet.getKeyPath().toFixed()]) : Message.createText(Language.getDefaultTranslation('Finalize the transaction for %1$y to continue sending the payment.'), [wallet.getName()])) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You\'re sending %1$c for a fee of %2$c, and the transaction doesn\'t have a payment proof.'), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('You can\'t guarantee that this payment is going to the intended recipient since the transaction doesn\'t have a payment proof.')) + ""; // Set second button secondButton = Language.getDefaultTranslation('Finalize'); } // Otherwise else { // Set text text = ((wallet.getName() === Wallet.NO_NAME) ? Message.createText(Language.getDefaultTranslation('Approve sending the transaction on the hardware wallet for Wallet %1$s to continue sending the payment.'), [wallet.getKeyPath().toFixed()]) : Message.createText(Language.getDefaultTranslation('Approve sending the transaction on the hardware wallet for %1$y to continue sending the payment.'), [wallet.getName()])) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Verify that the account index displayed on the hardware wallet is %1$s, the amount displayed is %2$c, the fee displayed is %3$c, the kernel features displayed is %4$x, and that there\'s no recipient payment proof address displayed.'), [ // Account index HardwareWallet.ACCOUNT.toFixed(), [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Kernel features kernelFeatures ]) + Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('You can\'t guarantee that this payment is going to the intended recipient since the transaction doesn\'t have a payment proof.')) + ""; // Set second button secondButton = Message.NO_BUTTON; } } // Otherwise else { // Check if wallet isn't a hardware wallet if(wallet.getHardwareType() === Wallet.NO_HARDWARE_TYPE) { // Set text text = ((wallet.getName() === Wallet.NO_NAME) ? Message.createText(Language.getDefaultTranslation('Finalize the transaction for Wallet %1$s to continue sending the payment.'), [wallet.getKeyPath().toFixed()]) : Message.createText(Language.getDefaultTranslation('Finalize the transaction for %1$y to continue sending the payment.'), [wallet.getName()])) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You\'re sending %1$c for a fee of %2$c, and the transaction\'s recipient payment proof address is the following payment proof address.'), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(receiverAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() + Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('You can guarantee that this payment is going to the intended recipient by having the recipient confirm that this payment proof address is their payment proof address.')) + ""; // Set second button secondButton = Language.getDefaultTranslation('Finalize'); } // Otherwise else { // Set text text = ((wallet.getName() === Wallet.NO_NAME) ? Message.createText(Language.getDefaultTranslation('Approve sending the transaction on the hardware wallet for Wallet %1$s to continue sending the payment.'), [wallet.getKeyPath().toFixed()]) : Message.createText(Language.getDefaultTranslation('Approve sending the transaction on the hardware wallet for %1$y to continue sending the payment.'), [wallet.getName()])) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Verify that the account index displayed on the hardware wallet is %1$s, the amount displayed is %2$c, the fee displayed is %3$c, the kernel features displayed is %4$x, and the recipient payment proof address displayed matches the following payment proof address.'), [ // Account index HardwareWallet.ACCOUNT.toFixed(), [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Kernel features kernelFeatures ]) + Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(receiverAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() + Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('You can guarantee that this payment is going to the intended recipient by having the recipient confirm that this payment proof address is their payment proof address.')) + ""; // Set second button secondButton = Message.NO_BUTTON; } } // Break break; // API get transaction response message case Api.GET_TRANSACTION_RESPONSE_MESSAGE: // Get file contents and name from the message data var fileContents = messageData[Api.GET_TRANSACTION_RESPONSE_MESSAGE_FILE_CONTENTS_INDEX]; var fileName = messageData[Api.GET_TRANSACTION_RESPONSE_MESSAGE_FILE_NAME_INDEX]; // Check if URL exists if(url !== SendPaymentSection.NO_URL) { // Revoke URL URL.revokeObjectURL(url); // Set URL to no URL url = SendPaymentSection.NO_URL; } // Create URL from file contents url = URL.createObjectURL(new Blob([ // Contents fileContents ], { // Type "type": "application/octet-stream" })); // Set text text = Message.createText(Language.getDefaultTranslation('Give the %1$m file to the payment\'s recipient and open their response file to continue sending the payment.'), [ [ // Text fileName, // URL url, // Is external true, // Is blob true ] ]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + ((senderAddress !== SendPaymentSection.NO_SENDER_ADDRESS && senderAddress !== Slate.NO_SENDER_ADDRESS) ? Message.createText(Language.getDefaultTranslation('The sender payment proof address you\'re using for the transaction is the following payment proof address.')) + Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(senderAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('The transaction doesn\'t have a payment proof.'))); // Set second button secondButton = Language.getDefaultTranslation('Open Response File'); // Break break; // API sender address message case Api.SENDER_ADDRESS_MESSAGE: // Check if sender address changed if(messageData !== senderAddress) { // Set sender address senderAddress = messageData; } // Otherwise else { // Cancel message replace self.getMessage().cancelReplace(); // Return return; } // Default default: // Set text text = Message.createText((wallet.getName() === Wallet.NO_NAME) ? ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from Wallet %2$s to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from Wallet %2$s for a fee of %3$c.')) : ((recipientAddress["length"] !== 0) ? Language.getDefaultTranslation('Sending %1$c from %2$y to the following address for a fee of %3$c.') : Language.getDefaultTranslation('Sending %1$c from %2$y for a fee of %3$c.')), [ [ // Number amount.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ], // Wallet key path or name (wallet.getName() === Wallet.NO_NAME) ? wallet.getKeyPath().toFixed() : wallet.getName(), [ // Number fee.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed(), // Currency Consensus.CURRENCY_NAME, // Display value true ] ]) + ((recipientAddress["length"] !== 0) ? Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(recipientAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : "") + ((senderAddress !== SendPaymentSection.NO_SENDER_ADDRESS) ? ((recipientAddress["length"] !== 0) ? Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('(?<=.) '))) + ((senderAddress !== Slate.NO_SENDER_ADDRESS) ? Message.createText(Language.getDefaultTranslation('The sender payment proof address you\'re using for the transaction is the following payment proof address.')) + Message.createLineBreak() + Message.createLineBreak() + "" + Common.htmlEncode(senderAddress) + "" + Language.createTranslatableContainer("", Language.getDefaultTranslation('Copy'), [], "copy", true) + "" + Message.createLineBreak() : Message.createText(Language.getDefaultTranslation('The transaction won\'t have a payment proof.'))) : "") + ((sendAsFile === false) ? Message.createLineBreak() + "" + Message.createText(Language.getDefaultTranslation('This may take several minutes to complete. The recipient must be online and listening at that address to receive this payment.')) + "" : ""); // Set second button secondButton = Message.NO_BUTTON; // Break break; } // Update last message type lastMessageType = messageType; } // Otherwise check if second button isn't no button else if(secondButton !== Message.NO_BUTTON) { // Set message is loading messageIsLoading = true; } // Check if message isn't already shown if(messageShown === false) { // Show message immediately and allow showing messages self.getMessage().show(Language.getDefaultTranslation('Sending Payment'), Message.createPendingResult() + Message.createLineBreak() + text, true, function() { // Check if canceled if(canceled === true) { // Return false return false; } // Otherwise else { // Set message shown messageShown = true; // Check if message isn't loading if(messageIsLoading === false) { // Hide loading self.getApplication().hideLoading(); } // Otherwise else { // Clear message is loading messageIsLoading = false; // Show loading self.getApplication().showLoading(); // Message before show not cancelable send payment section message replace event $(self.getMessage()).one(Message.BEFORE_SHOW_NOT_CANCELABLE_EVENT + ".sendPaymentSectionMessageReplace", function() { // Add focus apperance to message second button self.getMessage().messageDisplay.find("button").removeClass("focus").eq(1).addClass("focus"); // Set that message second button is loading self.getMessage().setButtonLoading(Message.SECOND_BUTTON); // Message show send payment section message replace event }).one(Message.SHOW_EVENT + ".sendPaymentSectionMessageReplace", function() { // Blur message buttons self.getMessage().messageDisplay.find("button").blur(); // Disable message self.getMessage().disable(); }); } } }, Language.getDefaultTranslation('Cancel'), secondButton, true, Message.VISIBLE_STATE_UNLOCKED).then(function(messageResult) { // Turn off message before show not cancelable send payment section message replace event $(self.getMessage()).off(Message.BEFORE_SHOW_NOT_CANCELABLE_EVENT + ".sendPaymentSectionMessageReplace"); // Turn off message show send payment section message replace event $(self.getMessage()).off(Message.SHOW_EVENT + ".sendPaymentSectionMessageReplace"); // Clear message shown messageShown = false; // Check if canceling if(messageResult === Message.FIRST_BUTTON_CLICKED_RESULT) { // Set canceled canceled = true; // Turn off message replace send section event $(self.getMessage()).off(Message.REPLACE_EVENT + ".sendPaymentSection"); // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } }); } // Otherwise check if finalizing else if(messageResult === Message.SECOND_BUTTON_CLICKED_RESULT) { // Show loading self.getApplication().showLoading(); // Set that message second button is loading self.getMessage().setButtonLoading(Message.SECOND_BUTTON); } }); } } }); // Return sending return self.getWallets().send(wallet.getKeyPath(), recipientAddress, currentFee[Api.FEE_AMOUNT_INDEX], currentFee[Api.FEE_FEE_INDEX], currentFee[Api.FEE_BASE_FEE_INDEX], message, sendAsFile, function() { // Return if canceled return canceled === true; }, true).then(function() { // Turn off message replace send section event $(self.getMessage()).off(Message.REPLACE_EVENT + ".sendPaymentSection"); // Release wallet's exclusive transactions lock self.getTransactions().releaseWalletsExclusiveTransactionsLock(wallet.getKeyPath()); // Check if URL exists if(url !== SendPaymentSection.NO_URL) { // Revoke URL URL.revokeObjectURL(url); // Set URL to no URL url = SendPaymentSection.NO_URL; } // Resolve resolve(); // Catch errors }).catch(function(error) { // Turn off message replace send section event $(self.getMessage()).off(Message.REPLACE_EVENT + ".sendPaymentSection"); // Release wallet's exclusive transactions lock self.getTransactions().releaseWalletsExclusiveTransactionsLock(wallet.getKeyPath()); // Check if URL exists if(url !== SendPaymentSection.NO_URL) { // Revoke URL URL.revokeObjectURL(url); // Set URL to no URL url = SendPaymentSection.NO_URL; } // Reject error reject(error); }); } // Otherwise else { // Release wallet's exclusive transactions lock self.getTransactions().releaseWalletsExclusiveTransactionsLock(wallet.getKeyPath()); // Reject error reject(Message.createText(Language.getDefaultTranslation('The fee changed.'))); } // Catch errors }).catch(function(error) { // Release wallet's exclusive transactions lock self.getTransactions().releaseWalletsExclusiveTransactionsLock(wallet.getKeyPath()); // Check if canceled if(error === Common.CANCELED_ERROR) { // Reject error reject(error); } // Otherwise else { // Reject error reject(Message.createText(error)); } }); }); }); }; // Send send().then(function() { // Set prevent cancel on hide preventCancelOnHide = true; // Disable message self.getMessage().disable(); // Show success result and catch errors self.getMessage().showSuccessResult().catch(function(error) { // Finally }).finally(function() { // Set timeout setTimeout(function() { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Check if current section is temporary if(self.getSections().isCurrentSectionTemporary() === true) { // Delete focus self.getFocus().delete(); // Prevent showing messages self.getMessage().prevent(); // Hide message self.getMessage().hide(); // Show current section and catch errors self.getSections().showCurrentSection(false).catch(function(error) { }); } // Otherwise else { // Clear input values and have their displays not show errors self.getDisplay().find("input").val("").closest("div").parent().closest("div").removeClass("error"); // Set send as file button to its default value self.getDisplay().find("button.sendAsFile").removeClass("enabled"); // Set base fee to the default base fee self.getDisplay().find("input.baseFee").val(Api.DEFAULT_BASE_FEE.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed()).trigger("input", [ // Is focus event false, // Force input true ]); // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Delete focus self.getFocus().delete(); // Hide loading self.getApplication().hideLoading(); // Hide message self.getMessage().hide(); } } // Otherwise else { // Clear input values and have their displays not show errors self.getDisplay().find("input").val("").closest("div").parent().closest("div").removeClass("error"); // Set send as file button to its default value self.getDisplay().find("button.sendAsFile").removeClass("enabled"); // Set base fee to the default base fee and have it not show an error self.getDisplay().find("input.baseFee").val(Api.DEFAULT_BASE_FEE.dividedBy(Consensus.VALUE_NUMBER_BASE).toFixed()).closest("div").parent().closest("div").removeClass("error"); // Update state and catch errors self.updateState().catch(function(error) { }); } }); }, SendPaymentSection.SEND_RESULT_DELAY_MILLISECONDS); }); // Catch errors }).catch(function(error) { // Check if not canceled if(canceled === false) { // Check if canceled if(error === Common.CANCELED_ERROR) { // Set prevent cancel on hide preventCancelOnHide = true; // Disable message self.getMessage().disable(); // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide loading self.getApplication().hideLoading(); // Hide message self.getMessage().hide(); } }); } // Otherwise else { // Set prevent cancel on hide preventCancelOnHide = true; // Disable message self.getMessage().disable(); // Show failure result and catch errors self.getMessage().showFailureResult().catch(function(error) { // Finally }).finally(function() { // Set timeout setTimeout(function() { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Show send error showSendError(error); } }); }, SendPaymentSection.SEND_RESULT_DELAY_MILLISECONDS); }); } } }); }, SendPaymentSection.START_SENDING_DELAY_MILLISECONDS); }); }, Language.getDefaultTranslation('Cancel'), Message.NO_BUTTON, true, Message.VISIBLE_STATE_UNLOCKED).then(function(messageResult) { // Turn off message show send section event $(self.getMessage()).off(Message.SHOW_EVENT + ".sendPaymentSection"); // Check if not preventing cancel on hide or message wasn't hidden if(preventCancelOnHide === false || messageResult !== Message.NOT_DISPLAYED_RESULT) { // Set canceled canceled = true; // Turn off message replace send section event $(self.getMessage()).off(Message.REPLACE_EVENT + ".sendPaymentSection"); // Check if message was displayed if(messageResult !== Message.NOT_DISPLAYED_RESULT) { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } }); } // Otherwise else { // Allow device to sleep and catch errors self.getWakeLock().allowLock().catch(function(error) { // Finally }).finally(function() { // Allow automatic lock self.getAutomaticLock().allow(); }); } } }); } } // Otherwise else { // Set that button isn't loading button.removeClass("loading"); // Enable unlocked self.getUnlocked().enable(); // Set that button isn't clicked button.removeClass("clicked"); // Restore focus and don't blur self.getFocus().restore(false); // Hide message self.getMessage().hide(); } } }); } // Catch errors }).catch(function(error) { // Enable automatic lock self.getAutomaticLock().allow(); // Check if automatic lock isn't locking if(self.getAutomaticLock().isLocking() === false) { // Show send error showSendError(Message.createText(error)); } }); } } }); // Cancel button click event this.getDisplay().find("button.cancel").on("click", function() { // Show current section and catch errors self.getSections().showCurrentSection(false).catch(function(error) { }); }); // Document key down event var savedValues = []; $(document).on("keydown", function(event) { // Check if key tab is pressed if(event["which"] === "\t".charCodeAt(0)) { // Enable tabbing to all not disabled inputs self.getDisplay().find("div:not(.disabled)").find("input").enableTab(); // Disable tabbing to all disabled inputs self.getDisplay().find("div.disabled").find("input").disableTab(); } // Document language before change event }).on(Language.BEFORE_CHANGE_EVENT, function() { // Check if shown if(self.isShown() === true) { // Clear saved values savedValues = []; // Go through all of the display's number inputs self.getDisplay().find("input[type=\"number\"]").each(function() { // Get input var input = $(this); // Append input's value to list savedValues.push((input.val()["length"] !== 0) ? (new BigNumber(input.val())).toFixed() : ""); }); } }); // HTML on language change event $("html").on(Language.CHANGE_EVENT, function(event) { // Check if target is HTML, is shown, and values are saved if($(event["target"]).is("html") === true && self.isShown() === true && savedValues["length"] !== 0) { // Go through all of the display's number inputs self.getDisplay().find("input[type=\"number\"]").each(function(index) { // Get input var input = $(this); // Restore input's value input.val(savedValues[index]); }); // Clear saved values savedValues = []; } }); } // Get name getName() { // Return name return SendPaymentSection.NAME; } // Reset reset() { // Reset super.reset(); // Turn off section shown send payment section event $(this).off(Section.SHOWN_EVENT + ".sendPaymentSection"); // Set that inputs aren't showing an error or hidden and clear their values this.getDisplay().find("div").removeClass("error hide").find("input").val(""); // Set that buttons aren't clicked, loading, enabled, or transition instantly this.getDisplay().find("button").removeClass("clicked loading enabled noTransition"); // Allow all button display to merge this.getDisplay().find("button.all").parent().closest("div").addClass("merge"); // Empty from wallet selection this.getDisplay().find("select.fromWallet").empty(); } // Get state getState() { // Get state var state = super.getState(); // Check if wallet key path exists if(this.walletKeyPath !== WalletSection.NO_WALLET_KEY_PATH) { // Set state's wallet key path state[SendPaymentSection.STATE_WALLET_KEY_PATH_NAME] = this.walletKeyPath; } // Set state's amount last changed state[SendPaymentSection.STATE_AMOUNT_LAST_CHANGED_NAME] = this.amountLastChanged; // Return state return state; } // Name static get NAME() { // Return name return "Send"; } // State wallet key path name static get STATE_WALLET_KEY_PATH_NAME() { // Return state wallet key path name return WalletSection.STATE_WALLET_KEY_PATH_NAME; } // State amount last changed name static get STATE_AMOUNT_LAST_CHANGED_NAME() { // Return state amount last changed name return "Amount Last Changed"; } // Private // Initialize initialize(state, firstShown) { // Set base class initialize var baseClassInitialize = super.initialize(state); // Set self var self = this; // Return promise return new Promise(function(resolve, reject) { // Return initializing base class return baseClassInitialize.then(function() { // Set wallet key path to value in state or no wallet key path if it doesn't exist self.walletKeyPath = (SendPaymentSection.STATE_WALLET_KEY_PATH_NAME in state === true) ? state[SendPaymentSection.STATE_WALLET_KEY_PATH_NAME] : WalletSection.NO_WALLET_KEY_PATH; // Set amount last changed to value in state or true if it doesn't exist self.amountLastChanged = (SendPaymentSection.STATE_AMOUNT_LAST_CHANGED_NAME in state === true) ? state[SendPaymentSection.STATE_AMOUNT_LAST_CHANGED_NAME] : true; // Check if there is no wallet key path if(self.walletKeyPath === WalletSection.NO_WALLET_KEY_PATH) { // Try try { // Get wallets in order var walletsInOrder = self.getWallets().getWalletsInOrder(); } // Catch errors catch(error) { // Reject error reject(error); // Return return; } // Get from wallet selection display var fromWalletSelectionDisplay = self.getDisplay().find("select.fromWallet"); // Go through all wallets in order for(var i = 0; i < walletsInOrder["length"]; ++i) { // Get wallet var wallet = walletsInOrder[i]; // Create option for wallet var option = $(Language.createTranslatableContainer("