VaKeR CYBER ARMY
Logo of a company Server : Apache/2.4.41 (Ubuntu)
System : Linux absol.cf 5.4.0-198-generic #218-Ubuntu SMP Fri Sep 27 20:18:53 UTC 2024 x86_64
User : www-data ( 33)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Directory :  /var/www/html/libs/absol-form/js/editor/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /var/www/html/libs/absol-form/js/editor/PropertyEditor.js
import FCore from '../core/FCore';
import Context from 'absol/src/AppPattern/Context';
import EventEmitter from 'absol/src/HTML5/EventEmitter';
import '../../css/propertyeditor.css';
import { camelCaseToPascalCase } from 'absol/src/String/stringFormat';
import { beginOfDay } from 'absol/src/Time/datetime';
import ListEditor from './ListEditor';
import { FONT_ITEMS } from '../font/GoogleFont';
import '../dom/FontIconInput';
import QuickMenu from 'absol-acomp/js/QuickMenu';
import { base64EncodeUnicode } from 'absol/src/Converter/base64';

// FontIconPicker

var _ = FCore._;
var $ = FCore.$;


function PropertyEditor() {
    Context.call(this);
    EventEmitter.call(this);
    this.dependents = {};
    this.$view = null;
    this.propertyHolders = {};
    /**
     * @type {import('../core/BaseComponent').default}
     */
    this.object = null;
    this.propertyNames = [];
    this.$needUpdate = [];// all element which had .as-need-update
    this.queuePools = {};
}

Object.defineProperties(PropertyEditor.prototype, Object.getOwnPropertyDescriptors(Context.prototype));
Object.defineProperties(PropertyEditor.prototype, Object.getOwnPropertyDescriptors(EventEmitter.prototype));
PropertyEditor.prototype.constructor = PropertyEditor;

PropertyEditor.prototype.pools = {};//share object


PropertyEditor.prototype.onDestroy = function () {
    this.flushAllToPools();
};


PropertyEditor.prototype.edit = function (object) {
    this.object = object;
    this.loadAttributes();
};



PropertyEditor.prototype.setProperty = function (name, value) {
    return this.object[name] = value;
};


PropertyEditor.prototype.getProperty = function (name) {
    return this.object[name];
};


PropertyEditor.prototype.getPropertyDescriptor = function (name) {
    return { type: typeof (this.object) };
};



PropertyEditor.prototype.getPropertyNames = function () {
    return Object.keys(this.object);
};

PropertyEditor.prototype.flushAllToPools = function () {
    var self = this;
    Object.keys(this.queuePools).forEach(function (key) {
        self.pools[key] = self.pools[key] === undefined ? [] : self.pools[key];
        var all = self.queuePools[key].splice(0);
        self.pools[key].push.apply(self.pools[key], all);
    });
};


PropertyEditor.prototype.assignToPool = function (key, value) {
    this.queuePools[key] = this.queuePools[key] === undefined ? [] : this.queuePools[key];
    if (value.__pool_assign__) {
        console.warn("Pool: reassign object", key, value);
    }
    else {
        value.__pool_assign__ = true;
        this.queuePools[key].push(value);
    }
};


PropertyEditor.prototype.putOnceFromPool = function (key) {
    var res = null;
    if (this.pools[key] && this.pools[key].length > 0) {
        res = this.pools[key].pop();
    }
    if (res) res.__pool_assign__ = false;
    return res;
};


