diff --git a/application/nicewebpage.class.inc.php b/application/nicewebpage.class.inc.php index a9f3b4ed9..3e6b55a66 100644 --- a/application/nicewebpage.class.inc.php +++ b/application/nicewebpage.class.inc.php @@ -63,6 +63,7 @@ class NiceWebPage extends WebPage $this->add_dict_entry('UI:Search:Criteria:Operator:String:EndsWith'); $this->add_dict_entry('UI:Button:Apply'); $this->add_dict_entry('UI:Button:Cancel'); + $this->add_dict_entry('UI:Button:Close'); $this->add_dict_entry('UI:Button:More'); $this->add_dict_entry('UI:Button:Less'); $this->add_ready_script( diff --git a/css/light-grey.css b/css/light-grey.css index 69c432ddf..8407ed636 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -795,12 +795,20 @@ div.HRDrawer { display: inline-block; margin-right: 5px; margin-bottom: 5px; + /* Non editable criteria */ + /* Draft criteria (modifications not applied) */ /* Top left corner icons */ /* Special criterion processing */ } .search_form_handler .sf_criterion_area .search_form_criteria.locked { background-color: #f1f1f1; } +.search_form_handler .sf_criterion_area .search_form_criteria.draft { + border-style: dashed; +} +.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_title { + font-style: italic; +} .search_form_handler .sf_criterion_area .search_form_criteria .sfc_close, .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle { position: absolute; top: 7px; @@ -811,7 +819,7 @@ div.HRDrawer { } .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle { display: inline-block; - right: 20px; + right: 23px; transition: all 0.4s ease-in-out; } .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle.opened { @@ -905,6 +913,9 @@ div.HRDrawer { .search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_title { cursor: initial; } +.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_form_group { + display: none; +} .search_form_handler .sf_criterion_area .sf_more_criterion .sf_mc_list { position: absolute; max-height: 420px; diff --git a/css/light-grey.scss b/css/light-grey.scss index 95572abb5..e8eeaa1fd 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -881,9 +881,18 @@ div.HRDrawer { margin-right: 5px; margin-bottom: 5px; + /* Non editable criteria */ &.locked{ background-color: $gray-extra-light; } + /* Draft criteria (modifications not applied) */ + &.draft{ + border-style: dashed; + + .sfc_title{ + font-style: italic; + } + } /* Top left corner icons */ .sfc_close, @@ -897,7 +906,7 @@ div.HRDrawer { } .sfc_toggle{ display: inline-block; - right: 20px; + right: 23px; transition: all 0.4s ease-in-out; &.opened{ @@ -1022,6 +1031,9 @@ div.HRDrawer { .sfc_title{ cursor: initial; } + .sfc_form_group{ + display: none; + } } } diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 50378c8ce..c0f9ed19a 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -367,6 +367,7 @@ Dict::Add('EN US', 'English', 'English', array( 'UI:Button:Ok' => 'Ok', 'UI:Button:Save' => 'Save', 'UI:Button:Cancel' => 'Cancel', + 'UI:Button:Close' => 'Close', 'UI:Button:Apply' => 'Apply', 'UI:Button:Back' => ' << Back ', 'UI:Button:Restart' => ' |<< Restart ', diff --git a/js/search/search_form_criteria.js b/js/search/search_form_criteria.js index b366734f8..cd16e008f 100644 --- a/js/search/search_form_criteria.js +++ b/js/search/search_form_criteria.js @@ -130,12 +130,12 @@ $(function() var me = this; // Get criteria data - this.element.bind('itop.search.criteria.get_data', function(oEvent, oData){ + this.element.on('itop.search.criteria.get_data', function(oEvent, oData){ return me._onGetData(oData); }); // Get/SetCurrentValues callbacks handler - this.element.bind('itop.search.criteria.get_current_values itop.search.criteria.set_current_values', function(oEvent, oData){ + this.element.on('itop.search.criteria.get_current_values itop.search.criteria.set_current_values', function(oEvent, oData){ oEvent.stopPropagation(); var callback = me.options[oEvent.type+'_callback']; @@ -154,10 +154,47 @@ $(function() return false; } }); + + // Close criteria + this.element.on('itop.search.criteria.close', function(){ + return me._close(); + }); }, + // - Cinematic + // - Open / Close criteria + _open: function() + { + this._resetOperators(); + this.element.find('.sfc_form_group, .sfc_toggle').addClass('opened'); + }, + _close: function() + { + this.element.find('.sfc_form_group, .sfc_toggle').removeClass('opened'); + this._unmarkAsDraft(); + }, + _closeAll: function() + { + this.element.closest('.search_form_handler').find('.search_form_criteria').each(function(){ + $(this).triggerHandler('itop.search.criteria.close'); + }); + }, + _remove: function() + { + this.element.remove(); + this.handler.triggerHandler('itop.search.criteria.removed'); + }, + // - Mark / Unmark criteria as draft (new value not applied) + _markAsDraft: function() + { + this.element.addClass('draft'); + }, + _unmarkAsDraft: function() + { + this.element.removeClass('draft'); + }, + // - Apply / Cancel new value _apply: function() { - this._trace('TODO: Apply button (call selected operator callback)'); // Find active operator var oActiveOpElem = this.element.find('.sfc_op_radio:checked').closest('.sfc_fg_operator'); if(oActiveOpElem.length === 0) @@ -179,14 +216,14 @@ $(function() this.options.operator = oActiveOpElem.find('.sfc_op_radio').val(); this.options.values = aValues; this._setTitle(); + this._unmarkAsDraft(); // Trigger event to handler this.handler.triggerHandler('itop.search.criteria.value_changed'); }, - _remove: function() + _cancel: function() { - this.element.remove(); - this.handler.triggerHandler('itop.search.criteria.removed'); + this._close(); }, @@ -198,7 +235,7 @@ $(function() }, _onButtonCancel: function() { - this._trace('TODO: Cancel button'); + this._cancel(); }, _onButtonMore: function() { @@ -246,11 +283,11 @@ $(function() // First memorize if current criteria is close var bOpen = !me.element.find('.sfc_toggle').hasClass('opened'); // Then close every criterion - me.handler.find('.sfc_form_group, .sfc_toggle').removeClass('opened'); + me._closeAll(); // Finally open current criteria if necessary if(bOpen === true) { - me.element.find('.sfc_form_group, .sfc_toggle').toggleClass('opened'); + me._open(); } }); @@ -332,6 +369,36 @@ $(function() me[sCallback](); }); }, + // - Reset all operators but active one + _resetOperators: function() + { + var me = this; + + // Reset all operators + this.element.find('.sfc_fg_operator').each(function(){ + var sCallback = '_reset' + me._toCamelCase($(this).attr('data-operator-code')) + 'Operator'; + if(me[sCallback] === undefined) + { + sCallback = '_resetOperator'; + } + me[sCallback]($(this)); + }); + + // Set value on current operator + var sCurrentOpCode = this.operators[this.options.operator].code; + this.element.find('.sfc_fg_operator[data-operator-code="' + sCurrentOpCode + '"]').each(function(){ + // Check radio (we don't use .trigger('click'), otherwise the criteria will be seen as draft. + $(this).find('.sfc_op_radio').prop('checked', true); + + // Reset values + var sCallback = '_set' + me._toCamelCase(sCurrentOpCode) + 'OperatorValues'; + if(me[sCallback] === undefined) + { + sCallback = '_setOperatorValues'; + } + me[sCallback]($(this), me.options.values); + }); + }, // - Set the title element _setTitle: function(sTitle) { @@ -342,15 +409,18 @@ $(function() } this.element.find('.sfc_title').text(sTitle); }, + + // Operators helpers // - Return a HTML template for operators _getOperatorTemplate: function() { return '
'; }, - - // Operators helpers + // Prepare operator's DOM element + // - Base preparation, always called _prepareOperator: function(oOpElem, sOpIdx, oOp) { + var me = this; var sInputId = oOp.code + '_' + oOpElem.attr('id'); // Set radio @@ -366,11 +436,18 @@ $(function() .attr('data-operator-code', oOp.code); // Bind events - // - Check radio button on click + // - Check radio button on click and mark criteria as draft oOpElem.on('click', function(){ - oOpElem.find('.sfc_op_radio').prop('checked', true); + var bIsChecked = oOpElem.find('.sfc_op_radio').prop('checked'); + + if(bIsChecked === false) + { + oOpElem.find('.sfc_op_radio').prop('checked', true); + me._markAsDraft(); + } }); }, + // - Fallback for operator that has no dedicated callback _prepareDefaultOperator: function(oOpElem, sOpIdx, oOp) { var me = this; @@ -392,6 +469,8 @@ $(function() oOpElem.find('.sfc_op_radio').prop('checked', true) } + me._markAsDraft(); + // Apply if enter key if(oEvent.key === 'Enter') { @@ -409,6 +488,13 @@ $(function() { // Do nothing as only the label is necessary }, + // Reset operator's state + // - Fallback for operator that has no dedicated callback + _resetOperator: function(oOpElem) + { + oOpElem.find('.sfc_op_content input').val(''); + }, + // Get operator's values // - Fallback for operators without a specific callback _getOperatorValues: function(oOpElem) { @@ -421,6 +507,21 @@ $(function() return aValues; }, + // Set operator's values + // - Fallback for operators without a specific callback + _setOperatorValues: function(oOpElem, aValues) + { + if(aValues.length === 0) + { + return false; + } + + oOpElem.find('.sfc_op_content input').each(function(){ + $(this).val(aValues[0].value); + }); + + return true; + }, // Values helpers diff --git a/js/search/search_form_handler.js b/js/search/search_form_handler.js index 47b7edcce..7e6998737 100644 --- a/js/search/search_form_handler.js +++ b/js/search/search_form_handler.js @@ -11,6 +11,7 @@ $(function() { 'criterion_outer_selector': null, 'result_list_outer_selector': null, + 'data_config_list_selector': null, 'submit_button_selector': null, 'hide_initial_criterion': false, // TODO: What is that? 'endpoint': null, @@ -133,10 +134,10 @@ $(function() }); // Criteria events - this.element.bind('itop.search.criteria.value_changed', function(oEvent, oData){ + this.element.on('itop.search.criteria.value_changed', function(oEvent, oData){ me._onCriteriaValueChanged(oData); }); - this.element.bind('itop.search.criteria.removed', function(oEvent, oData){ + this.element.on('itop.search.criteria.removed', function(oEvent, oData){ me._onCriteriaRemoved(oData); }); }, @@ -268,6 +269,7 @@ $(function() } else { + // TODO: Change this so it appears after the search drawer. oResultAreaElem = $('').appendTo(this.element); } oResultAreaElem.addClass('sf_results_area'); @@ -404,13 +406,23 @@ $(function() _submit: function() { var me = this; + + // Data + // - Regular params var oData = { 'params': JSON.stringify({ 'base_oql': this.options.search.base_oql, 'criterion': this.options.search.criterion, }), - 'list_params': this.elements.results_area.data('sExtraParams'), }; + // - List params (pass through for the server), merge data_config with list_params if present. + var oListParams = {}; + if(this.options.data_config_list_selector !== null) + { + // TODO: What ? + } + $.extend(oListParams, this.options.list_params); + oData.list_params = JSON.stringify(oListParams); // Show loader this._showLoader();