jenesius-vue-form
Advanced tools
Comparing version
import EventEmitter from "jenesius-event-emitter"; | ||
import { FunctionHandleData, Values } from "../types"; | ||
export default class Form extends EventEmitter { | ||
import { FormDependence, NamedFormDependence, FunctionHandleData, Values } from "../types"; | ||
export default class Form extends EventEmitter implements FormDependence { | ||
#private; | ||
@@ -8,2 +8,6 @@ static PROVIDE_NAME: string; | ||
static EVENT_SAVE: string; | ||
static EVENT_DISABLE: string; | ||
static EVENT_ENABLE: string; | ||
static EVENT_SUBSCRIBE: string; | ||
static EVENT_UNSUBSCRIBE: string; | ||
static EVENT_VALUE: string; | ||
@@ -26,3 +30,3 @@ static EVENT_UPDATE_ABILITY: string; | ||
*/ | ||
dependencies: any[]; | ||
dependencies: FormDependence[]; | ||
/** | ||
@@ -47,7 +51,7 @@ * @description Link to parent Form | ||
/** | ||
* Рекурсивное зименение значений. | ||
* По фатку в конечной реализации оно нихуя не рекурсивное. | ||
* Рекурсивное изменение значений. | ||
* В конечной реализации оно нихуя не рекурсивное. | ||
* Реализация 2: для каждой зависимости получает значение из values и устанавливаем его | ||
* Реализация 1: идем рекурсивно по всем значениям, находим подходящие зависимости | ||
* и устанвливаем значения для них. Основная проблема в количетсве итераций. | ||
* и устанавливаем значения для них. Основная проблема в количестве итераций. | ||
* Нужно это протестировать | ||
@@ -90,3 +94,3 @@ * И переименовать метод: changeValuesOfItem(values: any); | ||
* */ | ||
getAssociatedDependencies(name: string): any[]; | ||
getAssociatedDependencies(name: string): NamedFormDependence[]; | ||
/** | ||
@@ -100,14 +104,20 @@ * @description Вернёт точное совпадение зависимостей по имени | ||
getValueByName(name: string): Values | undefined; | ||
get disabledElements(): { | ||
[name: string]: boolean; | ||
}; | ||
get disabled(): boolean; | ||
set disabled(value: boolean); | ||
disable(names?: string | string[]): true | undefined; | ||
protected recursiveDisableItem(name?: string): void; | ||
protected recursiveEnableItem(name?: string): void; | ||
disable(name?: string): void; | ||
enable(name?: string): void; | ||
protected disableByName(name: string): void; | ||
protected enableByName(name: string): void; | ||
enable(names?: string | string[]): false | undefined; | ||
private getProxyAbilities; | ||
abilities: { | ||
[name: string]: boolean; | ||
}; | ||
/** | ||
* @param {String} name. Element name. | ||
* @param {Boolean} mark. True - Enable, false: disable | ||
* */ | ||
private markElementForAbility; | ||
protected disableByName(name: string): boolean | undefined; | ||
protected enableByName(name: string): boolean | undefined; | ||
/** | ||
* @description Функция вернёт наиболее релевантное значения для поля по име | ||
@@ -127,3 +137,3 @@ * ни. Для address.city.name более релевантным является address.city, чем | ||
/**VALIDATION**/ | ||
validate(): any; | ||
validate(): boolean; | ||
} | ||
@@ -130,0 +140,0 @@ interface FormParams { |
@@ -11,1 +11,11 @@ export interface Values { | ||
} | ||
export interface FormDependence { | ||
name?: string; | ||
disable: (name?: string | string[]) => void; | ||
enable: (name?: string | string[]) => void; | ||
change: (v: any) => void; | ||
validate: () => boolean | string; | ||
} | ||
export interface NamedFormDependence extends FormDependence { | ||
name: string; | ||
} |
/*! | ||
* jenesius-vue-form v2.0.10 | ||
* jenesius-vue-form v2.0.11 | ||
* (c) 2022 Jenesius | ||
@@ -203,3 +203,32 @@ * @license MIT | ||
var _Form_values, _Form_changes, _Form_debug, _Form_disabled, _Form_handleDE, _Form_disabledElements, _Form_readData, _Form_saveData; | ||
function checkCompositeName(parentName, childrenName) { | ||
// Parent name can't be less for size; | ||
if (parentName.length > childrenName.length) | ||
return false; | ||
// Equal | ||
if (parentName === childrenName) | ||
return true; | ||
let index = 0; | ||
const parentArray = parentName.split('.'); | ||
const childrenArray = childrenName.split('.'); | ||
while (index < parentArray.length) { | ||
if (parentArray[index] !== childrenArray[index]) | ||
return false; | ||
index++; | ||
} | ||
return true; | ||
} | ||
function findNearestNameFromArray(name, array) { | ||
let answer = ""; | ||
array.forEach(n => { | ||
if (!checkCompositeName(n, name)) | ||
return; | ||
if (n.length > answer.length) | ||
answer = n; | ||
}); | ||
return answer.length === 0 ? undefined : answer; | ||
} | ||
var _Form_values, _Form_changes, _Form_debug, _Form_disabled, _Form_readData, _Form_saveData; | ||
class Form extends EventEmitter__default["default"] { | ||
@@ -241,31 +270,2 @@ constructor(params = {}) { | ||
/** | ||
* Experiment. Code review. | ||
* */ | ||
_Form_handleDE.set(this, { | ||
defineProperty: (target, name, attributes) => { | ||
const value = attributes.value; | ||
Object.keys(target).forEach(disabledName => { | ||
if (disabledName.startsWith(name.toString())) { | ||
delete target[disabledName]; | ||
} | ||
}); | ||
target[name] = attributes.value; | ||
if (value) | ||
this.recursiveDisableItem(name.toString()); | ||
else | ||
this.recursiveEnableItem(name.toString()); | ||
return true; | ||
}, | ||
deleteProperty: (target, name) => { | ||
name = name.toString(); | ||
delete target[name]; | ||
if (this.disabled) | ||
this.recursiveDisableItem(name); | ||
else | ||
this.recursiveEnableItem(name); | ||
return true; | ||
} | ||
}); | ||
_Form_disabledElements.set(this, new Proxy({}, __classPrivateFieldGet(this, _Form_handleDE, "f"))); | ||
/** | ||
* @description Function for read data (For example from DataBase) | ||
@@ -278,2 +278,3 @@ * */ | ||
_Form_saveData.set(this, () => Promise.resolve()); | ||
this.abilities = this.getProxyAbilities(); | ||
if (params.name) | ||
@@ -327,7 +328,7 @@ this.name = params.name; | ||
/** | ||
* Рекурсивное зименение значений. | ||
* По фатку в конечной реализации оно нихуя не рекурсивное. | ||
* Рекурсивное изменение значений. | ||
* В конечной реализации оно нихуя не рекурсивное. | ||
* Реализация 2: для каждой зависимости получает значение из values и устанавливаем его | ||
* Реализация 1: идем рекурсивно по всем значениям, находим подходящие зависимости | ||
* и устанвливаем значения для них. Основная проблема в количетсве итераций. | ||
* и устанавливаем значения для них. Основная проблема в количестве итераций. | ||
* Нужно это протестировать | ||
@@ -350,6 +351,8 @@ * И переименовать метод: changeValuesOfItem(values: any); | ||
this.dependencies.forEach(dep => { | ||
if (!dep.name) | ||
return; | ||
dep.change(getPropFromObject(values, dep.name)); | ||
}); | ||
} | ||
// На данный момент не используется. ПОдсвечивается поскольку рекурсивная | ||
// На данный момент не используется. Подсвечивается поскольку рекурсивная | ||
recursiveChangeItem(values, path = '') { | ||
@@ -402,2 +405,3 @@ Object.keys(values).forEach(key => { | ||
this.dependencies.push(item); | ||
this.emit(Form.EVENT_SUBSCRIBE, item); | ||
return () => this.unsubscribe(item); | ||
@@ -410,2 +414,3 @@ } | ||
this.dependencies.splice(index, 1); | ||
this.emit(Form.EVENT_UNSUBSCRIBE, item); | ||
} | ||
@@ -422,6 +427,9 @@ dependInput(name, i) { | ||
getAssociatedDependencies(name) { | ||
return this.dependencies.filter(dep => { | ||
function t(dep) { | ||
if (dep.name === undefined) | ||
return false; | ||
const depName = dep.name; | ||
return depName.startsWith(name) || name.startsWith(depName); | ||
}); | ||
} | ||
return this.dependencies.filter(t); | ||
} | ||
@@ -440,5 +448,2 @@ /** | ||
} | ||
get disabledElements() { | ||
return __classPrivateFieldGet(this, _Form_disabledElements, "f"); | ||
} | ||
get disabled() { | ||
@@ -449,5 +454,3 @@ return __classPrivateFieldGet(this, _Form_disabled, "f"); | ||
__classPrivateFieldSet(this, _Form_disabled, value, "f"); | ||
this.emit(Form.EVENT_DISABLED, __classPrivateFieldGet(this, _Form_disabled, "f")); | ||
// installation disabledElements | ||
__classPrivateFieldSet(this, _Form_disabledElements, new Proxy({}, __classPrivateFieldGet(this, _Form_handleDE, "f")), "f"); | ||
this.abilities = this.getProxyAbilities(); | ||
if (value) | ||
@@ -458,2 +461,11 @@ this.recursiveDisableItem(); | ||
} | ||
disable(names) { | ||
if (typeof names === "string") | ||
names = [names]; | ||
this.emit(Form.EVENT_DISABLE, names); | ||
// Provided undefined -> full disable form | ||
if (!names) | ||
return this.disabled = true; | ||
names.forEach(name => this.disableByName(name)); | ||
} | ||
recursiveDisableItem(name) { | ||
@@ -482,26 +494,61 @@ // No name - disable all elements | ||
} | ||
disable(name) { | ||
this.emit(Form.EVENT_UPDATE_ABILITY, name); | ||
if (name) | ||
this.disableByName(name); | ||
else | ||
this.disabled = true; | ||
enable(names) { | ||
if (typeof names === "string") | ||
names = [names]; | ||
this.emit(Form.EVENT_ENABLE, names); | ||
if (!names) | ||
return this.disabled = false; | ||
names.forEach(name => this.enableByName(name)); | ||
} | ||
enable(name) { | ||
this.emit(Form.EVENT_UPDATE_ABILITY, name); | ||
if (name) | ||
this.enableByName(name); | ||
else | ||
this.disabled = false; | ||
getProxyAbilities() { | ||
return new Proxy({}, { | ||
defineProperty: (target, name, attributes) => { | ||
const value = attributes.value; | ||
Object.keys(target).forEach(disabledName => { | ||
if (disabledName.startsWith(name.toString())) { | ||
delete target[disabledName]; | ||
} | ||
}); | ||
target[name] = attributes.value; | ||
if (value) | ||
this.recursiveEnableItem(name.toString()); | ||
else | ||
this.recursiveDisableItem(name.toString()); | ||
return true; | ||
}, | ||
deleteProperty: (target, name) => { | ||
name = name.toString(); | ||
delete target[name]; | ||
if (this.disabled) | ||
this.recursiveDisableItem(name); | ||
else | ||
this.recursiveEnableItem(name); | ||
return true; | ||
} | ||
}); | ||
} | ||
disableByName(name) { | ||
if (this.disabled) { | ||
if (name in this.disabledElements) | ||
delete __classPrivateFieldGet(this, _Form_disabledElements, "f")[name]; | ||
/** | ||
* @param {String} name. Element name. | ||
* @param {Boolean} mark. True - Enable, false: disable | ||
* */ | ||
markElementForAbility(name, mark) { | ||
const nearestName = findNearestNameFromArray(name, Object.keys(this.abilities)); | ||
if (!nearestName) { | ||
this.abilities[name] = mark; | ||
return; | ||
} | ||
__classPrivateFieldGet(this, _Form_disabledElements, "f")[name] = true; | ||
// Был найден родительский элемент, сейчас всё зависит от него | ||
// Ближайший элемент заблокирован и нужно заблокировать | ||
if (!this.abilities[nearestName] && !mark) | ||
return; | ||
// Ближайший элемент разблокирован и нужно разблокировать | ||
if (this.abilities[nearestName] && mark) | ||
return; | ||
return this.abilities[name] = mark; | ||
} | ||
disableByName(name) { | ||
return this.markElementForAbility(name, false); | ||
} | ||
enableByName(name) { | ||
__classPrivateFieldGet(this, _Form_disabledElements, "f")[name] = false; | ||
return this.markElementForAbility(name, true); | ||
} | ||
@@ -514,14 +561,6 @@ /** | ||
getDisabledByName(name) { | ||
let refName = name; | ||
// Start with the most relevant level (From the End) | ||
while (refName.length !== 0) { | ||
if (refName in this.disabledElements) | ||
return this.disabledElements[refName]; | ||
const dotIndex = refName.lastIndexOf('.'); | ||
if (dotIndex === -1) | ||
refName = ''; | ||
refName = refName.slice(0, dotIndex); | ||
} | ||
// Not founded relevant value. | ||
return __classPrivateFieldGet(this, _Form_disabled, "f"); | ||
const nearestName = findNearestNameFromArray(name, Object.keys(this.abilities)); | ||
if (!nearestName) | ||
return this.disabled; | ||
return !this.abilities[nearestName]; | ||
} | ||
@@ -567,3 +606,3 @@ /** | ||
if (dep.validate) { | ||
acc = acc && dep.validate(); | ||
acc = acc && !!dep.validate(); | ||
} | ||
@@ -574,8 +613,12 @@ return acc; | ||
} | ||
_Form_values = new WeakMap(), _Form_changes = new WeakMap(), _Form_debug = new WeakMap(), _Form_disabled = new WeakMap(), _Form_handleDE = new WeakMap(), _Form_disabledElements = new WeakMap(), _Form_readData = new WeakMap(), _Form_saveData = new WeakMap(); | ||
Form.PROVIDE_NAME = 'form-controller'; | ||
Form.EVENT_READ = 'read'; | ||
Form.EVENT_SAVE = 'save'; | ||
_Form_values = new WeakMap(), _Form_changes = new WeakMap(), _Form_debug = new WeakMap(), _Form_disabled = new WeakMap(), _Form_readData = new WeakMap(), _Form_saveData = new WeakMap(); | ||
Form.PROVIDE_NAME = 'form-controller'; // LOCK | ||
Form.EVENT_READ = 'read'; // LOCK | ||
Form.EVENT_SAVE = 'save'; // LOCK | ||
Form.EVENT_DISABLE = 'disable'; // LOCK | ||
Form.EVENT_ENABLE = 'enable'; // LOCK | ||
Form.EVENT_SUBSCRIBE = 'subscribe'; // LOCK | ||
Form.EVENT_UNSUBSCRIBE = 'unsubscribe'; // LOCK | ||
Form.EVENT_VALUE = 'value'; | ||
Form.EVENT_UPDATE_ABILITY = 'update:ability'; | ||
Form.EVENT_UPDATE_ABILITY = 'ability:update'; | ||
/** | ||
@@ -582,0 +625,0 @@ * @description Вызывается всякий раз, когда форма была изменена. Внимание! |
{ | ||
"name": "jenesius-vue-form", | ||
"version": "2.0.10", | ||
"version": "2.0.11", | ||
"description": "Heavy form system for Vue.js", | ||
@@ -5,0 +5,0 @@ "author": "Jenesius", |
82731
2.81%43
4.88%1838
3.55%