define([ 'jquery', './options', './utils' ], function ($, Options, Utils) { var Select2 = function ($element, options) { this.$element = $element; if ($element.attr('id') != null) { this.id = $element.attr('id'); } else if ($element.attr('name') != null) { this.id = $element.attr('name') + '-' + Utils.generateChars(2); } else { this.id = Utils.generateChars(4); } this.id = 'select2-' + this.id; options = options || {}; options.multiple = options.multiple || $element.prop('multiple'); this.options = new Options(options); Select2.__super__.constructor.call(this); // Set up containers and adapters var DataAdapter = this.options.get('dataAdapter'); this.data = new DataAdapter($element, this.options); var $container = this.render(); this.$container = $container; $container.insertAfter(this.$element); $container.width($element.outerWidth(false)); var SelectionAdapter = this.options.get('selectionAdapter'); this.selection = new SelectionAdapter($element, this.options); var $selectionContainer = $container.find('.selection'); var $selection = this.selection.render(); $selectionContainer.append($selection); var DropdownAdapter = this.options.get('dropdownAdapter'); this.dropdown = new DropdownAdapter($element, this.options); var $dropdownContainer = $container.find('.dropdown-wrapper'); var $dropdown = this.dropdown.render(); $dropdownContainer.append($dropdown); var ResultsAdapter = this.options.get('resultsAdapter'); this.results = new ResultsAdapter($element, this.options, this.data); var $resultsContainer = $dropdown.find('.results'); var $results = this.results.render(); $resultsContainer.append($results); // Bind events var self = this; this.data.bind(this, $container); this.selection.bind(this, $container); this.dropdown.bind(this, $container); this.results.bind(this, $container); this.$element.on('change', function () { self.data.current(function (data) { self.trigger('selection:update', { data: data }); }); }); this.selection.on('open', function () { self.open(); }); this.selection.on('close', function () { self.close(); }); this.selection.on('toggle', function () { self.toggleDropdown(); }); this.selection.on('results:select', function () { self.trigger('results:select'); }); this.selection.on('results:previous', function () { self.trigger('results:previous'); }); this.selection.on('results:next', function () { self.trigger('results:next'); }); this.selection.on('unselected', function (params) { self.trigger('unselect', params); self.close(); }); this.results.on('selected', function (params) { self.trigger('select', params); self.close(); }); this.results.on('unselected', function (params) { self.trigger('unselect', params); self.close(); }); this.results.on('results:focus', function (params) { self.trigger('results:focus', params); }); this.on('open', function () { $container.addClass('open'); }); this.on('close', function () { $container.removeClass('open'); }); // Set the initial state this.data.current(function (initialData) { self.trigger('selection:update', { data: initialData }); }); this.on('query', function (params) { this.data.query(params, function (data) { self.trigger('results:all', { data: data, query: params }); }); }); this.trigger('query', {}); // Hide the original select $element.hide(); $element.attr('tabindex', '-1'); $element.data('select2', this); }; Utils.Extend(Select2, Utils.Observable); Select2.prototype.toggleDropdown = function () { if (this.isOpen()) { this.close(); } else { this.open(); } }; Select2.prototype.open = function () { if (this.isOpen()) { return; } this.trigger('open'); }; Select2.prototype.close = function () { if (!this.isOpen()) { return; } this.trigger('close'); }; Select2.prototype.isOpen = function () { return this.$container.hasClass('open'); }; Select2.prototype.render = function () { var $container = $( '' + '' + '' + '' ); return $container; }; return Select2; });