PropertyEditor.prototype.loadAttributes = function () {
    var self = this;
    this.flushAllToPools();
    self.$body.clearChild();
    this.clearAllDependents();
    this.propertyNames = [];
    this.$rows = [];
    this.$needUpdate = [];
    if (!this.object) return;
    this.propertyNames = this.getPropertyNames();
    this.propertyHolders = {};
    this.propertyNames.forEach(function (name) {
        var descriptor = self.getPropertyDescriptor(name) || { type: "NoDescriptor" };
        if (descriptor.dependency) {
            self.addDependents(name, descriptor.dependency);
        }
        var functionName = 'load' + camelCaseToPascalCase(descriptor.type) + 'Property';
        var cell = _('td');
        if (!self[functionName]) {
            // throw new Error('Not support type' + descriptor.type + '!')
            functionName = 'loadNotSupportedProperty';
        };
        var rowElt = _({
            tag: 'tr',
            child: [
                { tag: 'td', child: { text: name } },
                cell
            ]
        })
        rowElt.addTo(self.$body);
        self.propertyHolders[name] = self[functionName](name, descriptor, cell, cell);
    });
};


PropertyEditor.prototype.loadNotSupportedProperty = function (name, descriptor, cell, cellElt) {
    cellElt.addChild(_({ text: 'Not supported ' }))
        .addChild(_({
            tag: 'strong',
            child: { text: descriptor.type }
        }));
    return {};
};




PropertyEditor.prototype.loadEnumProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    var selectMenu = descriptor.sign ? this.putOnceFromPool(descriptor.sign) : null;
    if (selectMenu === null) {
        selectMenu = _({
            tag: 'selectmenu',
            props: {
                items: descriptor.values.map(function (value) { return { text: value + "", value: value } }),

                value: this.getProperty(name)
            },
            on: {
                change: function () {
                    this.peditor.setProperty(name, this.value);
                    this.peditor.notifyChange(name, this);
                    this.peditor.notifyStopChange(name);
                }
            }
        });
    }
    if (descriptor.sign)
        this.assignToPool(descriptor.sign, selectMenu);
    selectMenu.value = this.getProperty(name);
    selectMenu.peditor = this;
    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value != this.value) {
            selectMenu.value = value;
        }
    };
    cell.addChild(selectMenu);

    return res;
};


PropertyEditor.prototype.loadFontProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    var fontInput = descriptor.sign ? this.putOnceFromPool(descriptor.sign) : null;
    if (fontInput === null) {
        fontInput = _({
            tag: 'selectmenu',
            class: 'as-need-update',
            props: {
                items: [{ text: 'None', value: undefined }].concat(FONT_ITEMS)
            },
            on: {
                change: function () {
                    this.peditor.setProperty(name, this.value);
                    this.peditor.notifyChange(name, this);
                    this.peditor.notifyStopChange(name);
                }
            }
        });
    }
    if (descriptor.sign)
        this.assignToPool(descriptor.sign, fontInput);
    fontInput.value = this.getProperty(name);
    fontInput.peditor = this;

    res.elt = fontInput;
    cell.addChild(res.elt);
    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value != fontInput.value) {
            fontInput.value = value;
        }
    };

    return res;
};


PropertyEditor.prototype.loadConstProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.elt = _({
        tag: 'strong',
        child: { text: '' + descriptor.value }
    });
    cell.addChild(res.elt);
    return res;
};

PropertyEditor.prototype.loadTextProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.elt = _({
        tag: descriptor.long ? 'textarea' : 'input',
        attr: { type: 'text' },
        on: {
            keyup: function () {
                self.setProperty(name, this.value);
                self.notifyChange(name, this);
            },
            change: function () {
                self.notifyStopChange(name);
            }
        }
    });
    cell.addChild(res.elt);
    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value != this.value) {
            res.elt.value = value;
        }
    };
    res.requestUpdate();
    return res;
};

PropertyEditor.prototype.loadUniqueTextProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.elt = _({
        tag: descriptor.long ? 'textarea' : 'input',
        attr: { type: 'text' },
        on: {
            keyup: function () {
                if (descriptor.others[this.value]) {
                    this.addStyle('border-color', '#f99');
                    this.attr('title', 'This name is used!')

                }
                else {
                    this.attr('title', null)
                    this.removeStyle('border-color');
                }
                self.setProperty(name, this.value);
                self.notifyChange(name, this);
            },
            change: function () {
                if (descriptor.others[this.value]) {
                    this.addStyle('border-color', '#f99');
                    this.attr('title', 'This name is used!')

                }
                else {
                    this.attr('title', null)
                    this.removeStyle('border-color');
                }
                self.notifyStopChange(name);
            }
        }
    });
    cell.addChild(res.elt);
    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value != this.value) {
            res.elt.value = value;
        }
    };
    res.requestUpdate();
    return res;
};


