Source: modules/ui/SuiBuilder.jsxinc

BX.use('brixy', 'modules/es/types.jsxinc');
BX.use('brixy', 'modules/ui/components/base.jsxinc');

/**
* Easy and fun creation of Adobe ScriptUI user interface.
* 
* @module 'brixy.ui.SuiBuilder'
*/
BX.module.define('brixy.ui.SuiBuilder', function() {
	var baseComponents = BX.module('brixy.ui.components.base');
	
	/**
	* SuiBuilder object.
	* 
	* @class
	* @alias module:'brixy.ui.SuiBuilder'~SuiBuilder
	* @param {string} name - Builder's name. (optional)
	* 
	* @property {Object} _builder - Private builder object.
	* @property {string} _builder.name - Builder's name.
	* @property {component} _builder.element - Current SUI component.
	* @property {component} _builder.container - Current SUI container component.
	* @property {Object} _builder.validator - Validator object.
	* @property {SuiBuilder} _builder.builder - This SuiBuilder instance.
	*/
	function SuiBuilder(name) {
		this._builder = {
			name: name, // builder's name
			element: null, // current element
			container: null, // current container
			validator: null, // validator object
			builder: this, // SuiBuilder instance
			_containers: [], // the chain of the container components
			_ids: {}, // repository of the elements saved by the id() method
			_result: 0, // a result returned from the ScriptUI Window.show() method
			_counter: 0 // the number of the builder methods already executed
		};
	}
	
	/**
	* Returns a string representation of the object.
	* @method
	* @return {string}
	*/
	SuiBuilder.prototype.toString = BX.toString;
	
	/**
	* Returns saved element.
	* 
	* @param {string} id
	* @return {component}
	*/
	SuiBuilder.prototype.get = function (id) {
		return this._builder._ids[id];
	};
	
	/**
	* Returns all saved elements.
	* 
	* @return {Object}
	*/
	SuiBuilder.prototype.getAll = function () {
		return this._builder._ids;
	};
	
	/**
	* Returns a result of the ScriptUI window.show() method.
	* 
	* @return {int}
	*/
	SuiBuilder.prototype.result = function () {
		return this._builder._result;
	};
	
	/**
	* Adds methods into SuiBuilder instance. Existing methods are replaced.
	* 
	* @param {...Object} [components, ...] - Each argument is object with component definitions.
	*/
	SuiBuilder.prototype.addComponents = function (components /* components2, ... */) {
		var n = arguments.length,
			i = 0,
			comps;
			
		for ( ; i < n; i++) {
			comps = arguments[i];
			if (typeof comps === 'object') {
				for (var c in comps) {
					this.addComponent(c, comps[c]);
				}
			}
		}
	};
	
	/**
	* Adds method into SuiBuilder instance. Existing method are replaced.
	* 
	* @param {string} name - Component name.
	* @param {function} callback
	*/
	SuiBuilder.prototype.addComponent = function (name, callback) {
		if (!callback || typeof callback !== 'function')
			throw BX.error('brixy.ui.SuiBuilder.addComponent()', Error('Cannot add component "' + name + '".'), 'Callback must be a function. ' + callback + ' is given.');
			
		this[name] = function(/* custom parameters */) {
			return member.call(this, name, callback, arguments);
		};
	};
	
	/**
	* Adds methods into SuiBuilder prototype.
	* 
	* @param {Object} members - Methods.
	* @param {boolean} [replace=false] - If true, existing methods will be replaced. (optional)
	*/
	SuiBuilder.attach = function (members, replace) {
		if (typeof members === 'object') {
			for (var m in members) {
				if (replace || !(m in SuiBuilder.prototype))
					attachMember(m, members[m]);
			}
		}
	};
	
	/*
	* Adds a method into SuiBuilder prototype.
	* 
	* @param {string} name - Name of the method.
	* @param {function} callback - Method.
	*/
	function attachMember(name, callback) {
		if (!callback || typeof callback !== 'function')
			throw BX.error('brixy.ui.SuiBuilder.attachMember()', Error('Cannot add component "' + name + '".'), 'Callback must be a function. ' + callback + ' is given.');
			
		SuiBuilder.prototype[name] = function(/* custom parameters */) {
			return member.call(this, name, callback, arguments);
		};
	}
	
	/*
	* General builder method.
	* 
	* @param {string} name - Method name.
	* @param {function} callback - Method.
	* @param {Array} args - Arguments for callback.
	* @throws {BX.error.ErrorChain} Exception if component creation failed.
	* @return {SuiBuilder} Provides fluent interface.
	*/
	function member(name, callback, args) {
		try {
			var b = this._builder,
				n;
				
			b._counter++;
			
			callback.apply(b, args);
			
			if (b.container) {
				n = b._containers.length;
				if (!n || b._containers[n-1] !== b.container) {
					b._containers.push(b.container);
					b.element = b.container;
				}
			}
		}
		catch (e) {
			throw createMemberError(this, name, args, e);
		}
		return this;
	}
	
	/**
	* Removes methods from the SuiBuilder prototype.
	* 
	* @param {string|Array<string>} members - The list of the method names to detach.
	*/
	SuiBuilder.detach = function (members) {
		if (!members)
			return;
		
		if (members.constructor.name === 'String') { // one
			remove(members);
		}
		else if (members.constructor.name === 'Array') { // array
			for (var i = 0, n = members.length; i < n; i++) {
				remove(members[i]);
			}
		}
		
		function remove(name) {
			if (name in SuiBuilder.prototype) {
				SuiBuilder.prototype[name] = null;
				delete SuiBuilder.prototype[name];
			}
		}
	};
		
	/*
	* Error factory.
	* 
	* @param {SuiBuilder} builder - SuiBuilder object.
	* @param {string} functionName - Function name.
	* @param {Array} args - Function arguments.
	* @param {Error|string} error - Error message.
	* @return {BX.error.ErrorChain}
	*/
	function createMemberError(builder, functionName, args, error) {
		var method,
			message,
			s,
			ord,
			a = [],
			i,
			n,
			types = BX.module('brixy.es.types');
		
		// method name
		for (i = 0, n = args.length; i < n; i++) {
			a.push(types.valueString(args[i]));
		}
		method = functionName + '(' + a.join(', ') + ')';
		
		// convert _counter to ordinal number
		s = builder._builder._counter.toString(10);
		n = s.length;
		if (n > 1 && s[n-2] === '1')
			ord = s + 'th';
		else
			ord = s + ({1: 'st', 2: 'nd', 3: 'rd'}[s[n-1]] || 'th');

		// error message
		message = (builder._builder.name ? '"' + builder._builder.name + '": ' : 'SuiBuilder: ') + 'the ' + ord + ' method of builder chain failed.';
		
		return new BX.error.ErrorChain('brixy.ui.SuiBuilder.' + method, message, error);
	}
	
	
	// publish
	return {
		/** 
		* SuiBuilder class.
		* @memberOf module:'brixy.ui.SuiBuilder'
		* @type module:'brixy.ui.SuiBuilder'~SuiBuilder
		*/
		Me: SuiBuilder
	};
});