diff --git a/css/css-variables.scss b/css/css-variables.scss index e4e13bdcd..962c33cb7 100644 --- a/css/css-variables.scss +++ b/css/css-variables.scss @@ -24,5 +24,14 @@ $complement-color: #1c94c4; $complement-light: #d6e8ef; $frame-background-color: $gray-extra-light; $text-color: #000; +$box-radius: 0px; +$box-shadow-regular: 0 1px 1px rgba(0, 0, 0, 0.15); +// - Boxes +$box-blue-color: #2D2D2D; +$box-blue-bg-color: #d6e8ef; +$box-blue-border-color: #1c94c4; +$box-blue-border: 1px solid $box-blue-border-color; +$box-blue-radius: 1px; + // Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0 $version: "v2.4.0"; \ No newline at end of file diff --git a/css/light-grey.css b/css/light-grey.css index 1182e55f9..1349ad534 100644 --- a/css/light-grey.css +++ b/css/light-grey.css @@ -676,31 +676,34 @@ input.dp-applied { } /* For search forms */ /* TODO: Remove when cleaning up old search */ -.SearchDrawer { - border-top: 5px solid #1c94c4; - border-left: 5px solid #1c94c4; - border-right: 5px solid #1c94c4; - border-bottom: 0; - background: #d6e8ef; - color: #000; - padding: 10px; - margin: 0; - font-size: 12px; -} -.SearchDrawer label { - background: #d6e8ef; - color: #000; - text-align: right; -} -.SearchDrawer h1 { - color: #000; -} -.SearchDrawer .SearchAttribute > .field_input_zone { - display: inline-block; -} -.SearchDrawer .SearchAttribute > .field_input_zone > .field_select_wrapper { - display: inline-block; -} +/*.SearchDrawer { + //background: $complement-color url(../images/search-top-left-corner.png?v=#{$version}) top left no-repeat; + border-top: 5px solid $complement-color; + border-left: 5px solid $complement-color; + border-right: 5px solid $complement-color; + border-bottom: 0; + background: $complement-light; + color: #000; + padding: 10px; + margin: 0; + font-size: 12px; + } + .SearchDrawer label { + background: $complement-light; + color: #000; + text-align: right; + } + .SearchDrawer h1 { + color: #000; + } + .SearchDrawer .SearchAttribute{ + > .field_input_zone{ + display: inline-block; + > .field_select_wrapper{ + display: inline-block; + } + } + }*/ .DrawerClosed { display: none; } @@ -757,6 +760,9 @@ div.HRDrawer { /* Search forms v2 */ /* TODO: Remove comment before final commit */ .search_form_handler { + position: relative; + z-index: 10; + font-size: 12px; /* Sizing reset */ /* Hyperlink reset */ } @@ -777,20 +783,34 @@ div.HRDrawer { } .search_form_handler .sf_criterion_area .sf_more_criterion, .search_form_handler .sf_criterion_area .search_form_criteria { position: relative; - padding: 8px 10px; - background-color: #ea7d1e; - color: #fff; + padding: 7px 8px; + background-color: #d6e8ef; + color: #2d2d2d; + border: 1px solid #1c94c4; + border-radius: 1px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); } .search_form_handler .sf_criterion_area .search_form_criteria { display: inline-block; - margin-right: 3px; + margin-right: 5px; + padding-right: 35px; + /* 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 .sfc_close, .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle { + position: absolute; + top: 7px; + color: #1c94c4; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_close { + right: 7px; +} .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle { display: inline-block; + right: 20px; transition: all 0.2s ease-in-out; } .search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle.opened { @@ -800,20 +820,76 @@ div.HRDrawer { cursor: pointer; } .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group { + /* Form group (operators) is displayed only when the criteria is toggled to opened state */ display: none; } .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened { display: block; + margin-top: 5px; + /* Show only first operator in simple mode */ +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_apply, .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_cancel { + margin-top: 8px; + padding: 3px 6px; + font-size: 11px; + /* Not bold, so it looks like 10px/bold of more/less buttons */ +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_apply { + margin-right: 5px; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_more, .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_less { + position: absolute; + bottom: 3px; + right: 0px; + cursor: pointer; + color: #1c94c4; + font-size: 10px; + font-weight: bold; + border: none; + background-color: transparent; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_more > span, .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_less > span { + margin-left: 3px; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_operator:not(:first-of-type), .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_operator:first-of-type .sfc_op_radio { + display: none; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_less { + display: none; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened .sfc_fg_more { + display: inline-block; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced { + /* Show all operators in simple mode */ +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_operator { + margin-bottom: 3px; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_operator:last-of-type { + margin-bottom: 0px; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_operator:not(:first-of-type), .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_operator:first-of-type .sfc_op_radio { + display: inherit; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_less { + display: inline-block; +} +.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.opened.advanced .sfc_fg_more { + display: none; } .search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_title { cursor: initial; } .search_form_handler .sf_criterion_area .sf_more_criterion .sf_mc_list { position: absolute; + max-height: 420px; margin: 0px; top: 100%; left: 0px; - background-color: #ea7d1e; + overflow-y: auto; + background-color: #d6e8ef; + border: 1px solid #1c94c4; } .search_form_handler .sf_criterion_area .sf_more_criterion .sf_mc_list .sf_mc_field { cursor: pointer; diff --git a/css/light-grey.scss b/css/light-grey.scss index 80d8efc8c..fef2bdeaa 100644 --- a/css/light-grey.scss +++ b/css/light-grey.scss @@ -757,7 +757,7 @@ input.dp-applied { /* For search forms */ /* TODO: Remove when cleaning up old search */ -.SearchDrawer { +/*.SearchDrawer { //background: $complement-color url(../images/search-top-left-corner.png?v=#{$version}) top left no-repeat; border-top: 5px solid $complement-color; border-left: 5px solid $complement-color; @@ -785,7 +785,7 @@ input.dp-applied { display: inline-block; } } -} +}*/ .DrawerClosed { display: none; } @@ -843,6 +843,10 @@ div.HRDrawer { /* Search forms v2 */ /* TODO: Remove comment before final commit */ .search_form_handler{ + position: relative; + z-index: 10; + font-size: 12px; + /* Sizing reset */ *{ box-sizing: border-box; @@ -862,39 +866,116 @@ div.HRDrawer { .sf_more_criterion, .search_form_criteria{ position: relative; - padding: 8px 10px; - background-color: $combodo-orange; - color: $white; + padding: 7px 8px; + background-color: $box-blue-bg-color; + color: $box-blue-color; + border: $box-blue-border; + border-radius: $box-blue-radius; + box-shadow: $box-shadow-regular; } /* Criteria tags */ .search_form_criteria{ display: inline-block; - margin-right: 3px; + margin-right: 5px; + padding-right: 35px; &.locked{ background-color: $gray-extra-light; } + /* Top left corner icons */ + .sfc_close, + .sfc_toggle{ + position: absolute; + top: 7px; + color: $box-blue-border-color; + } .sfc_close{ - + right: 7px; } .sfc_toggle{ display: inline-block; + right: 20px; transition: all 0.2s ease-in-out; &.opened{ transform: rotateZ(180deg); } } + .sfc_title{ cursor: pointer; } .sfc_form_group{ + /* Form group (operators) is displayed only when the criteria is toggled to opened state */ display: none; &.opened{ display: block; + margin-top: 5px; + + .sfc_fg_apply, + .sfc_fg_cancel{ + margin-top: 8px; + padding: 3px 6px; + font-size: 11px; /* Not bold, so it looks like 10px/bold of more/less buttons */ + } + .sfc_fg_apply{ + margin-right: 5px; + } + + .sfc_fg_more, + .sfc_fg_less{ + position: absolute; + bottom: 3px; + right: 0px; + cursor: pointer; + color: $box-blue-border-color; + font-size: 10px; + font-weight: bold; + border: none; + background-color: transparent; + + > span{ + margin-left: 3px; + } + } + + /* Show only first operator in simple mode */ + .sfc_fg_operator:not(:first-of-type), + .sfc_fg_operator:first-of-type .sfc_op_radio{ + display: none; + } + .sfc_fg_less{ + display: none; + } + .sfc_fg_more{ + display: inline-block; + } + + &.advanced{ + + .sfc_fg_operator{ + margin-bottom: 3px; + + &:last-of-type{ + margin-bottom: 0px; + } + } + + /* Show all operators in simple mode */ + .sfc_fg_operator:not(:first-of-type), + .sfc_fg_operator:first-of-type .sfc_op_radio{ + display: inherit; + } + .sfc_fg_less{ + display: inline-block; + } + .sfc_fg_more{ + display: none; + } + } } } @@ -910,10 +991,13 @@ div.HRDrawer { .sf_more_criterion{ .sf_mc_list{ position: absolute; + max-height: 420px; margin: 0px; top: 100%; left: 0px; - background-color: $combodo-orange; + overflow-y: auto; + background-color: $box-blue-bg-color; + border: $box-blue-border; .sf_mc_field{ cursor: pointer; diff --git a/js/search/search_form_criteria.js b/js/search/search_form_criteria.js index 779797614..5b4e0cdd6 100644 --- a/js/search/search_form_criteria.js +++ b/js/search/search_form_criteria.js @@ -10,18 +10,18 @@ $(function() options: { // Default values for the criteria - ref: '', - operator: '=', - values: [], - oql: '', - is_removable: true, + 'ref': '', + 'operator': '=', + 'values': [], + 'oql': '', + 'is_removable': true, - field: { - label: '', + 'field': { + 'label': '', }, - // Available operators (merged with derived widgets, ordered and then copied to this.operators) - available_operators: { + // Available operators. They can be extended or restricted by derivated widgets (see this._initOperators() for more informations) + 'available_operators': { '=': { 'label': Dict.S('UI:Search:Criteria:Operator:Default:Equals'), 'code': 'equals', @@ -39,7 +39,7 @@ $(function() }, }, - is_modified: false, // TODO: change this on value change and remove oql property value + 'is_modified': false, // TODO: change this on value change and remove oql property value }, // Operators @@ -55,7 +55,8 @@ $(function() this.element.addClass('search_form_criteria'); - this._orderOperators(); + // Init operators + this._initOperators(); // Link search form handler this.handler = this.element.closest('.search_form_handler'); @@ -90,11 +91,37 @@ $(function() // Protected methods - // - Order available operators - _orderOperators: function() + // - Init operators by cleaning up available operators and ordering them. + // Note: A null operator or an operator with a rank "false" will be removed. + _initOperators: function() { - console.log(this.options.available_operators); + // Reset oprators + this.operators = {}; + // Temp array to sort operators + var aSortable = []; + for(var sOpIdx in this.options.available_operators) + { + var oOp = this.options.available_operators[sOpIdx]; + + // Some operator can be disabled by the derivated widget, so we check it. + if(oOp !== null && oOp.rank !== false) + { + aSortable.push([sOpIdx, oOp.rank]); + } + } + + // Sort the array + aSortable.sort(function(a, b){ + return a[1] - b[1]; + }) + + // Populate this.operators + for(var iIdx in aSortable) + { + var sOpIdx = aSortable[iIdx][0]; + this.operators[sOpIdx] = this.options.available_operators[sOpIdx]; + } }, // - Bind external events _bindEvents: function() @@ -138,7 +165,7 @@ $(function() // - Internal events _onButtonApply: function() { - this._trace('TODO: Apply button'); + this._trace('TODO: Apply button (call selected operator callback)'); this.handler.triggerHandler('itop.search.criteria.value_changed'); }, _onButtonCancel: function() @@ -182,8 +209,7 @@ $(function() // Bind events // - Toggler this.element.find('.sfc_toggle, .sfc_title').on('click', function(){ - me.element.find('.sfc_form_group').toggle(); - me.element.find('.sfc_toggle').toggleClass('opened'); + me.element.find('.sfc_form_group, .sfc_toggle').toggleClass('opened'); }); // Removable / locked decoration @@ -211,9 +237,9 @@ $(function() // Meant for overloading. _prepareOperators: function() { - for(var sOpIdx in this.options.available_operators) + for(var sOpIdx in this.operators) { - var oOp = this.options.available_operators[sOpIdx]; + var oOp = this.operators[sOpIdx]; var sMethod = '_prepare' + this._toCamelCase(oOp.code) + 'Operator'; // Create DOM element from template @@ -245,8 +271,8 @@ $(function() this.element.find('.sfc_fg_buttons') .append('') .append('') - .append('') - .append(''); + .append('') + .append(''); // Events this.element.find('.sfc_fg_button').on('click', function(oEvent){ diff --git a/js/search/search_form_criteria_string.js b/js/search/search_form_criteria_string.js index 522b22486..f25122f8d 100644 --- a/js/search/search_form_criteria_string.js +++ b/js/search/search_form_criteria_string.js @@ -10,17 +10,15 @@ $(function() options: { // Overload default operator - operator: 'contains', + 'operator': 'contains', // Available operators - available_operators: { + 'available_operators': { 'contains': { 'label': Dict.S('UI:Search:Criteria:Operator:String:Contains'), 'code': 'contains', 'rank': 5, }, - '=': { - 'rank': false, - }, + '=': null, // Remove this one from string widget. }, }, diff --git a/js/search/search_form_handler.js b/js/search/search_form_handler.js index 765e5eb64..d907a0d02 100644 --- a/js/search/search_form_handler.js +++ b/js/search/search_form_handler.js @@ -63,7 +63,6 @@ $(function() // }, ], }, - 'list_params': {}, // Passed through to the endpoint so it can render the list correctly regarding the context. 'supported_criterion_types': ['raw', 'string'], 'default_criteria_type': 'raw', }, @@ -144,6 +143,8 @@ $(function() // - Update search option of the widget _updateSearch: function() { + var me = this; + // Criterion // - Note: As of today, only a "or" level with a "and" is supported, so the following part // will need some refactoring when introducing new stuff. @@ -154,7 +155,17 @@ $(function() }; // - Retrieve criterion this.elements.active_criterion.find('.search_form_criteria').each(function(){ + // Retrieve criteria data var oCriteriaData = $(this).triggerHandler('itop.search.criteria.get_data'); + + // Add some of the field data to criteria data to help server rebuild query + // Note: This would be better to be passed in oCriteriaData.field but it's not how server is handling it. + var oFieldDef = me._getFieldDefinition(oCriteriaData.ref); + oCriteriaData.class = oFieldDef.class; + oCriteriaData.class_alias = oFieldDef.class_alias; + oCriteriaData.code = oFieldDef.code; + oCriteriaData.widget = oFieldDef.widget; + oCriterion['or'][0]['and'].push(oCriteriaData); }); // - Update search @@ -372,7 +383,7 @@ $(function() }, _getFieldDefinition: function(sRef) { - var oFieldDef = false; + var oFieldDef = null; for(var sListIdx in this.options.search.fields) { @@ -403,7 +414,7 @@ $(function() 'base_oql': this.options.search.base_oql, 'criterion': this.options.search.criterion, }), - 'list_params': JSON.stringify(this.options.list_params), + 'list_params': this.elements.results_area.data('sExtraParams'), }; // Show loader