PropertyEditor.prototype.loadBoolProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.elt = _({
        tag: 'checkboxbutton',
        class: 'as-need-update',
        props: {
            checked: this.getProperty(name),
            notifyChange: function () {

            }
        },
        on: {
            change: function () {
                self.setProperty(name, this.checked);
                self.notifyChange(name, this);
                self.notifyStopChange(name);
            }
        }
    });

    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value != res.elt.checked) {
            res.elt.checked = value;
        }
    };

    cell.addChild(res.elt);
    return res;
};


PropertyEditor.prototype.loadDateProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.calendarInput = _({
        tag: 'calendarinput',
        props: {
            disabled: descriptor.disabled,
            value: self.getProperty(name),
        },
        on: {
            change: function () {
                self.setProperty(name, this.value);
                self.notifyChange(name, this);
                res.nullCheckElt.checked = false;
                self.notifyStopChange(name);
            }
        }
    });
    cell.addChild(res.calendarInput);
    res.nullCheckElt = _({
        tag: 'checkbox',
        style: { marginLeft: '10px' },
        props: {
            text: 'NULL'
        },
        on: {
            change: function () {
                if (this.checked) {
                    self.setProperty(name, null);
                }
                else {
                    self.setProperty(name, beginOfDay(new Date()));
                }
                self.notifyChange(name, this);
                self.notifyStopChange(name);
            }
        }
    });
    cell.addChild(res.nullCheckElt);

    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (!value) {
            res.calendarInput.value = null;
            res.nullCheckElt.checked = true;
        }
        else {
            res.calendarInput.value = value; res.nullCheckElt.checked = false;
        }
        res.calendarInput.disabled = self.getPropertyDescriptor(name).disabled;
    };
    return res;
};

PropertyEditor.prototype.loadNumberProperty = function (name, descriptor, cell) {
    var self = this;
    var numberInput = this.putOnceFromPool("NUMBER_INPUT");//same with all sign
    if (numberInput === null) {
        numberInput = _({
            tag: 'numberinput',
            class: 'as-need-update',
            props: {

            },
            on: {
                change: function (event) {
                    if (event.by == 'keyup') return;
                    if (!descriptor.livePreview && event.by == 'long_press_button') return;
                    this.peditor.setProperty(this._propertyName, this.value);
                    this.peditor.notifyChange(this._propertyName, this);
                    if (event.by != 'long_press_button')
                        this.peditor.notifyStopChange(this._propertyName);
                }
            }
        }
        );
    }
    if (descriptor.sign)
        this.assignToPool(descriptor.sign, numberInput);
    numberInput.min = typeof (descriptor.min) == 'number' ? descriptor.min : -Infinity;
    numberInput.max = typeof (descriptor.max) == 'number' ? descriptor.max : Infinity;
    numberInput.value = this.getProperty(name);
    numberInput.disabled = descriptor.disabled;
    numberInput._propertyName = name;
    numberInput.peditor = this;
    var res = { elt: numberInput };
    res.requestUpdate = function () {
        var value = self.getProperty(name);
        if (value === null)
            res.elt.value = descriptor.defaultValue;
        else
            res.elt.value = value;
        res.elt.disabled = self.getPropertyDescriptor(name).disabled;
    }
    cell.addChild(res.elt);
    //todo NULL
    return res;
};


