Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion classes/Modules/Address/www/js/address_create.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var AddressDuplicates = (function ($) {
},

init: function () {
me.registerZipcodeSanitizer();
me.registerEvents();
},

Expand All @@ -33,6 +34,40 @@ var AddressDuplicates = (function ($) {
});
},

registerZipcodeSanitizer: function () {
var $zipcodeFields = $('#plz, #rechnung_plz');

if(!$zipcodeFields.length){
return;
}

me.sanitizeZipcodeField($zipcodeFields);

$zipcodeFields.on('blur change', function () {
me.sanitizeZipcodeField($(this));
});
},

sanitizeZipcodeField: function ($field) {
if(!$field || !$field.length){
return;
}

$field.each(function () {
var $currentField = $(this);
var currentValue = $currentField.val();
if(typeof currentValue !== 'string'){
return;
}

// Entfernt Leerzeichen am Anfang oder Ende, die keine eigentlichen Zeichen flankieren
var sanitizedValue = currentValue.replace(/^\s+|\s+$/g, '');
if(sanitizedValue !== currentValue){
$currentField.val(sanitizedValue);
}
});
},

checkDuplicate: function () {
var nameValue = $('#name').val();
var streetValue = $('#strasse').val();
Expand All @@ -58,4 +93,4 @@ var AddressDuplicates = (function ($) {

$(document).ready(function () {
AddressDuplicates.init();
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"api-docs:build": "./node_modules/raml2html/bin/raml2html --validate --theme raml2html-werk-theme --input www/api/docs.raml --output www/api/docs-tmp.html && cat www/api/docs-tmp.html | sed -e 's/<\\/head>/<link rel=\\\"stylesheet\\\" href=\\\"\\.\\/assets\\/docs_custom\\.css\\\"><\\/head>/' > www/api/docs.html && rm www/api/docs-tmp.html",
"dev": "vite -d --cors --host ::",
"build": "vite build",
"test:zipcode": "node --test tests/address_zipcode_sanitizer.test.js",
"preview": "vite preview"
},
"devDependencies": {
Expand Down
172 changes: 172 additions & 0 deletions tests/address_zipcode_sanitizer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import assert from 'node:assert';
import fs from 'node:fs';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import vm from 'node:vm';
import test from 'node:test';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const scriptPath = path.resolve(__dirname, '..', 'classes', 'Modules', 'Address', 'www', 'js', 'address_create.js');

const createElement = (id, value = '') => ({
id,
value,
handlers: {},
classes: new Set(),
});

const createJQueryStub = (elements, documentElement) => {
function JQueryCollection(resolvedElements) {
this.elements = resolvedElements;
this.length = resolvedElements.length;
}

JQueryCollection.prototype.on = function (events, handler) {
const eventList = events.split(/\s+/);
this.elements.forEach((element) => {
eventList.forEach((evt) => {
if (!element.handlers[evt]) {
element.handlers[evt] = [];
}
element.handlers[evt].push(handler);
});
});
return this;
};

JQueryCollection.prototype.ready = function (handler) {
if (typeof handler === 'function') {
handler();
}
return this;
};

JQueryCollection.prototype.val = function (newValue) {
if (newValue === undefined) {
return this.elements[0]?.value;
}
this.elements.forEach((element) => {
element.value = newValue;
});
return this;
};

JQueryCollection.prototype.each = function (callback) {
this.elements.forEach((element, index) => {
callback.call(element, index, element);
});
return this;
};

JQueryCollection.prototype.trigger = function (eventName) {
this.elements.forEach((element) => {
const handlers = element.handlers[eventName] || [];
handlers.forEach((handler) => handler.call(element, {type: eventName}));
});
return this;
};

JQueryCollection.prototype.addClass = function (className) {
this.elements.forEach((element) => element.classes.add(className));
return this;
};

JQueryCollection.prototype.removeClass = function (className) {
this.elements.forEach((element) => element.classes.delete(className));
return this;
};

JQueryCollection.prototype.hasClass = function (className) {
return this.elements.some((element) => element.classes.has(className));
};

JQueryCollection.prototype.next = function () {
return {
remove: () => undefined,
};
};

JQueryCollection.prototype.insertAfter = function () {
return this;
};

JQueryCollection.prototype.html = function () {
return this;
};

const resolveSelector = (selector) => {
if (selector === document || selector === 'document') {
return [documentElement];
}

if (typeof selector === 'string') {
if (selector.startsWith('<')) {
return [createElement('generated')];
}
const ids = selector.split(',').map((part) => part.trim());
return ids
.map((id) => (id.startsWith('#') ? id : `#${id}`))
.map((id) => elements[id])
.filter(Boolean);
}

if (selector && selector.id && elements[`#${selector.id}`]) {
return [elements[`#${selector.id}`]];
}

return [];
};

const jQuery = function (selector) {
return new JQueryCollection(resolveSelector(selector));
};

jQuery.ajax = () => ({
done: (handler) => {
handler(false);
return this;
},
});

return jQuery;
};

const setupEnvironment = (plzValue, rechnungPlzValue) => {
const elements = {
'#plz': createElement('plz', plzValue),
'#rechnung_plz': createElement('rechnung_plz', rechnungPlzValue),
'#name': createElement('name'),
'#strasse': createElement('strasse'),
'#ort': createElement('ort'),
};

const documentElement = createElement('document');
const $ = createJQueryStub(elements, documentElement);

globalThis.$ = $;
globalThis.jQuery = $;
globalThis.document = documentElement;

const scriptContent = fs.readFileSync(scriptPath, 'utf8');
vm.runInThisContext(scriptContent, {filename: scriptPath});

return {elements, $};
};

test('sanitizes zipcode fields on init', () => {
const {elements} = setupEnvironment(' 12345 ', ' 98765 ');

assert.equal(elements['#plz'].value, '12345');
assert.equal(elements['#rechnung_plz'].value, '98765');
});

test('sanitizes zipcode fields on blur', () => {
const {elements, $} = setupEnvironment('12345 ', '98765 ');

$(elements['#plz']).val(' 54321 ').trigger('blur');
$(elements['#rechnung_plz']).val(' 56789 ').trigger('blur');

assert.equal(elements['#plz'].value, '54321');
assert.equal(elements['#rechnung_plz'].value, '56789');
});