1 /*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
2 newcap:true, noarg:true, regexp:true, undef:true, trailing:true,
4 /*global enyo:true, XM:true, XT:true, XV:true, _:true, console:true */
10 @class An input control for the Advanced Search feature
11 in which the user specifies one or more search parameters.<br />
12 Represents one search parameter.
13 A component of {@link XV.ParameterWidget}.
16 /** @lends XV.ParameterItem# */{
17 name: "XV.ParameterItem",
18 classes: "xv-parameter-item",
25 isCharacteristic: false
31 onValueChange: "parameterChanged"
36 defaultKind: "XV.InputWidget",
38 Sets up widget in parameter item.
41 this.inherited(arguments);
43 if (!this.getOperator() && this.defaultKind === "XV.InputWidget") {
44 this.setOperator("MATCHES");
45 } else if (this.$.input instanceof XV.PickerWidget) {
46 this.$.input.setNoneText("_any".loc());
50 Sets the label value of the parameter item to that
51 specified in the kind definition.
53 labelChanged: function () {
54 this.$.input.setLabel(this.label);
57 Returns the search parameter object.
59 getParameter: function () {
61 attr = this.getAttr(),
62 value = this.getValue();
63 if (attr && value !== undefined && value !== null && value !== "") {
66 operator: this.getOperator(),
67 isCharacteristic: this.getIsCharacteristic(),
74 Returns the value of the parameter.
76 getValue: function () {
77 var value = this.$.input.getValue();
78 if (value && this.$.input.valueAttribute) {
79 value = value.get(this.$.input.valueAttribute);
84 This stores the originating parameter item and it's value
85 in an event and bubbles up a parameter change to the
88 parameterChanged: function () {
89 var inEvent = { value: this.getValue, originator: this };
90 this.doParameterChange(inEvent);
91 return true; // stop right here
93 setDisabled: function (disabled) {
94 if (this.$.input.setDisabled) {
95 return this.$.input.setDisabled(disabled);
100 Sets the value of the parameter item.
102 setValue: function (value, options) {
103 this.$.input.setValue(value, options);
109 @name XV.ParameterWidget
110 @class Contains a set of fittable rows to implement the Advanced Search feature.<br />
111 Each row is a {@link XV.ParameterItem} and represents a parameter on which
112 the user can narrow the search results.<br />
113 Derived from <a href="http://enyojs.com/api/#enyo.FittableRows">enyo.FittableRows</a>.
114 @extends enyo.FittableRows
116 enyo.kind(enyo.mixin(/** @lends XV.ParameterWidget# */{
117 name: "XV.ParameterWidget",
118 kind: "FittableRows",
119 classes: "xv-parameter-panel", // mixin class from workspace to pullout
121 onItemSave: "saveItem",
122 onItemChange: "loadItem",
123 onParameterChange: "parameterChanged"
126 onParameterChange: ""
129 characteristicsRole: undefined,
130 showSaveFilter: true,
136 defaultParameters: null,
137 defaultKind: "XV.ParameterItem",
140 Setup function for the parameter widget which adds the
141 item management forms to the top of the kind and the
142 characteristics to the bottom of the kind. Also loads
143 the last filter choice and sets the parameter values for
146 create: function () {
147 var role = this.getCharacteristicsRole(),
148 K = XM.Characteristic,
153 this.inherited(arguments);
154 this.processExtensions();
155 this.isAllSetUp = true;
159 if (XM.characteristics.where(hash).length) {
161 this.createComponent({
162 kind: "onyx.GroupboxHeader",
163 content: "_characteristics".loc()
166 // Process text and list
167 chars = XM.characteristics.filter(function (char) {
168 var type = char.get('characteristicType');
169 return char.get(role) &&
170 char.get('isSearchable') &&
171 (type === K.TEXT || type === K.LIST);
174 _.each(chars, function (char) {
177 name: char.get('name') + "Characteristic",
178 label: char.get('name'),
179 isCharacteristic: true,
180 attr: char.get('name')
182 if (char.get('characteristicType') === K.LIST) {
184 kind: "XV.PickerWidget",
185 idAttribute: "value",
186 nameAttribute: "value",
187 create: function () {
188 this.inherited(arguments);
191 filteredList: function () {
192 return char.get('options').models;
194 getValue: function () {
195 return this.value ? this.value.get('value') : null;
198 hash.defaultKind = kind;
200 that.createComponent(hash);
204 chars = XM.characteristics.filter(function (char) {
205 var type = char.get('characteristicType');
206 return char.get(role) &&
207 char.get('isSearchable') &&
211 _.each(chars, function (char) {
212 that.createComponent({
213 kind: "onyx.GroupboxHeader",
214 content: char.get('name').loc()
218 name: char.get('name') + "FromCharacteristic",
219 label: "_from".loc(),
220 filterLabel: char.get('name') + " " + "_from".loc(),
222 attr: char.get('name'),
223 isCharacteristic: true,
224 defaultKind: "XV.DateWidget"
226 that.createComponent(hash);
229 name: char.get('name') + "ToCharacteristic",
231 filterLabel: char.get('name') + " " + "_to".loc(),
233 attr: char.get('name'),
234 isCharacteristic: true,
235 defaultKind: "XV.DateWidget"
237 that.createComponent(hash);
241 // Sets published defaultFilter with the params object
242 // from the defaultParameters in the parameter widget (if exists)
243 this.setDefaultFilter(_.result(this, 'defaultParameters'));
245 // The "null" value of addBefore will add this
246 // component to the beginning of the array.
247 if (this.getShowSaveFilter()) {
248 compArray.push({kind: "XV.FilterForm", name: "filterForm", addBefore: null});
251 if (this.getShowLayout()) {
252 compArray.push({kind: "XV.LayoutForm", name: "layoutForm", addBefore: null});
255 this.createComponents(compArray, {owner: this});
256 this.populateFromUserPref();
260 Sends list object from the parent kind to the layout form
262 @param {Object} index
264 buildColumnList: function (list) {
265 this.$.layoutForm.addColumns(list);
268 When the default filter is set, populate the
269 params with the values.
271 defaultFilterChanged: function () {
272 // if defaults are null, this does nothing
273 this.populateParameters(this.getDefaultFilter());
276 Returns an array of the parameter search objects.
278 getParameters: function () {
283 for (i = 0; i < this.children.length; i++) {
284 child = this.children[i];
285 param = child && child.showing && child.getParameter ?
286 child.getParameter() : null;
288 // using union instead of push here in case param is an array of params
289 params = _.union(params, param);
295 Retrieves parameter values. By default returns values as human readable
296 strings. Boolean options are:<br />
297 * name - If true returns the parameter item control name, otherwise returns the label.<br />
298 * value - If true returns the control value, other wise returns a human readable string.<br />
299 * deltaDate - If true returns as string for the date difference for date widgets. (i.e. "+5").
300 @param {Object} options
302 getSelectedValues: function (options) {
303 options = options || {};
314 for (componentName in this.$) {
315 if (this.$[componentName] instanceof XV.ParameterItem &&
316 this.$[componentName].showing &&
317 this.$.hasOwnProperty(componentName)) {
318 component = this.$[componentName];
319 value = component.getValue();
320 label = options.name ?
321 component.getName() :
322 component.getFilterLabel() || component.getLabel();
323 control = component.$.input;
324 if (component.$.input.kind === 'XV.CheckboxWidget') {
326 values[label] = value;
327 } else if (value === true) {
328 values[label] = control.getValueToString ? control.getValueToString() : value;
331 // Special handling for toggle buttons that work opposite,
332 // meaning only show me when it's "off"
333 } else if (component.$.input.kind === 'XV.ToggleButtonWidget') {
335 values[label] = value;
336 } else if (value === false) {
337 values[label] = control.getValueToString ? control.getValueToString() : value;
339 } else if (value !== undefined && value !== null && value !== "") {
340 if (options.deltaDate &&
341 component.$.input.kind === 'XV.DateWidget') {
342 today = XT.date.today();
343 date = XT.date.applyTimezoneOffset(control.getValue(), true);
344 days = XT.date.daysBetween(date, today);
345 days = days < 0 ? "" + days : "+" + days;
346 values[label] = days;
347 } else if (options.value) {
348 values[label] = value instanceof XM.Model ? value.id : value;
350 values[label] = control.getValueToString ?
351 control.getValueToString() : value;
358 // implementation is up to subkinds or monkeypatches
359 parameterChanged: function (inSender, inEvent) {
362 Receives the event from the item form with the user-
363 entered values and combines these with the other item values
365 If the item name already exists for this type, it performs an edit
366 instead of a new insert.
368 saveItem: function (inSender, inEvent) {
369 var Klass = XT.getObjectByName("XM.Filter"),
370 model = inEvent.model,
371 options = {}, attrs = {},
376 if (inSender.itemType === "filter") {
377 params = JSON.stringify(this.getSelectedValues({
382 } else if (inSender.itemType === "layout") {
383 params = JSON.stringify(this.$.layoutForm.getColumnValues());
387 // there is not already a model
388 model = new Klass(null, {isNew: true});
390 // set the values from the save event and save
391 model.set("name", inEvent.itemName);
392 model.set("shared", inEvent.isShared);
393 model.set("params", params);
394 model.set("kind", kind);
395 model.set("type", inSender.itemType);
397 options.success = function (model, resp, options) {
398 // dear item form, we're all done here!
399 inEvent.callback(model);
401 if (model.isDirty()) {
402 model.save(null, options);
404 options.success(model);
408 Gets the model from the change
409 event and populates the fields with parameter
410 values from the model.
412 loadItem: function (inSender, inEvent) {
413 var model = inEvent.model,
414 params = model ? model.get("params") : null,
415 type = model ? model.get("type") : "filter";
417 if (type === "filter") {
418 this.setCurrentFilter(model);
419 // clear out the existing filters before populating this one
420 this.clearParameters();
421 // if there are no parameters, take the defaults
422 params = params ? params : this.getDefaultFilter();
423 // populate the parameters with filter or defaults
424 this.populateParameters(params);
425 } else if (type === "layout") {
426 this.setCurrentLayout(model);
427 this.populateLayout(params);
429 this.saveToUserPref();
432 Clear all of the currently loaded parameters and bubble
433 parameter change events.
435 clearParameters: function () {
436 _.each(this.$, function (item) {
437 if (item instanceof XV.ParameterItem && item.showing) {
438 item.$.input.clear({silent: true});
441 if (this._init) { this.doParameterChange(); }
444 Loops through the values in the params object
445 and sets the value on attribute fields in the
446 layout tree. Bubbles up a change event after
447 all of the fields are set.
449 @param {Object|String} params
451 populateLayout: function (params) {
452 params = _.isObject(params) ? params : JSON.parse(params);
453 this.$.layoutForm.loadColumns(params);
456 Loops through the values in the params object
457 and sets the value on the parameter fields and
458 bubbles up the change events.
460 @param {String} params
462 populateParameters: function (params) {
463 params = _.isObject(params) ? params : JSON.parse(params);
464 _.each(params, function (value, key) {
465 var param = this.$[key];
467 param.setValue(value, {silent: true});
471 if (this._init) { this.doParameterChange(); }
474 Reads the last filter value from the user preferences
475 and populates the filter picker with this value.
477 populateFromUserPref: function () {
484 // we have a cache of preferences, so find the last
485 // selected preferences for this kind
486 lastPref = XT.DataSource.getUserPreference(kind);
488 // if there is a last preference for this kind,
489 // and it isn't null, set the pickers.
490 if (lastPref && lastPref !== "null") {
491 lastPref = JSON.parse(lastPref);
492 lastFilter = lastPref.filter || {};
493 lastLayout = lastPref.layout || {};
494 if (this.getShowSaveFilter()) {
495 this.$.filterForm.$.itemPicker.setValue(lastFilter.uuid);
497 if (this.getShowLayout()) {
498 this.$.layoutForm.$.itemPicker.setValue(lastLayout.uuid);
503 Saves the last selected filter and layout to the user
506 saveToUserPref: function () {
511 filterModel = this.getCurrentFilter(),
512 layoutModel = this.getCurrentLayout();
514 // setup the parms object with the filter and layout
515 params.filter = filterModel || {};
516 params.layout = layoutModel || {};
517 payload = JSON.stringify(params);
519 // save the last selected filter and layout to the user preference
520 operation = XT.DataSource.getUserPreference(kind) ? "replace" : "add";
521 XT.DataSource.saveUserPreference(kind, payload, operation);
522 // save this item to the preference cache
523 XT.session.preferences.set(kind, payload);
526 Accepts an array of items to push into the parameter items. Matches item name
527 to component under the assumption that there will be a component by the
528 name of the incoming name (which itself is the name of the model attribute).
529 Fails silently if it cannot find the name.
532 @param {Array|String} [item.name] A string *or an array of strings* with the name or attr of
533 the attribute to be updated. In the case of an array, this function will set
534 any component that matches any of the names, and ignore the rest.
535 @param {Object|String|Number} [item.value] The payload of the setValue to the ParameterItem.
536 @param {Boolean} [item.showing] Set to false to completely hide and disable the parameter.
538 setParameterItemValues: function (items) {
540 setValueOnMatch = function (name, item) {
541 var control = that.$[name] || _.find(that.$, function (ctl) {
542 // look up controls by name or by the model attribute they map to
543 return ctl.attr === name;
546 if (item.showing !== false) {
547 control.setValue(item.value, {silent: true});
549 control.setShowing(item.showing !== false);
553 _.each(items, function (item) {
554 if (typeof item.name === 'string') {
555 // string case. set the component by this name
556 setValueOnMatch(item.name, item);
557 } else if (typeof item.name === 'object') {
558 // array case. loop through item.name and set any matches
559 _.each(item.name, function (subname) {
560 setValueOnMatch(subname, item);
565 }, XV.ExtensionsMixin));
568 Generalized form for supporting saved filters, layouts, and sorts.
569 This component expects a picker for selecting
570 saved items, a save drawer for saving the current item,
571 and a manage drawer for sharing and deleting items.
573 TODO: Move common components here from Filter and Layout forms
575 enyo.kind(/** @lends XV.UserItemForm# */{
576 name: "XV.UserItemForm",
577 classes: "xv-filter-form",
583 onValueChange: "valueChanged",
584 onListChange: "listChanged"
589 Opens the save drawer and switches the drawer icons.
591 activateSave: function (inSender, inEvent) {
592 this.$.saveDrawer.setOpen(!this.$.saveDrawer.open);
593 this.$.saveTopDrawer.changeIcon(this.$.saveDrawer.open);
596 Opens the manage filter drawer and switches the
599 activateManage: function (inSender, inEvent) {
600 this.$.filterList.reset();
601 this.$.manageDrawer.setOpen(!this.$.manageDrawer.open);
602 this.$.manageTopDrawer.changeIcon(this.$.manageDrawer.open);
605 This is called by the save/apply button in the
606 save drawer. It checks for an existing filter and
607 shows the warning popup or continues to the save.
609 checkExisting: function (inSender, inEvent) {
610 var name = this.$.itemName.getValue() ?
611 this.$.itemName.getValue().trim() : "",
612 exists = this.itemExists(name);
614 this.$.existingPopup.show();
616 this.saveItem(inSender, inEvent);
620 There was a change to the list and a model
621 was added or removed. Refresh list and picker.
623 listChanged: function (inSender, inEvent) {
624 inEvent = inEvent || {};
625 this.$.itemPicker.collectionChanged();
626 // a model was deleted
627 if (inEvent.delete && inEvent.model === this.$.itemPicker.getValue()) {
628 this.$.itemPicker.setValue(null);
630 this.$.filterList.fetched();
633 Sets the default items for the picker and the
634 list of items that can be managed.
636 create: function () {
637 this.inherited(arguments);
638 this.$.apply.setDisabled(!this.validate());
641 var filter = function (models, options) {
642 var filtered = _.filter(models, function (model) {
643 var kind = this.parent.parent.kind === model.get("kind"),
644 permission = model.get("shared") ||
645 model.get("createdBy") === XM.currentUser.get("username"),
646 type = this.parent.itemType === model.get("type") ||
647 (this.parent.itemType === "filter" && !model.get("type"));
648 if (kind && permission && type) {
654 this.$.itemPicker.filter = filter;
655 this.$.itemPicker.collectionChanged();
657 // filters the manage list
658 var query = this.$.filterList.getQuery() || {};
660 query.parameters = [];
661 query.parameters = [{
662 attribute: "createdBy",
664 value: XT.session.details.username
669 value: this.parent.kind
674 value: this.itemType,
675 includeNull: this.itemType === "filter" // handles filters added before type was created
677 this.$.filterList.setQuery(query);
680 Looks at the list of items for the current user and determines
681 an item exists by name.
686 itemExists: function (name) {
687 var exists = _.find(this.$.filterList.getValue().models,
689 var value = model.get("name");
690 return value.toLowerCase() === name.toLowerCase();
694 hidePopup: function (inSender, inEvent) {
695 this.$.existingPopup.hide();
698 This is called by the save/apply button in the
699 save drawer. It bubbles up the event to the parameter
700 widget with a callback so it knows when the save was
701 successful. It then closes the drawer and refreshes
704 saveItem: function (inSender, inEvent) {
705 var name = this.$.itemName.getValue() ?
706 this.$.itemName.getValue().trim() : "",
707 shared = this.$.isShared.getValue(),
708 exists = this.itemExists(name),
711 inEvent = {model: exists, itemName: name, isShared: shared,
712 callback: function (model) {
714 that.$.filterList.getValue().add(model);
716 that.activateSave(); // close the save drawer
717 that.$.existingPopup.hide(); // hide the popup if it was showing
718 that.$.itemPicker.setValue(model);
719 that.$.filterList.doListChange();
721 this.doItemSave(inEvent);
724 Checks that all of the form fields have
727 validate: function () {
728 if (this.$.itemName.getValue()) {
734 When an item is selected from the picker, the
735 form fields are populated and a changed
736 event is bubbled up to the parameter widget.
738 valueChanged: function (inSender, inEvent) {
739 this.$.apply.setDisabled(!this.validate());
740 if (inSender.kind === "XV.FilterPicker") {
741 // get values from inEvent for form load
742 var value = inEvent.originator.value,
743 name = value ? value.get("name") : null,
744 shared = value ? value.get("shared") : false;
745 this.$.itemName.setValue(name);
746 this.$.isShared.setValue(shared);
747 inEvent = {model: value};
748 this.doItemChange(inEvent);
755 User Item Form for selecting saved filters, a save drawer for saving
756 the current filter, and a manage drawer for sharing and deleting filters.
759 /** @lends XV.FilterForm# */{
760 name: "XV.FilterForm",
761 kind: "XV.UserItemForm",
764 {kind: "onyx.GroupboxHeader", content: "_filters".loc()},
765 {kind: "XV.FilterPicker", name: "itemPicker", label: "_filter".loc()},
766 {kind: "XV.TopDrawer", name: "saveTopDrawer", ontap: "activateSave", content: "_saveFilter".loc()},
767 {kind: "onyx.Drawer", name: "saveDrawer", open: false, animated: true, components: [
768 {kind: "onyx.GroupboxHeader", content: "_saveFilter".loc()},
769 {kind: "XV.InputWidget", name: "itemName", label: "_filterName".loc()},
770 {kind: "XV.CheckboxWidget", name: "isShared", attr: "isShared", label: "_isShared".loc()},
771 {kind: "FittableColumns", classes: "xv-buttons", components: [
772 {kind: "onyx.Button", name: "apply", classes: "icon-ok", disabled: true, ontap: "checkExisting"},
773 {kind: "onyx.Button", name: "cancel", classes: "icon-remove", ontap: "activateSave"}
776 {kind: "XV.TopDrawer", name: "manageTopDrawer", ontap: "activateManage", content: "_manageFilters".loc()},
777 {kind: "onyx.Drawer", name: "manageDrawer", open: false, animated: true, components: [
778 {kind: "onyx.GroupboxHeader", content: "_manageFilters".loc()},
779 {kind: "XV.FilterList", allowFilter: false},
780 {kind: "FittableColumns", classes: "xv-buttons", components: [
781 {kind: "onyx.Button", name: "done", classes: "icon-ok", ontap: "activateManage"}
784 {kind: "onyx.Popup", name: "existingPopup", centered: true,
785 modal: true, floating: true, scrim: true, components: [
786 {content: "_filterExists".loc()},
787 {content: "_editFilter?".loc()},
788 {classes: "xv-buttons", components: [
789 {kind: "onyx.Button", ontap: "saveItem", classes: "selected icon-ok"},
790 {kind: "onyx.Button", ontap: "hidePopup", classes: "icon-remove"}
797 User Item Form for selecting saved layouts, a save drawer for saving
798 the current layout, and a manage drawer for sharing and deleting layouts.
800 enyo.kind(/** @lends XV.LayoutForm# */{
801 name: "XV.LayoutForm",
802 kind: "XV.UserItemForm",
810 {kind: "onyx.GroupboxHeader", content: "_layout".loc()},
811 {kind: "XV.FilterPicker", name: "itemPicker", label: "_layout".loc()},
812 {kind: "XV.TopDrawer", name: "layoutTopDrawer", ontap: "activateLayout", content: "_changeLayout".loc()},
813 {kind: "onyx.Drawer", name: "columnsDrawer", open: false, animated: true, components: [
814 {kind: "XV.LayoutTree", name: "layoutTree"}
816 {kind: "XV.TopDrawer", name: "saveTopDrawer", ontap: "activateSave", content: "_saveLayout".loc()},
817 {kind: "onyx.Drawer", name: "saveDrawer", open: false, animated: true, components: [
818 {kind: "onyx.GroupboxHeader", content: "_saveLayout".loc()},
819 {kind: "XV.InputWidget", name: "itemName", label: "_layoutName".loc()},
820 {kind: "XV.CheckboxWidget", name: "isShared", attr: "isShared", label: "_isShared".loc()},
821 {kind: "FittableColumns", classes: "button-row", components: [
822 {kind: "onyx.Button", name: "apply", disabled: true, content: "_apply".loc(), ontap: "checkExisting"},
823 {kind: "onyx.Button", content: "_cancel".loc(), ontap: "activateSave"}
826 {kind: "XV.TopDrawer", name: "manageTopDrawer", ontap: "activateManage", content: "_manageLayouts".loc()},
827 {kind: "onyx.Drawer", name: "manageDrawer", open: false, animated: true, components: [
828 {kind: "onyx.GroupboxHeader", content: "_manageLayouts".loc()},
829 {kind: "XV.FilterList", allowFilter: false},
830 {kind: "FittableColumns", classes: "button-row", components: [
831 {kind: "onyx.Button", content: "_done".loc(), ontap: "activateManage"}
834 {kind: "onyx.Popup", name: "existingPopup", centered: true,
835 modal: true, floating: true, scrim: true, components: [
836 {content: "_layoutExists".loc()},
837 {content: "_editLayout?".loc()},
839 {kind: "onyx.Button", content: "_edit".loc(), ontap: "saveItem",
840 classes: "onyx-blue xv-popup-button"},
841 {kind: "onyx.Button", content: "_cancel".loc(), ontap: "hidePopup",
842 classes: "xv-popup-button"}
846 Opens the change layout drawer and switches the drawer icons.
848 activateLayout: function (inSender, inEvent) {
849 this.$.columnsDrawer.setOpen(!this.$.columnsDrawer.open);
850 this.$.layoutTopDrawer.changeIcon(this.$.columnsDrawer.open);
853 Builds a tree of nodes based on the current list layout. For each current
854 list attribute, a picker is shown with the set of available attributes. If
855 a column is already shown, it is selected, otherwise it will show as "none."
857 @param {Object} currentLayout
859 addColumns: function (currentLayout) {
861 matchSelections = function (sel) { return sel.attr === attributes[i]; },
866 // set the layout tree with the list of possible display attributes
867 this.$.layoutTree.setListAttrs(currentLayout.getDisplayAttributes());
868 // clear out the tree before building it
869 this.$.layoutTree.$.tree.destroyClientControls();
870 this.$.layoutTree.createTree(currentLayout);
871 this.$.columnsDrawer.render();
873 getColumnValues: function () {
875 _.each(this.$.layoutTree.$, function (leaf) {
876 if (leaf.order !== undefined && leaf.order !== null) {
877 params[leaf.order] = leaf.getAttr();
882 loadColumns: function (params) {
883 _.each(this.$.layoutTree.$, function (leaf) {
884 if (leaf.order !== undefined && leaf.order !== null &&
885 leaf.getAttr() !== params[leaf.order]) {
886 leaf.setAttr(params[leaf.order]);
889 value: params[leaf.order]
891 this.doColumnsChange(inEvent);
896 When an attribute is selected from the picker,
897 a change event is bubbled up to the parameter widget.
899 valueChanged: function (inSender, inEvent) {
900 this.inherited(arguments);
901 if (inEvent.originator.kind === "XV.AttributePicker") {
903 order: inEvent.originator.owner.order,
906 this.doColumnsChange(inEvent);
912 Simple FittableColumns that contains the open/close icon
913 and some text. When the ontap event is fired, this control
914 is responsible for switching icons and opening a drawer.
917 /** @lends XV.TopDrawer */{
918 name: "XV.TopDrawer",
919 kind: "FittableColumns",
920 classes: "onyx-groupbox-header",
925 {tag: "i", classes: "icon-plus-sign-alt", name: "drawerIcon"},
929 Switch icons depending on open state of a drawer
931 @param {Boolean} drawerOpen
933 changeIcon: function (drawerOpen) {
935 this.$.drawerIcon.setClasses("icon-minus-sign-alt");
937 this.$.drawerIcon.setClasses("icon-plus-sign-alt");
940 contentChanged: function () {
941 this.$.label.setContent(this.getContent());
943 create: function () {
944 this.inherited(arguments);
945 this.contentChanged();