PropertyEditor.prototype.loadIconProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    //todo: disabled
    res.elt = _({
        tag: 'fonticoninput',
        class: 'as-need-update',
        props: {
            value: self.getProperty(name),
            disabled: descriptor.disabled
        },
        on: {
            change: function (event) {
                self.setProperty(name, this.value);
                self.notifyStopChange(name, this);
            }
        }
    });
    cell.addChild(res.elt);
    res.requestUpdate = function () {
        res.elt.value = self.getProperty(name);
    };
    return res;
};


PropertyEditor.prototype.loadListProperty = function (name, descriptor, cell) {
    var self = this;
    var listEditor = new ListEditor();
    var res = {};
    res.elt = listEditor.getView();
    cell.addChild(res.elt);
    listEditor.on('change', function () {
        self.setProperty(name, this.getData());
        self.notifyStopChange(name);
    });
    listEditor.start();
    // res.
    listEditor.setData(this.getProperty(name));
    return res;
};


PropertyEditor.prototype.loadTextAlignProperty = function (name, descriptor, cell) {
    var self = this;
    var icons = {
        left: 'mdi-format-align-left',
        right: 'mdi-format-align-right',
        center: 'mdi-format-align-center'
    };
    var res = {};
    res.elt = _({
        tag: 'button',
        class: 'as-property-editor-text-align-input',
        child: 'span.mdi'
    });
    cell.addChild(res.elt);

    var $button = res.elt;
    var $icon = $('span.mdi', $button);
    var lasIconClass = icons[this.getProperty(name)] || icons.left;
    $icon.addClass(lasIconClass);
    res.requestUpdate = function () {
        $icon.removeClass(lasIconClass);
        lasIconClass = icons[self.getProperty(name)] || icons.left;
        $icon.addClass(lasIconClass);
    };
    var self = this;
    QuickMenu.toggleWhenClick($button, {
        getMenuProps: function () {
            return {
                items: [
                    {
                        text: 'Left',
                        icon: 'span.mdi.mdi-format-align-left',
                        menuData: 'left'
                    },
                    {
                        text: 'Center',
                        icon: 'span.mdi.mdi-format-align-center',
                        menuData: 'center'
                    },
                    {
                        text: 'Right',
                        icon: 'span.mdi.mdi-format-align-right',
                        menuData: 'right'

                    }
                ]
            }
        },
        onSelect: function (item) {
            $icon.removeClass(lasIconClass);
            lasIconClass = icons[item.menuData];
            $icon.addClass(lasIconClass);
            self.setProperty(name, item.menuData);
            self.notifyStopChange(name);
        }
    });
    return res;
};


