Performance adjustments

This commit is contained in:
varjolintu 2020-01-01 18:34:01 +02:00
parent d4fa2f7155
commit e95c8ad450
5 changed files with 117 additions and 53 deletions

View file

@ -575,6 +575,14 @@
"message": "Activate username field icons.",
"description": "Activate username field icons textbox text."
},
"optionsUseObserver": {
"message": "Use dynamic input field detection.",
"description": "Use dynamic input field detection checkbox text."
},
"optionsUseObserverHelpText": {
"message": "Useful with pages that use popups or dynamic dialogs. Disable the feature to reduce CPU load on slower machines. When disabled credentials can be only inserted using keyboard shortcuts, the context menu or the extension popup.",
"description": "Use dynamic input field detection help text."
},
"optionsCheckboxOTPIcons": {
"message": "Activate 2FA/OTP field icons.",
"description": "Activate OTP field icons textbox text."

View file

@ -17,6 +17,7 @@ const defaultSettings = {
showLoginNotifications: true,
showNotifications: true,
showOTPIcon: true,
useObserver: true,
usePasswordGeneratorIcons: false
};
@ -76,6 +77,10 @@ page.initSettings = async function() {
page.settings.defaultGroupAlwaysAsk = defaultSettings.defaultGroupAlwaysAsk;
}
if (!('redirectAllowance' in page.settings)) {
page.settings.redirectAllowance = defaultSettings.redirectAllowance;
}
if (!('saveDomainOnly' in page.settings)) {
page.settings.saveDomainOnly = defaultSettings.saveDomainOnly;
}
@ -100,8 +105,12 @@ page.initSettings = async function() {
page.settings.usePasswordGeneratorIcons = defaultSettings.usePasswordGeneratorIcons;
}
if (!('redirectAllowance' in page.settings)) {
page.settings.redirectAllowance = defaultSettings.redirectAllowance;
if (!('useObserver' in page.settings)) {
page.settings.useObserver = defaultSettings.useObserver;
}
if (!('usePasswordGeneratorIcons' in page.settings)) {
page.settings.usePasswordGeneratorIcons = defaultSettings.usePasswordGeneratorIcons;
}
await browser.storage.local.set({ 'settings': page.settings });

View file

@ -24,6 +24,7 @@ _called.manualFillRequested = ManualFill.NONE;
let _singleInputEnabledForPage = false;
let _databaseClosed = true;
const _maximumInputs = 100;
const _maximumMutations = 200;
// Count of detected form fields on the page
var _detectedFields = 0;
@ -712,7 +713,7 @@ kpxcObserverHelper.handleObserverAdd = function(target) {
if (Object.keys(kpxc.settings).length === 0) {
kpxc.init();
} else {
kpxc.initCredentialFields(true);
kpxc.initCredentialFields(true, inputs);
}
}
};
@ -747,53 +748,6 @@ kpxcObserverHelper.detectURLChange = function() {
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
// Detects DOM changes in the document
const observer = new MutationObserver(function(mutations, obs) {
if (document.visibilityState === 'hidden') {
return;
}
for (const mut of mutations) {
// Skip text nodes
if (mut.target.nodeType === Node.TEXT_NODE) {
continue;
}
// Check document URL change and detect new fields
kpxcObserverHelper.detectURLChange();
// Handle attributes only if CSS display is modified
if (mut.type === 'attributes') {
// Check if some class is changed that folds a form or input field(s)
if (mut.attributeName === 'class' && mut.target.querySelectorAll('form input').length > 0) {
kpxc.initCredentialFields(true);
continue;
}
const newValue = mut.target.getAttribute(mut.attributeName);
if (newValue && (newValue.includes('display') || newValue.includes('z-index'))) {
if (mut.target.style.display !== 'none') {
kpxcObserverHelper.handleObserverAdd(mut.target);
} else {
kpxcObserverHelper.handleObserverRemove(mut.target);
}
}
} else if (mut.type === 'childList') {
kpxcObserverHelper.handleObserverAdd((mut.addedNodes.length > 0) ? mut.addedNodes[0] : mut.target);
kpxcObserverHelper.handleObserverRemove((mut.removedNodes.length > 0) ? mut.removedNodes[0] : mut.target);
}
}
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true,
childList: true,
characterData: true,
attributeFilter: [ 'style', 'class' ]
});
const kpxc = {};
@ -811,6 +765,16 @@ const initcb = async function() {
});
kpxc.settings = settings;
// Don't initialize MutationObserver if the site is ignored
if (kpxc.siteIgnored()) {
return;
}
if (kpxc.settings.useObserver) {
kpxc.initObserver();
}
await kpxc.initCredentialFields();
// Retrieve submitted credentials if available.
@ -851,6 +815,61 @@ kpxc.init = function() {
initcb();
};
// Detects DOM changes in the document
kpxc.initObserver = function() {
const observer = new MutationObserver(function(mutations, obs) {
if (document.visibilityState === 'hidden' || kpxcUI.mouseDown) {
return;
}
// Limit the mutation handling
if (mutations.length > _maximumMutations) {
mutations.slice(0, _maximumMutations);
}
for (const mut of mutations) {
// Skip text nodes
if (mut.target.nodeType === Node.TEXT_NODE) {
continue;
}
// Check document URL change and detect new fields
kpxcObserverHelper.detectURLChange();
// Handle attributes only if CSS display is modified
if (mut.type === 'attributes') {
// Check if some class is changed that folds a form or input field(s)
if (mut.attributeName === 'class' && mut.target.querySelectorAll('form input').length > 0) {
kpxc.initCredentialFields(true);
continue;
}
const newValue = mut.target.getAttribute(mut.attributeName);
if (newValue && (newValue.includes('display') || newValue.includes('z-index'))) {
if (mut.target.style.display !== 'none') {
kpxcObserverHelper.handleObserverAdd(mut.target);
} else {
kpxcObserverHelper.handleObserverRemove(mut.target);
}
}
} else if (mut.type === 'childList') {
kpxcObserverHelper.handleObserverAdd((mut.addedNodes.length > 0) ? mut.addedNodes[0] : mut.target);
kpxcObserverHelper.handleObserverRemove((mut.removedNodes.length > 0) ? mut.removedNodes[0] : mut.target);
}
}
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true,
childList: true,
characterData: true,
attributeFilter: [ 'style', 'class' ]
});
};
// Clears all from the content and background scripts, including autocomplete
kpxc.clearAllFromPage = function() {
kpxcEvents.clearCredentials();
@ -920,7 +939,7 @@ kpxc.siteIgnored = function(condition) {
return false;
};
kpxc.initCredentialFields = async function(forceCall) {
kpxc.initCredentialFields = async function(forceCall, inputs) {
if (_called.initCredentialFields && !forceCall) {
return;
}
@ -937,7 +956,11 @@ kpxc.initCredentialFields = async function(forceCall) {
return;
}
const inputs = kpxcFields.getAllFields();
// If target input fields are not defined, get inputs from the whole document
if (inputs === undefined) {
inputs = kpxcFields.getAllFields();
}
if (inputs.length === 0) {
return;
}
@ -989,9 +1012,13 @@ kpxc.initCredentialFields = async function(forceCall) {
};
kpxc.initPasswordGenerator = function(inputs) {
if (!kpxc.settings.usePasswordGeneratorIcons) {
return;
}
for (let i = 0; i < inputs.length; i++) {
if (inputs[i] && inputs[i].getLowerCaseAttribute('type') === 'password') {
kpxcPasswordIcons.newIcon(kpxc.settings.usePasswordGeneratorIcons, inputs[i], inputs, i, _databaseClosed);
kpxcPasswordIcons.newIcon(true, inputs[i], inputs, i, _databaseClosed);
}
}
};

View file

@ -36,6 +36,7 @@ class Icon {
};
const kpxcUI = {};
kpxcUI.mouseDown = false;
// Wrapper for creating elements
kpxcUI.createElement = function(type, classes, attributes, textContent) {
@ -167,6 +168,10 @@ const initColorTheme = function(elem) {
// Enables dragging
document.addEventListener('mousemove', function(e) {
if (!kpxcUI.mouseDown) {
return;
}
if (kpxcPasswordDialog.selected === kpxcPasswordDialog.titleBar) {
const xPos = e.clientX - kpxcPasswordDialog.diffX;
const yPos = e.clientY - kpxcPasswordDialog.diffY;
@ -188,9 +193,14 @@ document.addEventListener('mousemove', function(e) {
}
});
document.addEventListener('mousedown', function() {
kpxcUI.mouseDown = true;
});
document.addEventListener('mouseup', function() {
kpxcPasswordDialog.selected = null;
kpxcDefine.selected = null;
kpxcUI.mouseDown = false;
});
HTMLDivElement.prototype.appendMultiple = function(...args) {

View file

@ -77,6 +77,16 @@
</div>
</p>
<hr />
<p>
<div class="checkbox">
<label class="checkbox">
<input type="checkbox" name="useObserver" value="true"/><span data-i18n="optionsUseObserver"></span>
</label>
<span class="help-block">
<span data-i18n="optionsUseObserverHelpText"></span>
</span>
</div>
</p>
<p>
<div class="checkbox">
<label class="checkbox">