js/vercengen/components/ComponentSelect.js

/**
 * Refer to <span color = "yellow">{@link ve.Component}</span> for methods or fields inherited from this Component's parent such as `.options.attributes` or `.element`.
 * 
 * Conventional select dropdown that returns the key of the option selected by the end user.
 * - Functional binding: <span color=00ffff>veSelect</span>().
 * 
 * ##### Constructor:
 * - `arg0_value`: {@link Object}
 *   - `<option_key>`: {@link Object|string}
 *     - `.name`: {@link string}
 *     - `.selected`: {@link boolean} - Whether the current option is selected.
 * - `arg1_options`: {@link Object}
 *   - `.disabled=false`: {@link boolean}
 * 
 * ##### Instance:
 * - `.v`: {@link string} - The selected option key. 
 * 
 * ##### Methods:
 * - <span color=00ffff>{@link ve.Select.generateHTML|generateHTML}</span>() | {@link Array}<{@link string}> - Returns the HTML for the present select input.
 * 
 * @augments ve.Component
 * @augments {@link ve.Component}
 * @memberof ve.Component
 * @type {ve.Select}
 */
ve.Select = class veSelect extends ve.Component {
	static demo_value = {
		afghanistan: "Afghanistan",
		albania: {
			name: "Albania",
			selected: true
		},
		algeria: "Algeria",
		andorra: "Andorra"
	};
	static demo_options = {
		onchange: (e) => {
			if (ve.debug_mode)
				console.log(`ve.Select: Changed selection to:`, e);
		}
	};
	
	constructor (arg0_value, arg1_options) {
		//Convert from parameters
		let value = arg0_value;
		let options = (arg1_options) ? arg1_options : {};
			super(options);
			
		//Initialise options
		options.attributes = (options.attributes) ? options.attributes : {};
		
		//Declare local instance variables
		let attributes = {
			readonly: options.disabled,
			...options.attributes
		};
		this.element = document.createElement("div");
			this.element.setAttribute("component", "ve-select");
			this.element.instance = this;
		HTML.applyTelestyle(this.element, options.style);
		this.options = options;
		this.value = value;
		
		//Format HTML string
		let html_string = [];
		html_string.push(`<span id = "name"></span>`);
		html_string.push(`<select>`);
			html_string.concat(this.generateHTML());
		html_string.push(`</select>`);
		
		//Populate element and initialise handlers
		this.element.innerHTML = html_string.join("");
		
		let input_el = this.element.querySelector("select");
		input_el.addEventListener("change", (e) => {
			let selected_id = this.element.querySelectorAll("option")[e.target.selectedIndex].id;
			this.from_binding_fire_silently = true;
			this.v = global.String(selected_id);
			delete this.from_binding_fire_silently;
			this.fireToBinding();
		});
		this.v = this.value;
	}
	
	/**
	 * Gets the currently selected key from its `.id`.
	 * - Accessor of: {@link ve.Select}
	 * 
	 * @returns {string}
	 */
	get v () {
		//Return statement
		return this.element.querySelectorAll("option")[
			this.element.querySelector("select").selectedIndex
		].id;
	}
	
	/**
	 * Sets the current selected key value.
	 * - Accessor of: {@link ve.Select}
	 * 
	 * @param {string} arg0_value
	 */
	set v (arg0_value) {
		//Convert from parameters
		let value = arg0_value;
		
		//Declare local instance variables
		if (typeof value === "object") {
			this.value = value;
			this.element.querySelector("select").innerHTML = this.generateHTML().join("");
			Object.iterate(this.value, (local_key, local_value) => {
				if (local_value.selected)
					this.element.querySelector(`option[id="${local_key}"]`).selected = true;
			});
		} else if (typeof value === "string") {
			this.element.querySelector(`option[id="${value}"]`).selected = true;
		}
		this.fireFromBinding();
	}
	
	/**
	 * Returns the HTML string of the present component as an {@link Array}<{@link string}>
	 * 
	 * @returns {string[]}
	 */
	generateHTML () {
		//Declare local instance variables
		let html_string = [];
		
		//Iterate over this.value
		if (typeof this.value === "object")
			Object.iterate(this.value, (local_key, local_value) => {
				if (typeof local_value === "object") {
					html_string.push(`<option id = "${local_key}">${local_value.name}</option>`);
				} else {
					html_string.push(`<option id = "${local_key}">${local_value}</option>`);
				}
			});
		
		//Return statement
		return html_string;
	}
};

//Functional binding

/**
 * @returns {ve.Select}
 */
veSelect = function () {
	//Return statement
	return new ve.Select(...arguments);
};