PropertyEditor.prototype.loadBoxAlignProperty = function (name, descriptor, cell) {
    var self = this;
    var icons = {
        lefttop: 'm0 0v24h24v-24zm1 1h22v22h-22zm2 2h10.3v2h-10.3v-2m0 4h14v2h-14v-2m0 4h9.9v2h-9.9v-2',
        centertop: 'm24 24v-24h-24v24zm-1-1h-22v-22h22zm-6.05-18h-9.9v-2h9.9v2m2.05 4h-14v-2h14v2m-1.85 4h-10.3v-2h10.3v2',
        righttop: 'm24 0v24h-24v-24zm-1 1h-22v22h22zm-2 2h-10.3v2h10.3v-2m0 4h-14v2h14v-2m0 4h-9.9v2h9.9v-2',
        leftcenter: 'm0 24v-24h24v24zm1-1h22v-22h-22zm2-6h10.3v-2h-10.3v2m0-4h14v-2h-14v2m0-4h9.9v-2h-9.9v2',
        centercenter: 'm0 24v-24h24v24zm1-1h22v-22h-22zm6.05-14h9.9v-2h-9.9v2m-2.05 4h14v-2h-14v2m1.85 4h10.3v-2h-10.3v2',
        rightcenter: 'm24 24v-24h-24v24zm-1-1h-22v-22h22zm-2-6h-10.3v-2h10.3v2m0-4h-14v-2h14v2m0-4h-9.9v-2h9.9v2',
        leftbottom: 'm0 24v-24h24v24zm1-1h22v-22h-22zm2-2h10.3v-2h-10.3v2m0-4h14v-2h-14v2m0-4h9.9v-2h-9.9v2',
        centerbottom: 'm24 0v24h-24v-24zm-1 1h-22v22h22zm-6.05 18h-9.9v2h9.9v-2m2.05-4h-14v2h14v-2m-1.85-4h-10.3v2h10.3v-2',
        rightbottom: 'm24 24v-24h-24v24zm-1-1h-22v-22h22zm-2-2h-10.3v-2h10.3v2m0-4h-14v-2h14v2m0-4h-9.9v-2h9.9v2'
    };
    function makeIcon(path) {
        var data = '<svg width="24" height="24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">\
                    <path d="'+ path + '" style="stroke-width:0"/>\
                </svg>';
        return {
            tag: 'img',
            style: {
                'image-rendering': 'pixelated'
            },
            props: {
                src: 'data:image/svg+xml;base64,' + base64EncodeUnicode(data)
            }
        }
    }

    var res = {};
    res.elt = _('button.as-property-editor-text-align-input', res);
    cell.addChild(res.elt);
    res.elt.addChild(_(makeIcon(icons[this.getProperty(name)] || icons.lefttop)));
    QuickMenu.toggleWhenClick(res.elt, {
        getMenuProps: function () {
            return {
                items: [
                    {
                        text: 'Left-Top',
                        icon: makeIcon(icons.lefttop),
                        menuData: 'lefttop'
                    },
                    {
                        text: 'Center-Top',
                        icon: makeIcon(icons.centertop),
                        menuData: 'centertop'
                    },
                    {
                        text: 'Right-Top',
                        icon: makeIcon(icons.righttop),
                        menuData: 'righttop'
                    },
                    {
                        text: 'Left-Center',
                        icon: makeIcon(icons.leftcenter),
                        menuData: 'leftcenter'
                    },
                    {
                        text: 'Center-Center',
                        icon: makeIcon(icons.centercenter),
                        menuData: 'centercenter'
                    },
                    {
                        text: 'Right-Center',
                        icon: makeIcon(icons.rightcenter),
                        menuData: 'rightcenter'
                    },
                    {
                        text: 'Left-Botttom',
                        icon: makeIcon(icons.leftbottom),
                        menuData: 'leftbottom'
                    },
                    {
                        text: 'Center-Botttom',
                        icon: makeIcon(icons.centerbottom),
                        menuData: 'centerbottom'
                    },
                    {
                        text: 'Right-Botttom',
                        icon: makeIcon(icons.rightbottom),
                        menuData: 'rightbottom'
                    }
                ]
            }
        },
        onSelect: function (item) {
            res.elt.clearChild().addChild(_(makeIcon(icons[item.menuData])));
            self.setProperty(name, item.menuData);
            self.notifyStopChange(name);
        }
    });

    res.requestUpdate = function () {
        res.elt.clearChild().addChild(_(makeIcon(icons[self.getProperty(name)] || icons.lefttop)));
    };
    return res;
};


PropertyEditor.prototype.loadColorProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    res.elt = _({
        tag: 'colorpickerbutton',
        on: {
            change: function (event) {
                self.setProperty(name, '#' + event.value.toHex8());
                self.notifyChange(name);
            },
            stopchange: function (event) {
                self.notifyStopChange(name);
            }
        },
        props: {
            value: 'transparent',
            mode: 'RGBA'
        }
    });

    cell.addChild(res.elt);

    res.requestUpdate = function () {
        res.elt.value = self.getProperty(name);
    };

    res.requestUpdate();
    return res;
};


