From ad8740adc2ba413992526615d6234555496cf0c1 Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sat, 26 Sep 2020 11:20:43 +0300 Subject: [PATCH] Fix relative icon position --- keepassxc-browser/content/pwgen.js | 5 +-- keepassxc-browser/content/totp-field.js | 7 +--- keepassxc-browser/content/ui.js | 45 +++++++++++++++------ keepassxc-browser/content/username-field.js | 10 ++--- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/keepassxc-browser/content/pwgen.js b/keepassxc-browser/content/pwgen.js index 4064b8d..75823b2 100644 --- a/keepassxc-browser/content/pwgen.js +++ b/keepassxc-browser/content/pwgen.js @@ -30,8 +30,7 @@ kpxcPasswordIcons.isValid = function(field) { class PasswordIcon extends Icon { constructor(field, databaseState = DatabaseState.DISCONNECTED) { - super(); - this.databaseState = databaseState; + super(field, databaseState); this.nextFieldExists = false; this.initField(field); @@ -80,7 +79,7 @@ PasswordIcon.prototype.createIcon = function(field) { kpxcPasswordDialog.showDialog(field, icon); }); - kpxcUI.setIconPosition(icon, field); + kpxcUI.setIconPosition(icon, field, this.rtl); this.icon = icon; const styleSheet = document.createElement('link'); diff --git a/keepassxc-browser/content/totp-field.js b/keepassxc-browser/content/totp-field.js index 15ecd4e..6b6ef79 100644 --- a/keepassxc-browser/content/totp-field.js +++ b/keepassxc-browser/content/totp-field.js @@ -75,10 +75,7 @@ kpxcTOTPIcons.isValid = function(field, forced) { class TOTPFieldIcon extends Icon { constructor(field, databaseState = DatabaseState.DISCONNECTED, forced = false) { - super(); - this.icon = null; - this.inputField = null; - this.databaseState = databaseState; + super(field, databaseState); this.initField(field, forced); kpxcUI.monitorIconPosition(this); @@ -127,7 +124,7 @@ TOTPFieldIcon.prototype.createIcon = function(field) { kpxc.fillFromTOTP(field); }); - kpxcUI.setIconPosition(icon, field); + kpxcUI.setIconPosition(icon, field, this.rtl); this.icon = icon; const styleSheet = document.createElement('link'); diff --git a/keepassxc-browser/content/ui.js b/keepassxc-browser/content/ui.js index 2c70ab8..582ae2b 100644 --- a/keepassxc-browser/content/ui.js +++ b/keepassxc-browser/content/ui.js @@ -20,7 +20,12 @@ const Pixels = function(value) { // Basic icon class class Icon { - constructor() { + constructor(field, databaseState = DatabaseState.DISCONNECTED) { + this.databaseState = databaseState; + this.icon = null; + this.inputField = null; + this.rtl = kpxcUI.isRTL(field); + try { this.observer = new IntersectionObserver((entries) => { kpxcUI.updateFromIntersectionObserver(this, entries); @@ -92,7 +97,7 @@ kpxcUI.monitorIconPosition = function(iconClass) { kpxcUI.updateIconPosition = function(iconClass) { if (iconClass.inputField && iconClass.icon) { - kpxcUI.setIconPosition(iconClass.icon, iconClass.inputField); + kpxcUI.setIconPosition(iconClass.icon, iconClass.inputField, iconClass.rtl); } }; @@ -101,18 +106,17 @@ kpxcUI.calculateIconOffset = function(field, size) { return (offset < 0) ? 0 : offset; }; -kpxcUI.setIconPosition = function(icon, field) { +kpxcUI.setIconPosition = function(icon, field, rtl = false) { const rect = field.getBoundingClientRect(); - const size = (document.dir !== 'rtl') ? Number(icon.getAttribute('size')) : 0; + const size = Number(icon.getAttribute('size')); const offset = kpxcUI.calculateIconOffset(field, size); + const left = kpxcUI.bodyStyle.position.toLowerCase() === 'relative' ? rect.left - kpxcUI.bodyRect.left : rect.left; + const top = kpxcUI.bodyStyle.position.toLowerCase() === 'relative' ? rect.top - kpxcUI.bodyRect.top : rect.top; - if (kpxcUI.bodyStyle.position.toLowerCase() === 'relative') { - icon.style.top = Pixels(rect.top - kpxcUI.bodyRect.top + document.scrollingElement.scrollTop + offset + 1); - icon.style.left = Pixels(rect.left - kpxcUI.bodyRect.left + document.scrollingElement.scrollLeft + field.offsetWidth - size - offset); - } else { - icon.style.top = Pixels(rect.top + document.scrollingElement.scrollTop + offset + 1); - icon.style.left = Pixels(rect.left + document.scrollingElement.scrollLeft + field.offsetWidth - size - offset); - } + icon.style.top = Pixels(top + document.scrollingElement.scrollTop + offset + 1); + icon.style.left = rtl + ? Pixels((left + document.scrollingElement.scrollLeft) + offset) + : Pixels(left + document.scrollingElement.scrollLeft + field.offsetWidth - size - offset); }; kpxcUI.deleteHiddenIcons = function(iconList, attr) { @@ -135,6 +139,23 @@ kpxcUI.deleteHiddenIcons = function(iconList, attr) { } }; +kpxcUI.isRTL = function(field) { + if (!field) { + return false; + } + + const style = getComputedStyle(field); + if (style.textAlign.toLowerCase() === 'left') { + return false; + } else if (style.textAlign.toLowerCase() === 'right') { + return true; + } + + return kpxcFields.traverseParents(field, + f => [ 'ltr', 'rtl' ].includes(f.getLowerCaseAttribute('dir')), + f => ({ 'ltr': false, 'rtl': true })[f.getLowerCaseAttribute('dir')]); +}; + /** * Detects if the input field appears or disappears -> show/hide the icon * - boundingClientRect with slightly (< -10) negative values -> hidden @@ -154,7 +175,7 @@ kpxcUI.updateFromIntersectionObserver = function(iconClass, entries) { // Wait for possible DOM animations setTimeout(() => { - kpxcUI.setIconPosition(iconClass.icon, entry.target); + kpxcUI.setIconPosition(iconClass.icon, entry.target, iconClass.rtl); }, 400); } } diff --git a/keepassxc-browser/content/username-field.js b/keepassxc-browser/content/username-field.js index 6074c1f..9c6a6c4 100644 --- a/keepassxc-browser/content/username-field.js +++ b/keepassxc-browser/content/username-field.js @@ -31,10 +31,7 @@ kpxcUsernameIcons.isValid = function(field) { class UsernameFieldIcon extends Icon { constructor(field, databaseState = DatabaseState.DISCONNECTED) { - super(); - this.databaseState = databaseState; - this.icon = null; - this.inputField = null; + super(field, databaseState); this.initField(field); kpxcUI.monitorIconPosition(this); @@ -63,8 +60,7 @@ UsernameFieldIcon.prototype.initField = function(field) { this.inputField = field; }; -UsernameFieldIcon.prototype.createIcon = function(target) { - const field = target; +UsernameFieldIcon.prototype.createIcon = function(field) { const className = getIconClassName(this.databaseState); // Size the icon dynamically, but not greater than 24 or smaller than 14 @@ -99,7 +95,7 @@ UsernameFieldIcon.prototype.createIcon = function(target) { iconClicked(field, icon); }); - kpxcUI.setIconPosition(icon, field); + kpxcUI.setIconPosition(icon, field, this.rtl); this.icon = icon; const styleSheet = document.createElement('link');