/** * Create a stateselection widget. As used for address inputs. * * Calling `.presentationUiStateselection()` creates a stateselection as you can see on all addresses in the storefront and backoffice. * * ### Examples * Render stateselection with respect to a already present country selection. * * JavaScript: * * jQuery.ready({ * DOM : true, * plugin : ['de_epages.presentation.ui.stateselection'] * }, function ($) { * de_epages('#' + 'ID50A1052BAC1432E11D38_StateDiv').presentationUiStateselection({ * "input":{ * "name":"State", * "id":"ID50A1052BAC1432E11D38_State", * "mandatoryStar":"*", * "label":"County", * "emptyEntry":"(Select entry)" * }, * "countrySelectId" : "ID50A1052BAC1432E11D38_CountryID", * "cssClasses":{ * "dialogError" : "DialogError", * "inputField" : "InputField", * "inputLabelling" : "InputLabelling", * "input" : "Text", * "select" : "LongText" * }, * "countryId":"276", * "preselectedState":"", * "shopAddressCountryId" : "276", * "formError":false, * "shopRegistrationField":{ * "state":{ * "isVisibleName":false, * "isMandatoryName":false * }, * "countryId":{ * "isVisibleName":true, * "isMandatoryName":true} * } * }, * "data":{ * "300":{"subdivsMandatory":false,"subDivisions":[]}, * "372":{"subdivsMandatory":false,"subDivisions":[]}, * "484":{"subdivsMandatory":true,"subDivisions":[ * { * "code":"BCS", * "language":{ * "english":"Baja California Sur", * "native":"" * } * }, * { * "code":"COA", * "language":{ * "english":"Coahuila", * "native":"" * } * } * ]} * "840":{"subdivsMandatory":true,"subDivisions":[ * {"code":"AL","language":{"english":"Alabama","native":""}} * ]} * } * }); * }); * * HTML: * * <div class="InputBlock"> * <div class="InputLabelling">Country *</div> * <div class="InputField"> * <select name="CountryID" class="LongText" id="ID50A1052BAC1432E11D38_CountryID"> * <option value="">(Select entry)</option> * <option value="372">Ireland</option> * <option value="484">México (Mexico)</option> * <option value="840">United States</option> * <option value="300">Griech (Greece)</option> * </select> * </div> * </div> * * <div id="ID50A1052BAC1432E11D38_StateDiv" class="InputBlock HideElement"> * <div class="InputLabelling"></div> * <div class="InputField"></div> * </div> * * * @class jQuery.ui.presentationUiStateselection * @extends jQuery.widget * * @uses jQuery.tmpl * @uses jQuery.ui.widget * @uses de_epages * @uses ep.ui.validate * @uses ep.ui.input * @since 6.15.0 */ /** * @cfg {Object} input A hash specifying the state input field to be created. (E.g. with keys "name", "id",...) */ /** * @cfg {String} [countrySelectId] Id of the corresponding country select element. */ /** * @cfg {Object} cssClasses A hash specifying the relevant css classes. (E.g. "dialogError", "inputField",...) */ /** * @cfg {String} [countryId] Id of selected country. */ /** * @cfg {String} [preselectedState] Code of preselected state. */ /** * @cfg {String} shopAddressCountryId Id of country of the shop address. */ /** * @cfg {Boolean} formError Boolean indicating whether this state selection caused a formError. */ /** * @cfg {Object} shopRegistrationField Hash specifying whether state/country selection is visible/mandatory for the shop. */ /** * @cfg {Object} data Data hash of the countries and their states. */ /** * See `jQuery.ui.presentationUiStateselection` for details. * * @param {Object} [options] A map of additional options to pass to the method. * @param {Object} input A hash specifying the state input field to be created. (E.g. with keys "name", "id",...) * @param {String} [countrySelectId] Id of the corresponding country select element. * @param {Object} cssClasses A hash specifying the relevant css classes. (E.g. "dialogError", "inputField",...) * @param {String} [countryId] Id of selected country. * @param {String} [preselectedState] Code of preselected state. * @param {String} shopAddressCountryId Id of country of the shop address. * @param {Boolean} formError Boolean indicating whether this state selection caused a formError. * @param {Object} shopRegistrationField Hash specifying whether state/country selection is visible/mandatory for the shop. * @param {Object} data Data hash of the countries and their states. * * @method presentationUiStateselection * @member jQuery * * @since 6.15.0 */ define( "de_epages/presentation/ui/stateselection", [ "jquery", "ep", "de_epages", "$tmpl!./stateselection", "jquery/ui/widget", "ep/ui/validate", "ep/ui/input" ], function ( $, ep, de_epages, tmplStateselection ) { // The widget. $.widget('ui.presentationUiStateselection', { options : {}, _create : function () { var self = this, o = self.options; // Merge in options from data attribute. $.extend(true, o, $.parseJSON(self.element.attr('data-de_epages-presentation-ui-stateselection'))); // Init *change* listener on corresponding *country* *select* element. self.countrySelect = $('#' + o.countrySelectId).on('change.presentationUiStateselection', $.proxy(self, '_onCountrySelect')); // Init input containers. o.cssClasses.inputLabelling && (self.inputLabelling = self.element.find('.' + o.cssClasses.inputLabelling)); self.inputField = (o.cssClasses.inputField && self.element.find('.' + o.cssClasses.inputField)) || self.element; // Trigger initial rendering by setting *countryId*. var initalCountryID = o.countryId ? o.countryId : self.countrySelect.val(); self._setOption('countryId', initalCountryID, true); }, _setOption : function (key, value, calledByCreate) { if (key === 'countryId') { var self = this, o = self.options; // In case we already luckily guessed the countryId before, we do nothing. if (!calledByCreate && o.countryId === value) { return; } this._superApply(arguments); // If there is no country selected we assume the country to be equal to the shop's country. if (!(o.countryId && self.countrySelect.length && o.shopRegistrationField.countryId.isVisibleName)) { o.countryId = o.shopAddressCountryId; } // Render input with newly selected *countryId*. if (o.countryId !== '' ) { self._render(); } } }, _onCountrySelect : function (event) { this._setOption('countryId', this.countrySelect.children(':selected').val()); }, _render : function () { var self = this, o = self.options, hasSubDivisions = false, stateIsMandatory = false, stateIsDisabled = $('#' + o.input.id).prop('disabled'), countryData; // Clean the plate. if (self.input) {self.input.remove();} if (self.inputLabelling) {self.inputLabelling.empty();} if ( o.data[o.countryId] ) { countryData = o.data[o.countryId]; stateIsMandatory = o.shopRegistrationField.state.isMandatoryName || countryData.subdivsMandatory; hasSubDivisions = true; } if ( (stateIsMandatory || o.shopRegistrationField.state.isVisibleName) && hasSubDivisions ) { // Render *input* template. self.input = tmplStateselection({ country: countryData }, o) .prop({ disabled: stateIsDisabled }) .uiValidate({ valid: !o.formError, required: stateIsMandatory }); // Reset *preselectedState* option. Only used for initial *_create*. // E.g. the user is redirected to the form and already entered a state before. self._setOption('preselectedState', ''); // Set *inputLabelling*. if (self.inputLabelling) { self.inputLabelling.append(o.input.label + (stateIsMandatory ? (' ' + o.input.mandatoryStar) : '')); } // Add *input* to *inputField*. self.inputField.empty() .append(self.input); // Show *element*. self.element.removeClass('HideElement'); } else { // Hide *element*. self.element.addClass('HideElement'); // Add hidden input to overwrite previously value on the server-side. // This could/should be handled by the server, but currently is not. self.input = $('<input type="hidden"/>').attr({ name : o.input.name, id : o.input.id, value : '' }); self.input.appendTo(self.inputField); } }, destroy : function () { this.countrySelect && this.countrySelect.length && this.countrySelect.off('change.presentationUiStateselection'); this.inputLabelling && this.inputLabelling.empty(); this.input && this.input.remove(); this._superApply(arguments); } }); return de_epages; });