PropertyEditor.prototype.loadMeasureSizeProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    cell.addStyle('white-space', 'nowrap');
    res.numberInputElt = _('numberinput').addStyle('margin-right', '5px');
    res.typeSelectElt = _({
        tag: 'selectmenu',
        style: {
            verticalAlign: 'middle'
        },
        props: {
            items: [
                { text: 'px', value: 'px' },
                { text: '%', value: '%' },
                { text: 'match_parent', value: 'match_parent' },
                { text: 'auto', value: 'auto' }
            ]
        }
    });

    cell.addChild(res.numberInputElt)
        .addChild(res.typeSelectElt);
    res.numberInputElt.on('change', function (event) {
        if (event.by == 'keyup') return;
        switch (res.typeSelectElt.value) {
            case '%': self.setProperty(name, this.value + '%'); break;
            case 'px': self.setProperty(name, this.value); break;
        }
        self.notifyChange(name);
        if (event.by != 'long_press_button')
            self.notifyStopChange(name);
    })
        .on('stopchange', function () {
            switch (res.typeSelectElt.value) {
                case '%': self.setProperty(name, this.value + '%'); break;
                case 'px': self.setProperty(name, this.value); break;
            }
            self.notifyStopChange(name);
        });

    res.typeSelectElt.on('change', function (event) {
        if (this.value == 'match_parent' || this.value == 'auto') {
            self.setProperty(name, this.value);
            res.numberInputElt.disabled = true;
        }
        else {
            res.numberInputElt.disabled = false;
            var value = self.getProperty(name, this.value);
            res.numberInputElt.value = value;
            if (this.value == '%') {
                self.setProperty(name, value + '%');
            }
            else {
                self.setProperty(name, value);
            }
        }
        self.notifyChange(name);
        self.notifyStopChange(name);
    });


    res.requestUpdate = function () {
        var descriptor = self.getPropertyDescriptor(name);
        if (descriptor.disabled) res.numberInputElt.disabled = !!descriptor.disabled;
        var value = self.getProperty(name);
        if (typeof value == 'number') {
            res.numberInputElt.value = value;
            res.typeSelectElt.value = 'px';
        }
        else if (typeof value == 'string') {
            if (value.match(/\%$/)) {
                res.typeSelectElt.value = '%';
                res.numberInputElt.value = parseFloat(value.replace('%', ''));
                res.numberInputElt.disabled = false;
            }
            else if (value == 'match_parent' || value == 'auto') {
                res.numberInputElt.disabled = true;
                res.typeSelectElt.value = value;
            }
            else {
                console.error("Unknow typeof " + name, value);
            }
        }
    }

    res.requestUpdate();
    return res;
};


PropertyEditor.prototype.loadMeasurePositionProperty = function (name, descriptor, cell) {
    var self = this;
    var res = {};
    cell.addStyle('white-space', 'nowrap');
    res.numberInputElt = _('numberinput').addStyle('margin-right', '5px');
    res.typeSelectElt = _({
        tag: 'selectmenu',
        style: {
            verticalAlign: 'middle'
        },
        props: {
            items: [
                { text: 'px', value: 'px' },
                { text: '%', value: '%' }
            ]
        }
    });

    cell.addChild(res.numberInputElt)
        .addChild(res.typeSelectElt);
    res.numberInputElt.on('change', function (event) {
        if (event.by == 'keyup') return;
        switch (res.typeSelectElt.value) {
            case '%': self.setProperty(name, this.value + '%'); break;
            case 'px': self.setProperty(name, this.value); break;
        }
        self.notifyChange(name);
        if (event.by != 'long_press_button')
            self.notifyStopChange(name);
    })
        .on('stopchange', function () {
            switch (res.typeSelectElt.value) {
                case '%': self.setProperty(name, this.value + '%'); break;
                case 'px': self.setProperty(name, this.value); break;
            }
            self.notifyStopChange(name);
        });

    res.typeSelectElt.on('change', function (event) {
        if (this.value == 'match_parent' || this.value == 'auto') {
            self.setProperty(name, this.value);
            res.numberInputElt.disabled = true;
        }
        else {
            res.numberInputElt.disabled = false;
            var value = self.getProperty(name, this.value);
            res.numberInputElt.value = value;
            if (this.value == '%') {
                self.setProperty(name, value + '%');
            }
            else {
                self.setProperty(name, value);
            }
        }
        self.notifyChange(name);
        self.notifyStopChange(name);
    });


    res.requestUpdate = function () {
        var descriptor = self.getPropertyDescriptor(name);
        res.numberInputElt.disabled = !!descriptor.disabled;
        var value;
        if (descriptor.disabled) {
            value = self.getProperty(name, res.typeSelectElt.value);
            res.numberInputElt.value = value;
            //set-back
            if (res.typeSelectElt.value == 'px') {
                self.setProperty(name, value);
            }
            else if (res.typeSelectElt.value == '%') {
                self.setProperty(name, value + '%');
            }
        }
        else {
            value = self.getProperty(name);
            if (typeof value == 'number') {
                res.numberInputElt.value = value;
                res.typeSelectElt.value = 'px';
            }
            else if (typeof value == 'string') {
                if (value.match(/\%$/)) {
                    res.typeSelectElt.value = '%';
                    res.numberInputElt.value = parseFloat(value.replace('%', ''));
                }
                else {
                    console.error("Unknow typeof " + name, value);
                }
            }
        }
    }

    res.requestUpdate();
    return res;
};



PropertyEditor.prototype.getView = function () {
    if (this.$view) return this.$view;
    this.$view = _({
        class: 'as-property-editor',
        child: {
            tag: 'table',
            child: [
                {
                    tag: 'thead',
                    child: [

                        {
                            tag: 'tr',
                            child: [
                                {
                                    tag: 'td',
                                    child: { text: "key" }
                                },
                                {
                                    tag: 'td',
                                    attr: { colspan: '3' },
                                    child: { text: 'value' }
                                }
                            ]
                        }
                    ]
                },
                {
                    tag: 'tbody'
                }
            ]
        }
    });
    this.$body = $('tbody', this.$view);
    return this.$view;
};


PropertyEditor.prototype.clearAllDependents = function () {
    for (var key in this.dependents)
        delete this.dependents[key];
};


/**
 * @param {String} propertyName
 * @param {Array<String>} dependencyProperties
 */
PropertyEditor.prototype.addDependents = function (propertyName, dependencyProperties) {
    var dependencyProperty;
    for (var i = 0; i < dependencyProperties.length; ++i) {
        dependencyProperty = dependencyProperties[i];
        this.dependents[dependencyProperty] = this.dependents[dependencyProperty] || {};
        this.dependents[dependencyProperty][propertyName] = true;
    }
};

PropertyEditor.prototype.updateDependentsOf = function (name, excludes) {
    excludes = excludes || {};
    excludes[name] = true;
    for (var dependentPropertyName in this.dependents[name]) {
        if (!excludes[dependentPropertyName] && this.propertyHolders[dependentPropertyName]) {
            excludes[dependentPropertyName] = true;
            if (this.propertyHolders[dependentPropertyName].requestUpdate) {
                this.propertyHolders[dependentPropertyName].requestUpdate();
            }
            this.updateDependentsOf(dependentPropertyName, excludes);
        }
    }
};

PropertyEditor.prototype.updatePropertyRecursive = function (name) {
    if (!this.propertyHolders[name]) return;
    if (this.propertyHolders[name].requestUpdate)
        this.propertyHolders[name].requestUpdate();
    this.updateDependentsOf(name);
}


PropertyEditor.prototype.notifyChange = function (name, from) {
    this.updateDependentsOf(name);
    this.emit('change', { type: 'change', target: this, from: from, name: name, object: this.object }, this);
};


PropertyEditor.prototype.notifyStopChange = function (name) {
    this.emit('stopchange', { type: 'stopchange', name: name, object: this.object }, this);
};


export default PropertyEditor;

VaKeR 2022