diff options
Diffstat (limited to 'src/main/resources')
14 files changed, 3484 insertions, 2734 deletions
diff --git a/src/main/resources/META-INF/resources/designer/authenticate.html b/src/main/resources/META-INF/resources/designer/authenticate.html index 0db00c3da..8b30ef8cb 100644 --- a/src/main/resources/META-INF/resources/designer/authenticate.html +++ b/src/main/resources/META-INF/resources/designer/authenticate.html @@ -20,8 +20,41 @@ =================================================================== ECOMP is a trademark and service mark of AT&T Intellectual Property. --> +<style> +.divRow { + margin-left: 5px; + font-size: 20px; + font-weight: normal; +} +.divFormRow { + margin-left: 5px; + font-size: 13px; + font-weight: normal; +} -<div ng-init="authenticate()"> - <b>Validating Login.... Please wait....</b> +.divRow + .divForm { + margin-top:10px; +} +</style> + +<head> + <title>CLDS</title> +</head> +<div ng-controller="AuthenticateCtrl"> + <div id='head'> + <div ng-include="'menu_simplified.html'"></div> + </div> + + <div id='main'> + <div class="divRow"><b>Welcome to Clamp. Please login first.</b></div> + <div class="divForm"> + <form ng-submit="authenticate()"> + <div class="divFormRow"><label>User Name : <input type="text" ng-model="username" name="username"/> </label></div> + <div class="divFormRow"><label>Password: <input type="password" ng-model="password" name="password"/> </label></div> + <div class="divFormRow"><input type="submit" value=" Sign In"/></div> + </form> + </div> + </div> </div> + diff --git a/src/main/resources/META-INF/resources/designer/index.html b/src/main/resources/META-INF/resources/designer/index.html index a63bfd6be..31b20e34a 100644 --- a/src/main/resources/META-INF/resources/designer/index.html +++ b/src/main/resources/META-INF/resources/designer/index.html @@ -118,6 +118,7 @@ <!-- <script src="lib/angular.min.js"></script>--> <script src="lib/angular-route.js"></script> <script src="lib/angular-resource.min.js"></script> + <script src="lib/angular-md5.js"></script> <!-- jQuery Include and Bootstrap --> @@ -209,6 +210,8 @@ <script src="scripts/AutosaveProjectCtrl.js"></script> <script src="scripts/userPreferencesService.js"></script> + <script src="scripts/ExtraUserInfoCtrl.js"></script> + <script src="scripts/ExtraUserInfoService.js"></script> <script src="scripts/saveConfirmationModalPopUpCtrl.js"></script> <script src="scripts/CldsTemplateService.js"></script> <script src="scripts/CldsOpenTemplateCtrl.js"></script> diff --git a/src/main/resources/META-INF/resources/designer/lib/multiselect.js b/src/main/resources/META-INF/resources/designer/lib/multiselect.js index 9a50a18a0..fac82e894 100644 --- a/src/main/resources/META-INF/resources/designer/lib/multiselect.js +++ b/src/main/resources/META-INF/resources/designer/lib/multiselect.js @@ -1,1716 +1,1716 @@ -/** - * Bootstrap Multiselect (https://github.com/davidstutz/bootstrap-multiselect) - * - * Apache License, Version 2.0: - * Copyright (c) 2012 - 2015 David Stutz - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a - * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * BSD 3-Clause License: - * Copyright (c) 2012 - 2015 David Stutz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of David Stutz nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -!function ($) { - "use strict";// jshint ;_; - - if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) { - ko.bindingHandlers.multiselect = { - after: ['options', 'value', 'selectedOptions', 'enable', 'disable'], - - init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { - var $element = $(element); - var config = ko.toJS(valueAccessor()); - - $element.multiselect(config); - - if (allBindings.has('options')) { - var options = allBindings.get('options'); - if (ko.isObservable(options)) { - ko.computed({ - read: function() { - options(); - setTimeout(function() { - var ms = $element.data('multiselect'); - if (ms) - ms.updateOriginalOptions();//Not sure how beneficial this is. - $element.multiselect('rebuild'); - }, 1); - }, - disposeWhenNodeIsRemoved: element - }); - } - } - - //value and selectedOptions are two-way, so these will be triggered even by our own actions. - //It needs some way to tell if they are triggered because of us or because of outside change. - //It doesn't loop but it's a waste of processing. - if (allBindings.has('value')) { - var value = allBindings.get('value'); - if (ko.isObservable(value)) { - ko.computed({ - read: function() { - value(); - setTimeout(function() { - $element.multiselect('refresh'); - }, 1); - }, - disposeWhenNodeIsRemoved: element - }).extend({ rateLimit: 100, notifyWhenChangesStop: true }); - } - } - - //Switched from arrayChange subscription to general subscription using 'refresh'. - //Not sure performance is any better using 'select' and 'deselect'. - if (allBindings.has('selectedOptions')) { - var selectedOptions = allBindings.get('selectedOptions'); - if (ko.isObservable(selectedOptions)) { - ko.computed({ - read: function() { - selectedOptions(); - setTimeout(function() { - $element.multiselect('refresh'); - }, 1); - }, - disposeWhenNodeIsRemoved: element - }).extend({ rateLimit: 100, notifyWhenChangesStop: true }); - } - } - - var setEnabled = function (enable) { - setTimeout(function () { - if (enable) - $element.multiselect('enable'); - else - $element.multiselect('disable'); - }); - }; - - if (allBindings.has('enable')) { - var enable = allBindings.get('enable'); - if (ko.isObservable(enable)) { - ko.computed({ - read: function () { - setEnabled(enable()); - }, - disposeWhenNodeIsRemoved: element - }).extend({ rateLimit: 100, notifyWhenChangesStop: true }); - } else { - setEnabled(enable); - } - } - - if (allBindings.has('disable')) { - var disable = allBindings.get('disable'); - if (ko.isObservable(disable)) { - ko.computed({ - read: function () { - setEnabled(!disable()); - }, - disposeWhenNodeIsRemoved: element - }).extend({ rateLimit: 100, notifyWhenChangesStop: true }); - } else { - setEnabled(!disable); - } - } - - ko.utils.domNodeDisposal.addDisposeCallback(element, function() { - $element.multiselect('destroy'); - }); - }, - - update: function(element, valueAccessor, allBindings, viewModel, bindingContext) { - var $element = $(element); - var config = ko.toJS(valueAccessor()); - - $element.multiselect('setOptions', config); - $element.multiselect('rebuild'); - } - }; - } - - function forEach(array, callback) { - for (var index = 0; index < array.length; ++index) { - callback(array[index], index); - } - } - - /** - * Constructor to create a new multiselect using the given select. - * - * @param {jQuery} select - * @param {Object} options - * @returns {Multiselect} - */ - function Multiselect(select, options) { - - this.$select = $(select); - this.options = this.mergeOptions($.extend({}, options, this.$select.data())); - - // Placeholder via data attributes - if (this.$select.attr("data-placeholder")) { - this.options.nonSelectedText = this.$select.data("placeholder"); - } - - // Initialization. - // We have to clone to create a new reference. - this.originalOptions = this.$select.clone()[0].options; - this.query = ''; - this.searchTimeout = null; - this.lastToggledInput = null; - - this.options.multiple = this.$select.attr('multiple') === "multiple"; - this.options.onChange = $.proxy(this.options.onChange, this); - this.options.onSelectAll = $.proxy(this.options.onSelectAll, this); - this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this); - this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this); - this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this); - this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this); - this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this); - this.options.onInitialized = $.proxy(this.options.onInitialized, this); - this.options.onFiltering = $.proxy(this.options.onFiltering, this); - - // Build select all if enabled. - this.buildContainer(); - this.buildButton(); - this.buildDropdown(); - this.buildSelectAll(); - this.buildDropdownOptions(); - this.buildFilter(); - - this.updateButtonText(); - this.updateSelectAll(true); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - this.options.wasDisabled = this.$select.prop('disabled'); - if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) { - this.disable(); - } - - this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container); - this.options.onInitialized(this.$select, this.$container); - } - - Multiselect.prototype = { - - defaults: { - /** - * Default text function will either print 'None selected' in case no - * option is selected or a list of the selected options up to a length - * of 3 selected options. - * - * @param {jQuery} options - * @param {jQuery} select - * @returns {String} - */ - buttonText: function(options, select) { - if (this.disabledText.length > 0 - && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) { - - return this.disabledText; - } - else if (options.length === 0) { - return this.nonSelectedText; - } - else if (this.allSelectedText - && options.length === $('option', $(select)).length - && $('option', $(select)).length !== 1 - && this.multiple) { - - if (this.selectAllNumber) { - return this.allSelectedText + ' (' + options.length + ')'; - } - else { - return this.allSelectedText; - } - } - else if (options.length > this.numberDisplayed) { - return options.length + ' ' + this.nSelectedText; - } - else { - var selected = ''; - var delimiter = this.delimiterText; - - options.each(function() { - var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text(); - selected += label + delimiter; - }); - - return selected.substr(0, selected.length - this.delimiterText.length); - } - }, - /** - * Updates the title of the button similar to the buttonText function. - * - * @param {jQuery} options - * @param {jQuery} select - * @returns {@exp;selected@call;substr} - */ - buttonTitle: function(options, select) { - if (options.length === 0) { - return this.nonSelectedText; - } - else { - var selected = ''; - var delimiter = this.delimiterText; - - options.each(function () { - var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text(); - selected += label + delimiter; - }); - return selected.substr(0, selected.length - this.delimiterText.length); - } - }, - checkboxName: function(option) { - return false; // no checkbox name - }, - /** - * Create a label. - * - * @param {jQuery} element - * @returns {String} - */ - optionLabel: function(element){ - return $(element).attr('label') || $(element).text(); - }, - /** - * Create a class. - * - * @param {jQuery} element - * @returns {String} - */ - optionClass: function(element) { - return $(element).attr('class') || ''; - }, - /** - * Triggered on change of the multiselect. - * - * Not triggered when selecting/deselecting options manually. - * - * @param {jQuery} option - * @param {Boolean} checked - */ - onChange : function(option, checked) { - - }, - /** - * Triggered when the dropdown is shown. - * - * @param {jQuery} event - */ - onDropdownShow: function(event) { - - }, - /** - * Triggered when the dropdown is hidden. - * - * @param {jQuery} event - */ - onDropdownHide: function(event) { - - }, - /** - * Triggered after the dropdown is shown. - * - * @param {jQuery} event - */ - onDropdownShown: function(event) { - - }, - /** - * Triggered after the dropdown is hidden. - * - * @param {jQuery} event - */ - onDropdownHidden: function(event) { - - }, - /** - * Triggered on select all. - */ - onSelectAll: function() { - - }, - /** - * Triggered on deselect all. - */ - onDeselectAll: function() { - - }, - /** - * Triggered after initializing. - * - * @param {jQuery} $select - * @param {jQuery} $container - */ - onInitialized: function($select, $container) { - - }, - /** - * Triggered on filtering. - * - * @param {jQuery} $filter - */ - onFiltering: function($filter) { - - }, - enableHTML: false, - buttonClass: 'btn btn-default', - inheritClass: false, - buttonWidth: 'auto', - buttonContainer: '<div class="btn-group" />', - dropRight: false, - dropUp: false, - selectedClass: 'active', - // Maximum height of the dropdown menu. - // If maximum height is exceeded a scrollbar will be displayed. - maxHeight: false, - includeSelectAllOption: false, - includeSelectAllIfMoreThan: 0, - selectAllText: ' Select all', - selectAllValue: 'multiselect-all', - selectAllName: false, - selectAllNumber: true, - selectAllJustVisible: true, - enableFiltering: false, - enableCaseInsensitiveFiltering: false, - enableFullValueFiltering: false, - enableClickableOptGroups: false, - enableCollapsibleOptGroups: false, - filterPlaceholder: 'Search', - // possible options: 'text', 'value', 'both' - filterBehavior: 'text', - includeFilterClearBtn: true, - preventInputChangeEvent: false, - nonSelectedText: 'None selected', - nSelectedText: 'selected', - allSelectedText: 'All selected', - numberDisplayed: 3, - disableIfEmpty: false, - disabledText: '', - delimiterText: ', ', - templates: { - button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>', - ul: '<ul class="multiselect-container dropdown-menu"></ul>', - filter: '<li class="multiselect-item multiselect-filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>', - filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>', - li: '<li><a tabindex="0"><label></label></a></li>', - divider: '<li class="multiselect-item divider"></li>', - liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>' - } - }, - - constructor: Multiselect, - - /** - * Builds the container of the multiselect. - */ - buildContainer: function() { - this.$container = $(this.options.buttonContainer); - this.$container.on('show.bs.dropdown', this.options.onDropdownShow); - this.$container.on('hide.bs.dropdown', this.options.onDropdownHide); - this.$container.on('shown.bs.dropdown', this.options.onDropdownShown); - this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden); - }, - - /** - * Builds the button of the multiselect. - */ - buildButton: function() { - this.$button = $(this.options.templates.button).addClass(this.options.buttonClass); - if (this.$select.attr('class') && this.options.inheritClass) { - this.$button.addClass(this.$select.attr('class')); - } - // Adopt active state. - if (this.$select.prop('disabled')) { - this.disable(); - } - else { - this.enable(); - } - - // Manually add button width if set. - if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') { - this.$button.css({ - 'width' : '100%', //this.options.buttonWidth, - 'overflow' : 'hidden', - 'text-overflow' : 'ellipsis' - }); - this.$container.css({ - 'width': this.options.buttonWidth - }); - } - - // Keep the tab index from the select. - var tabindex = this.$select.attr('tabindex'); - if (tabindex) { - this.$button.attr('tabindex', tabindex); - } - - this.$container.prepend(this.$button); - }, - - /** - * Builds the ul representing the dropdown menu. - */ - buildDropdown: function() { - - // Build ul. - this.$ul = $(this.options.templates.ul); - - if (this.options.dropRight) { - this.$ul.addClass('pull-right'); - } - - // Set max height of dropdown menu to activate auto scrollbar. - if (this.options.maxHeight) { - // TODO: Add a class for this option to move the css declarations. - this.$ul.css({ - 'max-height': this.options.maxHeight + 'px', - 'overflow-y': 'auto', - 'overflow-x': 'hidden' - }); - } - - if (this.options.dropUp) { - - var height = Math.min(this.options.maxHeight, $('option[data-role!="divider"]', this.$select).length*26 + $('option[data-role="divider"]', this.$select).length*19 + (this.options.includeSelectAllOption ? 26 : 0) + (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering ? 44 : 0)); - var moveCalc = height + 34; - - this.$ul.css({ - 'max-height': height + 'px', - 'overflow-y': 'auto', - 'overflow-x': 'hidden', - 'margin-top': "-" + moveCalc + 'px' - }); - } - - this.$container.append(this.$ul); - }, - - /** - * Build the dropdown options and binds all necessary events. - * - * Uses createDivider and createOptionValue to create the necessary options. - */ - buildDropdownOptions: function() { - - this.$select.children().each($.proxy(function(index, element) { - - var $element = $(element); - // Support optgroups and options without a group simultaneously. - var tag = $element.prop('tagName') - .toLowerCase(); - - if ($element.prop('value') === this.options.selectAllValue) { - return; - } - - if (tag === 'optgroup') { - this.createOptgroup(element); - } - else if (tag === 'option') { - - if ($element.data('role') === 'divider') { - this.createDivider(); - } - else { - this.createOptionValue(element); - } - - } - - // Other illegal tags will be ignored. - }, this)); - - // Bind the change event on the dropdown elements. - $('li:not(.multiselect-group) input', this.$ul).on('change', $.proxy(function(event) { - var $target = $(event.target); - - var checked = $target.prop('checked') || false; - var isSelectAllOption = $target.val() === this.options.selectAllValue; - - // Apply or unapply the configured selected class. - if (this.options.selectedClass) { - if (checked) { - $target.closest('li') - .addClass(this.options.selectedClass); - } - else { - $target.closest('li') - .removeClass(this.options.selectedClass); - } - } - - // Get the corresponding option. - var value = $target.val(); - var $option = this.getOptionByValue(value); - - var $optionsNotThis = $('option', this.$select).not($option); - var $checkboxesNotThis = $('input', this.$container).not($target); - - if (isSelectAllOption) { - - if (checked) { - this.selectAll(this.options.selectAllJustVisible, true); - } - else { - this.deselectAll(this.options.selectAllJustVisible, true); - } - } - else { - if (checked) { - $option.prop('selected', true); - - if (this.options.multiple) { - // Simply select additional option. - $option.prop('selected', true); - } - else { - // Unselect all other options and corresponding checkboxes. - if (this.options.selectedClass) { - $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass); - } - - $($checkboxesNotThis).prop('checked', false); - $optionsNotThis.prop('selected', false); - - // It's a single selection, so close. - this.$button.click(); - } - - if (this.options.selectedClass === "active") { - $optionsNotThis.closest("a").css("outline", ""); - } - } - else { - // Unselect option. - $option.prop('selected', false); - } - - // To prevent select all from firing onChange: #575 - this.options.onChange($option, checked); - - // Do not update select all or optgroups on select all change! - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - } - - this.$select.change(); - this.updateButtonText(); - - if(this.options.preventInputChangeEvent) { - return false; - } - }, this)); - - $('li a', this.$ul).on('mousedown', function(e) { - if (e.shiftKey) { - // Prevent selecting text by Shift+click - return false; - } - }); - - $('li a', this.$ul).on('touchstart click', $.proxy(function(event) { - event.stopPropagation(); - - var $target = $(event.target); - - if (event.shiftKey && this.options.multiple) { - if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431) - event.preventDefault(); - $target = $target.find("input"); - $target.prop("checked", !$target.prop("checked")); - } - var checked = $target.prop('checked') || false; - - if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range - var from = $target.closest("li").index(); - var to = this.lastToggledInput.closest("li").index(); - - if (from > to) { // Swap the indices - var tmp = to; - to = from; - from = tmp; - } - - // Make sure we grab all elements since slice excludes the last index - ++to; - - // Change the checkboxes and underlying options - var range = this.$ul.find("li").slice(from, to).find("input"); - - range.prop('checked', checked); - - if (this.options.selectedClass) { - range.closest('li') - .toggleClass(this.options.selectedClass, checked); - } - - for (var i = 0, j = range.length; i < j; i++) { - var $checkbox = $(range[i]); - - var $option = this.getOptionByValue($checkbox.val()); - - $option.prop('selected', checked); - } - } - - // Trigger the select "change" event - $target.trigger("change"); - } - - // Remembers last clicked option - if($target.is("input") && !$target.closest("li").is(".multiselect-item")){ - this.lastToggledInput = $target; - } - - $target.blur(); - }, this)); - - // Keyboard support. - this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) { - if ($('input[type="text"]', this.$container).is(':focus')) { - return; - } - - if (event.keyCode === 9 && this.$container.hasClass('open')) { - this.$button.click(); - } - else { - var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible"); - - if (!$items.length) { - return; - } - - var index = $items.index($items.filter(':focus')); - - // Navigation up. - if (event.keyCode === 38 && index > 0) { - index--; - } - // Navigate down. - else if (event.keyCode === 40 && index < $items.length - 1) { - index++; - } - else if (!~index) { - index = 0; - } - - var $current = $items.eq(index); - $current.focus(); - - if (event.keyCode === 32 || event.keyCode === 13) { - var $checkbox = $current.find('input'); - - $checkbox.prop("checked", !$checkbox.prop("checked")); - $checkbox.change(); - } - - event.stopPropagation(); - event.preventDefault(); - } - }, this)); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - $("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) { - event.stopPropagation(); - - var $target = $(event.target); - var checked = $target.prop('checked') || false; - - var $li = $(event.target).closest('li'); - var $group = $li.nextUntil("li.multiselect-group") - .not('.multiselect-filter-hidden') - .not('.disabled'); - - var $inputs = $group.find("input"); - - var values = []; - var $options = []; - - if (this.options.selectedClass) { - if (checked) { - $li.addClass(this.options.selectedClass); - } - else { - $li.removeClass(this.options.selectedClass); - } - } - - $.each($inputs, $.proxy(function(index, input) { - var value = $(input).val(); - var $option = this.getOptionByValue(value); - - if (checked) { - $(input).prop('checked', true); - $(input).closest('li') - .addClass(this.options.selectedClass); - - $option.prop('selected', true); - } - else { - $(input).prop('checked', false); - $(input).closest('li') - .removeClass(this.options.selectedClass); - - $option.prop('selected', false); - } - - $options.push(this.getOptionByValue(value)); - }, this)) - - // Cannot use select or deselect here because it would call updateOptGroups again. - - this.options.onChange($options, checked); - - this.updateButtonText(); - this.updateSelectAll(); - }, this)); - } - - if (this.options.enableCollapsibleOptGroups && this.options.multiple) { - $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) { - var $li = $(event.target).closest('li'); - var $inputs = $li.nextUntil("li.multiselect-group") - .not('.multiselect-filter-hidden'); - - var visible = true; - $inputs.each(function() { - visible = visible && $(this).is(':visible'); - }); - - if (visible) { - $inputs.hide() - .addClass('multiselect-collapsible-hidden'); - } - else { - $inputs.show() - .removeClass('multiselect-collapsible-hidden'); - } - }, this)); - - $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea'); - $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px'); - $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px'); - } - }, - - /** - * Create an option using the given select option. - * - * @param {jQuery} element - */ - createOptionValue: function(element) { - var $element = $(element); - if ($element.is(':selected')) { - $element.prop('selected', true); - } - - // Support the label attribute on options. - var label = this.options.optionLabel(element); - var classes = this.options.optionClass(element); - var value = $element.val(); - var inputType = this.options.multiple ? "checkbox" : "radio"; - - var $li = $(this.options.templates.li); - var $label = $('label', $li); - $label.addClass(inputType); - $li.addClass(classes); - - if (this.options.enableHTML) { - $label.html(" " + label); - } - else { - $label.text(" " + label); - } - - var $checkbox = $('<input/>').attr('type', inputType); - - var name = this.options.checkboxName($element); - if (name) { - $checkbox.attr('name', name); - } - - $label.prepend($checkbox); - - var selected = $element.prop('selected') || false; - $checkbox.val(value); - - if (value === this.options.selectAllValue) { - $li.addClass("multiselect-item multiselect-all"); - $checkbox.parent().parent() - .addClass('multiselect-all'); - } - - $label.attr('title', $element.attr('title')); - - this.$ul.append($li); - - if ($element.is(':disabled')) { - $checkbox.attr('disabled', 'disabled') - .prop('disabled', true) - .closest('a') - .attr("tabindex", "-1") - .closest('li') - .addClass('disabled'); - } - - $checkbox.prop('checked', selected); - - if (selected && this.options.selectedClass) { - $checkbox.closest('li') - .addClass(this.options.selectedClass); - } - }, - - /** - * Creates a divider using the given select option. - * - * @param {jQuery} element - */ - createDivider: function(element) { - var $divider = $(this.options.templates.divider); - this.$ul.append($divider); - }, - - /** - * Creates an optgroup. - * - * @param {jQuery} group - */ - createOptgroup: function(group) { - var label = $(group).attr("label"); - var value = $(group).attr("value"); - var $li = $('<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><label><b></b></label></a></li>'); - - var classes = this.options.optionClass(group); - $li.addClass(classes); - - if (this.options.enableHTML) { - $('label b', $li).html(" " + label); - } - else { - $('label b', $li).text(" " + label); - } - - if (this.options.enableCollapsibleOptGroups && this.options.multiple) { - $('a', $li).append('<span class="caret-container"><b class="caret"></b></span>'); - } - - if (this.options.enableClickableOptGroups && this.options.multiple) { - $('a label', $li).prepend('<input type="checkbox" value="' + value + '"/>'); - } - - if ($(group).is(':disabled')) { - $li.addClass('disabled'); - } - - this.$ul.append($li); - - $("option", group).each($.proxy(function($, group) { - this.createOptionValue(group); - }, this)) - }, - - /** - * Build the select all. - * - * Checks if a select all has already been created. - */ - buildSelectAll: function() { - if (typeof this.options.selectAllValue === 'number') { - this.options.selectAllValue = this.options.selectAllValue.toString(); - } - - var alreadyHasSelectAll = this.hasSelectAll(); - - if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple - && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) { - - // Check whether to add a divider after the select all. - if (this.options.includeSelectAllDivider) { - this.$ul.prepend($(this.options.templates.divider)); - } - - var $li = $(this.options.templates.li); - $('label', $li).addClass("checkbox"); - - if (this.options.enableHTML) { - $('label', $li).html(" " + this.options.selectAllText); - } - else { - $('label', $li).text(" " + this.options.selectAllText); - } - - if (this.options.selectAllName) { - $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />'); - } - else { - $('label', $li).prepend('<input type="checkbox" />'); - } - - var $checkbox = $('input', $li); - $checkbox.val(this.options.selectAllValue); - - $li.addClass("multiselect-item multiselect-all"); - $checkbox.parent().parent() - .addClass('multiselect-all'); - - this.$ul.prepend($li); - - $checkbox.prop('checked', false); - } - }, - - /** - * Builds the filter. - */ - buildFilter: function() { - - // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength. - if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) { - var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering); - - if (this.$select.find('option').length >= enableFilterLength) { - - this.$filter = $(this.options.templates.filter); - $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder); - - // Adds optional filter clear button - if(this.options.includeFilterClearBtn) { - var clearBtn = $(this.options.templates.filterClearBtn); - clearBtn.on('click', $.proxy(function(event){ - clearTimeout(this.searchTimeout); - - this.$filter.find('.multiselect-search').val(''); - $('li', this.$ul).show().removeClass('multiselect-filter-hidden'); - - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - }, this)); - this.$filter.find('.input-group').append(clearBtn); - } - - this.$ul.prepend(this.$filter); - - this.$filter.val(this.query).on('click', function(event) { - event.stopPropagation(); - }).on('input keydown', $.proxy(function(event) { - // Cancel enter key default behaviour - if (event.which === 13) { - event.preventDefault(); - } - - // This is useful to catch "keydown" events after the browser has updated the control. - clearTimeout(this.searchTimeout); - - this.searchTimeout = this.asyncFunction($.proxy(function() { - - if (this.query !== event.target.value) { - this.query = event.target.value; - - var currentGroup, currentGroupVisible; - $.each($('li', this.$ul), $.proxy(function(index, element) { - var value = $('input', element).length > 0 ? $('input', element).val() : ""; - var text = $('label', element).text(); - - var filterCandidate = ''; - if ((this.options.filterBehavior === 'text')) { - filterCandidate = text; - } - else if ((this.options.filterBehavior === 'value')) { - filterCandidate = value; - } - else if (this.options.filterBehavior === 'both') { - filterCandidate = text + '\n' + value; - } - - if (value !== this.options.selectAllValue && text) { - - // By default lets assume that element is not - // interesting for this search. - var showElement = false; - - if (this.options.enableCaseInsensitiveFiltering) { - filterCandidate = filterCandidate.toLowerCase(); - this.query = this.query.toLowerCase(); - } - - if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') { - var valueToMatch = filterCandidate.trim().substring(0, this.query.length); - if (this.query.indexOf(valueToMatch) > -1) { - showElement = true; - } - } - else if (filterCandidate.indexOf(this.query) > -1) { - showElement = true; - } - - // Toggle current element (group or group item) according to showElement boolean. - $(element).toggle(showElement) - .toggleClass('multiselect-filter-hidden', !showElement); - - // Differentiate groups and group items. - if ($(element).hasClass('multiselect-group')) { - // Remember group status. - currentGroup = element; - currentGroupVisible = showElement; - } - else { - // Show group name when at least one of its items is visible. - if (showElement) { - $(currentGroup).show() - .removeClass('multiselect-filter-hidden'); - } - - // Show all group items when group name satisfies filter. - if (!showElement && currentGroupVisible) { - $(element).show() - .removeClass('multiselect-filter-hidden'); - } - } - } - }, this)); - } - - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - this.options.onFiltering(event.target); - - }, this), 300, this); - }, this)); - } - } - }, - - /** - * Unbinds the whole plugin. - */ - destroy: function() { - this.$container.remove(); - this.$select.show(); - - // reset original state - this.$select.prop('disabled', this.options.wasDisabled); - - this.$select.data('multiselect', null); - }, - - /** - * Refreshs the multiselect based on the selected options of the select. - */ - refresh: function () { - var inputs = $.map($('li input', this.$ul), $); - - $('option', this.$select).each($.proxy(function (index, element) { - var $elem = $(element); - var value = $elem.val(); - var $input; - for (var i = inputs.length; 0 < i--; /**/) { - if (value !== ($input = inputs[i]).val()) - continue; // wrong li - - if ($elem.is(':selected')) { - $input.prop('checked', true); - - if (this.options.selectedClass) { - $input.closest('li') - .addClass(this.options.selectedClass); - } - } - else { - $input.prop('checked', false); - - if (this.options.selectedClass) { - $input.closest('li') - .removeClass(this.options.selectedClass); - } - } - - if ($elem.is(":disabled")) { - $input.attr('disabled', 'disabled') - .prop('disabled', true) - .closest('li') - .addClass('disabled'); - } - else { - $input.prop('disabled', false) - .closest('li') - .removeClass('disabled'); - } - break; // assumes unique values - } - }, this)); - - this.updateButtonText(); - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - }, - - /** - * Select all options of the given values. - * - * If triggerOnChange is set to true, the on change event is triggered if - * and only if one value is passed. - * - * @param {Array} selectValues - * @param {Boolean} triggerOnChange - */ - select: function(selectValues, triggerOnChange) { - if(!$.isArray(selectValues)) { - selectValues = [selectValues]; - } - - for (var i = 0; i < selectValues.length; i++) { - var value = selectValues[i]; - - if (value === null || value === undefined) { - continue; - } - - var $option = this.getOptionByValue(value); - var $checkbox = this.getInputByValue(value); - - if($option === undefined || $checkbox === undefined) { - continue; - } - - if (!this.options.multiple) { - this.deselectAll(false); - } - - if (this.options.selectedClass) { - $checkbox.closest('li') - .addClass(this.options.selectedClass); - } - - $checkbox.prop('checked', true); - $option.prop('selected', true); - - if (triggerOnChange) { - this.options.onChange($option, true); - } - } - - this.updateButtonText(); - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - }, - - /** - * Clears all selected items. - */ - clearSelection: function () { - this.deselectAll(false); - this.updateButtonText(); - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - }, - - /** - * Deselects all options of the given values. - * - * If triggerOnChange is set to true, the on change event is triggered, if - * and only if one value is passed. - * - * @param {Array} deselectValues - * @param {Boolean} triggerOnChange - */ - deselect: function(deselectValues, triggerOnChange) { - if(!$.isArray(deselectValues)) { - deselectValues = [deselectValues]; - } - - for (var i = 0; i < deselectValues.length; i++) { - var value = deselectValues[i]; - - if (value === null || value === undefined) { - continue; - } - - var $option = this.getOptionByValue(value); - var $checkbox = this.getInputByValue(value); - - if($option === undefined || $checkbox === undefined) { - continue; - } - - if (this.options.selectedClass) { - $checkbox.closest('li') - .removeClass(this.options.selectedClass); - } - - $checkbox.prop('checked', false); - $option.prop('selected', false); - - if (triggerOnChange) { - this.options.onChange($option, false); - } - } - - this.updateButtonText(); - this.updateSelectAll(); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - }, - - /** - * Selects all enabled & visible options. - * - * If justVisible is true or not specified, only visible options are selected. - * - * @param {Boolean} justVisible - * @param {Boolean} triggerOnSelectAll - */ - selectAll: function (justVisible, triggerOnSelectAll) { - - var justVisible = typeof justVisible === 'undefined' ? true : justVisible; - var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul); - var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible'); - - if(justVisible) { - $('input:enabled' , visibleLis).prop('checked', true); - visibleLis.addClass(this.options.selectedClass); - - $('input:enabled' , visibleLis).each($.proxy(function(index, element) { - var value = $(element).val(); - var option = this.getOptionByValue(value); - $(option).prop('selected', true); - }, this)); - } - else { - $('input:enabled' , allLis).prop('checked', true); - allLis.addClass(this.options.selectedClass); - - $('input:enabled' , allLis).each($.proxy(function(index, element) { - var value = $(element).val(); - var option = this.getOptionByValue(value); - $(option).prop('selected', true); - }, this)); - } - - $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', true); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - if (triggerOnSelectAll) { - this.options.onSelectAll(); - } - }, - - /** - * Deselects all options. - * - * If justVisible is true or not specified, only visible options are deselected. - * - * @param {Boolean} justVisible - */ - deselectAll: function (justVisible, triggerOnDeselectAll) { - - var justVisible = typeof justVisible === 'undefined' ? true : justVisible; - var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul); - var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible'); - - if(justVisible) { - $('input[type="checkbox"]:enabled' , visibleLis).prop('checked', false); - visibleLis.removeClass(this.options.selectedClass); - - $('input[type="checkbox"]:enabled' , visibleLis).each($.proxy(function(index, element) { - var value = $(element).val(); - var option = this.getOptionByValue(value); - $(option).prop('selected', false); - }, this)); - } - else { - $('input[type="checkbox"]:enabled' , allLis).prop('checked', false); - allLis.removeClass(this.options.selectedClass); - - $('input[type="checkbox"]:enabled' , allLis).each($.proxy(function(index, element) { - var value = $(element).val(); - var option = this.getOptionByValue(value); - $(option).prop('selected', false); - }, this)); - } - - $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', false); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - if (triggerOnDeselectAll) { - this.options.onDeselectAll(); - } - }, - - /** - * Rebuild the plugin. - * - * Rebuilds the dropdown, the filter and the select all option. - */ - rebuild: function() { - this.$ul.html(''); - - // Important to distinguish between radios and checkboxes. - this.options.multiple = this.$select.attr('multiple') === "multiple"; - - this.buildSelectAll(); - this.buildDropdownOptions(); - this.buildFilter(); - - this.updateButtonText(); - this.updateSelectAll(true); - - if (this.options.enableClickableOptGroups && this.options.multiple) { - this.updateOptGroups(); - } - - if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) { - this.disable(); - } - else { - this.enable(); - } - - if (this.options.dropRight) { - this.$ul.addClass('pull-right'); - } - }, - - /** - * The provided data will be used to build the dropdown. - */ - dataprovider: function(dataprovider) { - - var groupCounter = 0; - var $select = this.$select.empty(); - - $.each(dataprovider, function (index, option) { - var $tag; - - if ($.isArray(option.children)) { // create optiongroup tag - groupCounter++; - - $tag = $('<optgroup/>').attr({ - label: option.label || 'Group ' + groupCounter, - disabled: !!option.disabled - }); - - forEach(option.children, function(subOption) { // add children option tags - var attributes = { - value: subOption.value, - label: subOption.label || subOption.value, - title: subOption.title, - selected: !!subOption.selected, - disabled: !!subOption.disabled - }; - - //Loop through attributes object and add key-value for each attribute - for (var key in subOption.attributes) { - attributes['data-' + key] = subOption.attributes[key]; - } - //Append original attributes + new data attributes to option - $tag.append($('<option/>').attr(attributes)); - }); - } - else { - - var attributes = { - 'value': option.value, - 'label': option.label || option.value, - 'title': option.title, - 'class': option.class, - 'selected': !!option.selected, - 'disabled': !!option.disabled - }; - //Loop through attributes object and add key-value for each attribute - for (var key in option.attributes) { - attributes['data-' + key] = option.attributes[key]; - } - //Append original attributes + new data attributes to option - $tag = $('<option/>').attr(attributes); - - $tag.text(option.label || option.value); - } - - $select.append($tag); - }); - - this.rebuild(); - }, - - /** - * Enable the multiselect. - */ - enable: function() { - this.$select.prop('disabled', false); - this.$button.prop('disabled', false) - .removeClass('disabled'); - }, - - /** - * Disable the multiselect. - */ - disable: function() { - this.$select.prop('disabled', true); - this.$button.prop('disabled', true) - .addClass('disabled'); - }, - - /** - * Set the options. - * - * @param {Array} options - */ - setOptions: function(options) { - this.options = this.mergeOptions(options); - }, - - /** - * Merges the given options with the default options. - * - * @param {Array} options - * @returns {Array} - */ - mergeOptions: function(options) { - return $.extend(true, {}, this.defaults, this.options, options); - }, - - /** - * Checks whether a select all checkbox is present. - * - * @returns {Boolean} - */ - hasSelectAll: function() { - return $('li.multiselect-all', this.$ul).length > 0; - }, - - /** - * Update opt groups. - */ - updateOptGroups: function() { - var $groups = $('li.multiselect-group', this.$ul) - var selectedClass = this.options.selectedClass; - - $groups.each(function() { - var $options = $(this).nextUntil('li.multiselect-group') - .not('.multiselect-filter-hidden') - .not('.disabled'); - - var checked = true; - $options.each(function() { - var $input = $('input', this); - - if (!$input.prop('checked')) { - checked = false; - } - }); - - if (selectedClass) { - if (checked) { - $(this).addClass(selectedClass); - } - else { - $(this).removeClass(selectedClass); - } - } - - $('input', this).prop('checked', checked); - }); - }, - - /** - * Updates the select all checkbox based on the currently displayed and selected checkboxes. - */ - updateSelectAll: function(notTriggerOnSelectAll) { - if (this.hasSelectAll()) { - var allBoxes = $("li:not(.multiselect-item):not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$ul); - var allBoxesLength = allBoxes.length; - var checkedBoxesLength = allBoxes.filter(":checked").length; - var selectAllLi = $("li.multiselect-all", this.$ul); - var selectAllInput = selectAllLi.find("input"); - - if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) { - selectAllInput.prop("checked", true); - selectAllLi.addClass(this.options.selectedClass); - } - else { - selectAllInput.prop("checked", false); - selectAllLi.removeClass(this.options.selectedClass); - } - } - }, - - /** - * Update the button text and its title based on the currently selected options. - */ - updateButtonText: function() { - var options = this.getSelected(); - - // First update the displayed button text. - if (this.options.enableHTML) { - $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select)); - } - else { - $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select)); - } - - // Now update the title attribute of the button. - $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select)); - }, - - /** - * Get all selected options. - * - * @returns {jQUery} - */ - getSelected: function() { - return $('option', this.$select).filter(":selected"); - }, - - /** - * Gets a select option by its value. - * - * @param {String} value - * @returns {jQuery} - */ - getOptionByValue: function (value) { - - var options = $('option', this.$select); - var valueToCompare = value.toString(); - - for (var i = 0; i < options.length; i = i + 1) { - var option = options[i]; - if (option.value === valueToCompare) { - return $(option); - } - } - }, - - /** - * Get the input (radio/checkbox) by its value. - * - * @param {String} value - * @returns {jQuery} - */ - getInputByValue: function (value) { - - var checkboxes = $('li input:not(.multiselect-search)', this.$ul); - var valueToCompare = value.toString(); - - for (var i = 0; i < checkboxes.length; i = i + 1) { - var checkbox = checkboxes[i]; - if (checkbox.value === valueToCompare) { - return $(checkbox); - } - } - }, - - /** - * Used for knockout integration. - */ - updateOriginalOptions: function() { - this.originalOptions = this.$select.clone()[0].options; - }, - - asyncFunction: function(callback, timeout, self) { - var args = Array.prototype.slice.call(arguments, 3); - return setTimeout(function() { - callback.apply(self || window, args); - }, timeout); - }, - - setAllSelectedText: function(allSelectedText) { - this.options.allSelectedText = allSelectedText; - this.updateButtonText(); - } - }; - - $.fn.multiselect = function(option, parameter, extraOptions) { - return this.each(function() { - var data = $(this).data('multiselect'); - var options = typeof option === 'object' && option; - - // Initialize the multiselect. - if (!data) { - data = new Multiselect(this, options); - $(this).data('multiselect', data); - } - - // Call multiselect method. - if (typeof option === 'string') { - data[option](parameter, extraOptions); - - if (option === 'destroy') { - $(this).data('multiselect', false); - } - } - }); - }; - - $.fn.multiselect.Constructor = Multiselect; - - $(function() { - $("select[data-role=multiselect]").multiselect(); - }); - -}(window.jQuery); +/**
+ * Bootstrap Multiselect (https://github.com/davidstutz/bootstrap-multiselect)
+ *
+ * Apache License, Version 2.0:
+ * Copyright (c) 2012 - 2015 David Stutz
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a
+ * copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * BSD 3-Clause License:
+ * Copyright (c) 2012 - 2015 David Stutz
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of David Stutz nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+!function ($) {
+ "use strict";// jshint ;_;
+
+ if (typeof ko !== 'undefined' && ko.bindingHandlers && !ko.bindingHandlers.multiselect) {
+ ko.bindingHandlers.multiselect = {
+ after: ['options', 'value', 'selectedOptions', 'enable', 'disable'],
+
+ init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
+ var $element = $(element);
+ var config = ko.toJS(valueAccessor());
+
+ $element.multiselect(config);
+
+ if (allBindings.has('options')) {
+ var options = allBindings.get('options');
+ if (ko.isObservable(options)) {
+ ko.computed({
+ read: function() {
+ options();
+ setTimeout(function() {
+ var ms = $element.data('multiselect');
+ if (ms)
+ ms.updateOriginalOptions();//Not sure how beneficial this is.
+ $element.multiselect('rebuild');
+ }, 1);
+ },
+ disposeWhenNodeIsRemoved: element
+ });
+ }
+ }
+
+ //value and selectedOptions are two-way, so these will be triggered even by our own actions.
+ //It needs some way to tell if they are triggered because of us or because of outside change.
+ //It doesn't loop but it's a waste of processing.
+ if (allBindings.has('value')) {
+ var value = allBindings.get('value');
+ if (ko.isObservable(value)) {
+ ko.computed({
+ read: function() {
+ value();
+ setTimeout(function() {
+ $element.multiselect('refresh');
+ }, 1);
+ },
+ disposeWhenNodeIsRemoved: element
+ }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
+ }
+ }
+
+ //Switched from arrayChange subscription to general subscription using 'refresh'.
+ //Not sure performance is any better using 'select' and 'deselect'.
+ if (allBindings.has('selectedOptions')) {
+ var selectedOptions = allBindings.get('selectedOptions');
+ if (ko.isObservable(selectedOptions)) {
+ ko.computed({
+ read: function() {
+ selectedOptions();
+ setTimeout(function() {
+ $element.multiselect('refresh');
+ }, 1);
+ },
+ disposeWhenNodeIsRemoved: element
+ }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
+ }
+ }
+
+ var setEnabled = function (enable) {
+ setTimeout(function () {
+ if (enable)
+ $element.multiselect('enable');
+ else
+ $element.multiselect('disable');
+ });
+ };
+
+ if (allBindings.has('enable')) {
+ var enable = allBindings.get('enable');
+ if (ko.isObservable(enable)) {
+ ko.computed({
+ read: function () {
+ setEnabled(enable());
+ },
+ disposeWhenNodeIsRemoved: element
+ }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
+ } else {
+ setEnabled(enable);
+ }
+ }
+
+ if (allBindings.has('disable')) {
+ var disable = allBindings.get('disable');
+ if (ko.isObservable(disable)) {
+ ko.computed({
+ read: function () {
+ setEnabled(!disable());
+ },
+ disposeWhenNodeIsRemoved: element
+ }).extend({ rateLimit: 100, notifyWhenChangesStop: true });
+ } else {
+ setEnabled(!disable);
+ }
+ }
+
+ ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
+ $element.multiselect('destroy');
+ });
+ },
+
+ update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
+ var $element = $(element);
+ var config = ko.toJS(valueAccessor());
+
+ $element.multiselect('setOptions', config);
+ $element.multiselect('rebuild');
+ }
+ };
+ }
+
+ function forEach(array, callback) {
+ for (var index = 0; index < array.length; ++index) {
+ callback(array[index], index);
+ }
+ }
+
+ /**
+ * Constructor to create a new multiselect using the given select.
+ *
+ * @param {jQuery} select
+ * @param {Object} options
+ * @returns {Multiselect}
+ */
+ function Multiselect(select, options) {
+
+ this.$select = $(select);
+ this.options = this.mergeOptions($.extend({}, options, this.$select.data()));
+
+ // Placeholder via data attributes
+ if (this.$select.attr("data-placeholder")) {
+ this.options.nonSelectedText = this.$select.data("placeholder");
+ }
+
+ // Initialization.
+ // We have to clone to create a new reference.
+ this.originalOptions = this.$select.clone()[0].options;
+ this.query = '';
+ this.searchTimeout = null;
+ this.lastToggledInput = null;
+
+ this.options.multiple = this.$select.attr('multiple') === "multiple";
+ this.options.onChange = $.proxy(this.options.onChange, this);
+ this.options.onSelectAll = $.proxy(this.options.onSelectAll, this);
+ this.options.onDeselectAll = $.proxy(this.options.onDeselectAll, this);
+ this.options.onDropdownShow = $.proxy(this.options.onDropdownShow, this);
+ this.options.onDropdownHide = $.proxy(this.options.onDropdownHide, this);
+ this.options.onDropdownShown = $.proxy(this.options.onDropdownShown, this);
+ this.options.onDropdownHidden = $.proxy(this.options.onDropdownHidden, this);
+ this.options.onInitialized = $.proxy(this.options.onInitialized, this);
+ this.options.onFiltering = $.proxy(this.options.onFiltering, this);
+
+ // Build select all if enabled.
+ this.buildContainer();
+ this.buildButton();
+ this.buildDropdown();
+ this.buildSelectAll();
+ this.buildDropdownOptions();
+ this.buildFilter();
+
+ this.updateButtonText();
+ this.updateSelectAll(true);
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ this.options.wasDisabled = this.$select.prop('disabled');
+ if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
+ this.disable();
+ }
+
+ this.$select.wrap('<span class="multiselect-native-select" />').after(this.$container);
+ this.options.onInitialized(this.$select, this.$container);
+ }
+
+ Multiselect.prototype = {
+
+ defaults: {
+ /**
+ * Default text function will either print 'None selected' in case no
+ * option is selected or a list of the selected options up to a length
+ * of 3 selected options.
+ *
+ * @param {jQuery} options
+ * @param {jQuery} select
+ * @returns {String}
+ */
+ buttonText: function(options, select) {
+ if (this.disabledText.length > 0
+ && (select.prop('disabled') || (options.length == 0 && this.disableIfEmpty))) {
+
+ return this.disabledText;
+ }
+ else if (options.length === 0) {
+ return this.nonSelectedText;
+ }
+ else if (this.allSelectedText
+ && options.length === $('option', $(select)).length
+ && $('option', $(select)).length !== 1
+ && this.multiple) {
+
+ if (this.selectAllNumber) {
+ return this.allSelectedText + ' (' + options.length + ')';
+ }
+ else {
+ return this.allSelectedText;
+ }
+ }
+ else if (options.length > this.numberDisplayed) {
+ return options.length + ' ' + this.nSelectedText;
+ }
+ else {
+ var selected = '';
+ var delimiter = this.delimiterText;
+
+ options.each(function() {
+ var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
+ selected += label + delimiter;
+ });
+
+ return selected.substr(0, selected.length - this.delimiterText.length);
+ }
+ },
+ /**
+ * Updates the title of the button similar to the buttonText function.
+ *
+ * @param {jQuery} options
+ * @param {jQuery} select
+ * @returns {@exp;selected@call;substr}
+ */
+ buttonTitle: function(options, select) {
+ if (options.length === 0) {
+ return this.nonSelectedText;
+ }
+ else {
+ var selected = '';
+ var delimiter = this.delimiterText;
+
+ options.each(function () {
+ var label = ($(this).attr('label') !== undefined) ? $(this).attr('label') : $(this).text();
+ selected += label + delimiter;
+ });
+ return selected.substr(0, selected.length - this.delimiterText.length);
+ }
+ },
+ checkboxName: function(option) {
+ return false; // no checkbox name
+ },
+ /**
+ * Create a label.
+ *
+ * @param {jQuery} element
+ * @returns {String}
+ */
+ optionLabel: function(element){
+ return $(element).attr('label') || $(element).text();
+ },
+ /**
+ * Create a class.
+ *
+ * @param {jQuery} element
+ * @returns {String}
+ */
+ optionClass: function(element) {
+ return $(element).attr('class') || '';
+ },
+ /**
+ * Triggered on change of the multiselect.
+ *
+ * Not triggered when selecting/deselecting options manually.
+ *
+ * @param {jQuery} option
+ * @param {Boolean} checked
+ */
+ onChange : function(option, checked) {
+
+ },
+ /**
+ * Triggered when the dropdown is shown.
+ *
+ * @param {jQuery} event
+ */
+ onDropdownShow: function(event) {
+
+ },
+ /**
+ * Triggered when the dropdown is hidden.
+ *
+ * @param {jQuery} event
+ */
+ onDropdownHide: function(event) {
+
+ },
+ /**
+ * Triggered after the dropdown is shown.
+ *
+ * @param {jQuery} event
+ */
+ onDropdownShown: function(event) {
+
+ },
+ /**
+ * Triggered after the dropdown is hidden.
+ *
+ * @param {jQuery} event
+ */
+ onDropdownHidden: function(event) {
+
+ },
+ /**
+ * Triggered on select all.
+ */
+ onSelectAll: function() {
+
+ },
+ /**
+ * Triggered on deselect all.
+ */
+ onDeselectAll: function() {
+
+ },
+ /**
+ * Triggered after initializing.
+ *
+ * @param {jQuery} $select
+ * @param {jQuery} $container
+ */
+ onInitialized: function($select, $container) {
+
+ },
+ /**
+ * Triggered on filtering.
+ *
+ * @param {jQuery} $filter
+ */
+ onFiltering: function($filter) {
+
+ },
+ enableHTML: false,
+ buttonClass: 'btn btn-default',
+ inheritClass: false,
+ buttonWidth: 'auto',
+ buttonContainer: '<div class="btn-group" />',
+ dropRight: false,
+ dropUp: false,
+ selectedClass: 'active',
+ // Maximum height of the dropdown menu.
+ // If maximum height is exceeded a scrollbar will be displayed.
+ maxHeight: false,
+ includeSelectAllOption: false,
+ includeSelectAllIfMoreThan: 0,
+ selectAllText: ' Select all',
+ selectAllValue: 'multiselect-all',
+ selectAllName: false,
+ selectAllNumber: true,
+ selectAllJustVisible: true,
+ enableFiltering: false,
+ enableCaseInsensitiveFiltering: false,
+ enableFullValueFiltering: false,
+ enableClickableOptGroups: false,
+ enableCollapsibleOptGroups: false,
+ filterPlaceholder: 'Search',
+ // possible options: 'text', 'value', 'both'
+ filterBehavior: 'text',
+ includeFilterClearBtn: true,
+ preventInputChangeEvent: false,
+ nonSelectedText: 'None selected',
+ nSelectedText: 'selected',
+ allSelectedText: 'All selected',
+ numberDisplayed: 3,
+ disableIfEmpty: false,
+ disabledText: '',
+ delimiterText: ', ',
+ templates: {
+ button: '<button type="button" class="multiselect dropdown-toggle" data-toggle="dropdown"><span class="multiselect-selected-text"></span> <b class="caret"></b></button>',
+ ul: '<ul class="multiselect-container dropdown-menu"></ul>',
+ filter: '<li class="multiselect-item multiselect-filter"><div class="input-group"><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span><input class="form-control multiselect-search" type="text"></div></li>',
+ filterClearBtn: '<span class="input-group-btn"><button class="btn btn-default multiselect-clear-filter" type="button"><i class="glyphicon glyphicon-remove-circle"></i></button></span>',
+ li: '<li><a tabindex="0"><label></label></a></li>',
+ divider: '<li class="multiselect-item divider"></li>',
+ liGroup: '<li class="multiselect-item multiselect-group"><label></label></li>'
+ }
+ },
+
+ constructor: Multiselect,
+
+ /**
+ * Builds the container of the multiselect.
+ */
+ buildContainer: function() {
+ this.$container = $(this.options.buttonContainer);
+ this.$container.on('show.bs.dropdown', this.options.onDropdownShow);
+ this.$container.on('hide.bs.dropdown', this.options.onDropdownHide);
+ this.$container.on('shown.bs.dropdown', this.options.onDropdownShown);
+ this.$container.on('hidden.bs.dropdown', this.options.onDropdownHidden);
+ },
+
+ /**
+ * Builds the button of the multiselect.
+ */
+ buildButton: function() {
+ this.$button = $(this.options.templates.button).addClass(this.options.buttonClass);
+ if (this.$select.attr('class') && this.options.inheritClass) {
+ this.$button.addClass(this.$select.attr('class'));
+ }
+ // Adopt active state.
+ if (this.$select.prop('disabled')) {
+ this.disable();
+ }
+ else {
+ this.enable();
+ }
+
+ // Manually add button width if set.
+ if (this.options.buttonWidth && this.options.buttonWidth !== 'auto') {
+ this.$button.css({
+ 'width' : '100%', //this.options.buttonWidth,
+ 'overflow' : 'hidden',
+ 'text-overflow' : 'ellipsis'
+ });
+ this.$container.css({
+ 'width': this.options.buttonWidth
+ });
+ }
+
+ // Keep the tab index from the select.
+ var tabindex = this.$select.attr('tabindex');
+ if (tabindex) {
+ this.$button.attr('tabindex', tabindex);
+ }
+
+ this.$container.prepend(this.$button);
+ },
+
+ /**
+ * Builds the ul representing the dropdown menu.
+ */
+ buildDropdown: function() {
+
+ // Build ul.
+ this.$ul = $(this.options.templates.ul);
+
+ if (this.options.dropRight) {
+ this.$ul.addClass('pull-right');
+ }
+
+ // Set max height of dropdown menu to activate auto scrollbar.
+ if (this.options.maxHeight) {
+ // TODO: Add a class for this option to move the css declarations.
+ this.$ul.css({
+ 'max-height': this.options.maxHeight + 'px',
+ 'overflow-y': 'auto',
+ 'overflow-x': 'hidden'
+ });
+ }
+
+ if (this.options.dropUp) {
+
+ var height = Math.min(this.options.maxHeight, $('option[data-role!="divider"]', this.$select).length*26 + $('option[data-role="divider"]', this.$select).length*19 + (this.options.includeSelectAllOption ? 26 : 0) + (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering ? 44 : 0));
+ var moveCalc = height + 34;
+
+ this.$ul.css({
+ 'max-height': height + 'px',
+ 'overflow-y': 'auto',
+ 'overflow-x': 'hidden',
+ 'margin-top': "-" + moveCalc + 'px'
+ });
+ }
+
+ this.$container.append(this.$ul);
+ },
+
+ /**
+ * Build the dropdown options and binds all necessary events.
+ *
+ * Uses createDivider and createOptionValue to create the necessary options.
+ */
+ buildDropdownOptions: function() {
+
+ this.$select.children().each($.proxy(function(index, element) {
+
+ var $element = $(element);
+ // Support optgroups and options without a group simultaneously.
+ var tag = $element.prop('tagName')
+ .toLowerCase();
+
+ if ($element.prop('value') === this.options.selectAllValue) {
+ return;
+ }
+
+ if (tag === 'optgroup') {
+ this.createOptgroup(element);
+ }
+ else if (tag === 'option') {
+
+ if ($element.data('role') === 'divider') {
+ this.createDivider();
+ }
+ else {
+ this.createOptionValue(element);
+ }
+
+ }
+
+ // Other illegal tags will be ignored.
+ }, this));
+
+ // Bind the change event on the dropdown elements.
+ $('li:not(.multiselect-group) input', this.$ul).on('change', $.proxy(function(event) {
+ var $target = $(event.target);
+
+ var checked = $target.prop('checked') || false;
+ var isSelectAllOption = $target.val() === this.options.selectAllValue;
+
+ // Apply or unapply the configured selected class.
+ if (this.options.selectedClass) {
+ if (checked) {
+ $target.closest('li')
+ .addClass(this.options.selectedClass);
+ }
+ else {
+ $target.closest('li')
+ .removeClass(this.options.selectedClass);
+ }
+ }
+
+ // Get the corresponding option.
+ var value = $target.val();
+ var $option = this.getOptionByValue(value);
+
+ var $optionsNotThis = $('option', this.$select).not($option);
+ var $checkboxesNotThis = $('input', this.$container).not($target);
+
+ if (isSelectAllOption) {
+
+ if (checked) {
+ this.selectAll(this.options.selectAllJustVisible, true);
+ }
+ else {
+ this.deselectAll(this.options.selectAllJustVisible, true);
+ }
+ }
+ else {
+ if (checked) {
+ $option.prop('selected', true);
+
+ if (this.options.multiple) {
+ // Simply select additional option.
+ $option.prop('selected', true);
+ }
+ else {
+ // Unselect all other options and corresponding checkboxes.
+ if (this.options.selectedClass) {
+ $($checkboxesNotThis).closest('li').removeClass(this.options.selectedClass);
+ }
+
+ $($checkboxesNotThis).prop('checked', false);
+ $optionsNotThis.prop('selected', false);
+
+ // It's a single selection, so close.
+ this.$button.click();
+ }
+
+ if (this.options.selectedClass === "active") {
+ $optionsNotThis.closest("a").css("outline", "");
+ }
+ }
+ else {
+ // Unselect option.
+ $option.prop('selected', false);
+ }
+
+ // To prevent select all from firing onChange: #575
+ this.options.onChange($option, checked);
+
+ // Do not update select all or optgroups on select all change!
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+ }
+
+ this.$select.change();
+ this.updateButtonText();
+
+ if(this.options.preventInputChangeEvent) {
+ return false;
+ }
+ }, this));
+
+ $('li a', this.$ul).on('mousedown', function(e) {
+ if (e.shiftKey) {
+ // Prevent selecting text by Shift+click
+ return false;
+ }
+ });
+
+ $('li a', this.$ul).on('touchstart click', $.proxy(function(event) {
+ event.stopPropagation();
+
+ var $target = $(event.target);
+
+ if (event.shiftKey && this.options.multiple) {
+ if($target.is("label")){ // Handles checkbox selection manually (see https://github.com/davidstutz/bootstrap-multiselect/issues/431)
+ event.preventDefault();
+ $target = $target.find("input");
+ $target.prop("checked", !$target.prop("checked"));
+ }
+ var checked = $target.prop('checked') || false;
+
+ if (this.lastToggledInput !== null && this.lastToggledInput !== $target) { // Make sure we actually have a range
+ var from = $target.closest("li").index();
+ var to = this.lastToggledInput.closest("li").index();
+
+ if (from > to) { // Swap the indices
+ var tmp = to;
+ to = from;
+ from = tmp;
+ }
+
+ // Make sure we grab all elements since slice excludes the last index
+ ++to;
+
+ // Change the checkboxes and underlying options
+ var range = this.$ul.find("li").slice(from, to).find("input");
+
+ range.prop('checked', checked);
+
+ if (this.options.selectedClass) {
+ range.closest('li')
+ .toggleClass(this.options.selectedClass, checked);
+ }
+
+ for (var i = 0, j = range.length; i < j; i++) {
+ var $checkbox = $(range[i]);
+
+ var $option = this.getOptionByValue($checkbox.val());
+
+ $option.prop('selected', checked);
+ }
+ }
+
+ // Trigger the select "change" event
+ $target.trigger("change");
+ }
+
+ // Remembers last clicked option
+ if($target.is("input") && !$target.closest("li").is(".multiselect-item")){
+ this.lastToggledInput = $target;
+ }
+
+ $target.blur();
+ }, this));
+
+ // Keyboard support.
+ this.$container.off('keydown.multiselect').on('keydown.multiselect', $.proxy(function(event) {
+ if ($('input[type="text"]', this.$container).is(':focus')) {
+ return;
+ }
+
+ if (event.keyCode === 9 && this.$container.hasClass('open')) {
+ this.$button.click();
+ }
+ else {
+ var $items = $(this.$container).find("li:not(.divider):not(.disabled) a").filter(":visible");
+
+ if (!$items.length) {
+ return;
+ }
+
+ var index = $items.index($items.filter(':focus'));
+
+ // Navigation up.
+ if (event.keyCode === 38 && index > 0) {
+ index--;
+ }
+ // Navigate down.
+ else if (event.keyCode === 40 && index < $items.length - 1) {
+ index++;
+ }
+ else if (!~index) {
+ index = 0;
+ }
+
+ var $current = $items.eq(index);
+ $current.focus();
+
+ if (event.keyCode === 32 || event.keyCode === 13) {
+ var $checkbox = $current.find('input');
+
+ $checkbox.prop("checked", !$checkbox.prop("checked"));
+ $checkbox.change();
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }, this));
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ $("li.multiselect-group input", this.$ul).on("change", $.proxy(function(event) {
+ event.stopPropagation();
+
+ var $target = $(event.target);
+ var checked = $target.prop('checked') || false;
+
+ var $li = $(event.target).closest('li');
+ var $group = $li.nextUntil("li.multiselect-group")
+ .not('.multiselect-filter-hidden')
+ .not('.disabled');
+
+ var $inputs = $group.find("input");
+
+ var values = [];
+ var $options = [];
+
+ if (this.options.selectedClass) {
+ if (checked) {
+ $li.addClass(this.options.selectedClass);
+ }
+ else {
+ $li.removeClass(this.options.selectedClass);
+ }
+ }
+
+ $.each($inputs, $.proxy(function(index, input) {
+ var value = $(input).val();
+ var $option = this.getOptionByValue(value);
+
+ if (checked) {
+ $(input).prop('checked', true);
+ $(input).closest('li')
+ .addClass(this.options.selectedClass);
+
+ $option.prop('selected', true);
+ }
+ else {
+ $(input).prop('checked', false);
+ $(input).closest('li')
+ .removeClass(this.options.selectedClass);
+
+ $option.prop('selected', false);
+ }
+
+ $options.push(this.getOptionByValue(value));
+ }, this))
+
+ // Cannot use select or deselect here because it would call updateOptGroups again.
+
+ this.options.onChange($options, checked);
+
+ this.updateButtonText();
+ this.updateSelectAll();
+ }, this));
+ }
+
+ if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
+ $("li.multiselect-group .caret-container", this.$ul).on("click", $.proxy(function(event) {
+ var $li = $(event.target).closest('li');
+ var $inputs = $li.nextUntil("li.multiselect-group")
+ .not('.multiselect-filter-hidden');
+
+ var visible = true;
+ $inputs.each(function() {
+ visible = visible && $(this).is(':visible');
+ });
+
+ if (visible) {
+ $inputs.hide()
+ .addClass('multiselect-collapsible-hidden');
+ }
+ else {
+ $inputs.show()
+ .removeClass('multiselect-collapsible-hidden');
+ }
+ }, this));
+
+ $("li.multiselect-all", this.$ul).css('background', '#f3f3f3').css('border-bottom', '1px solid #eaeaea');
+ $("li.multiselect-all > a > label.checkbox", this.$ul).css('padding', '3px 20px 3px 35px');
+ $("li.multiselect-group > a > input", this.$ul).css('margin', '4px 0px 5px -20px');
+ }
+ },
+
+ /**
+ * Create an option using the given select option.
+ *
+ * @param {jQuery} element
+ */
+ createOptionValue: function(element) {
+ var $element = $(element);
+ if ($element.is(':selected')) {
+ $element.prop('selected', true);
+ }
+
+ // Support the label attribute on options.
+ var label = this.options.optionLabel(element);
+ var classes = this.options.optionClass(element);
+ var value = $element.val();
+ var inputType = this.options.multiple ? "checkbox" : "radio";
+
+ var $li = $(this.options.templates.li);
+ var $label = $('label', $li);
+ $label.addClass(inputType);
+ $li.addClass(classes);
+
+ if (this.options.enableHTML) {
+ $label.html(" " + label);
+ }
+ else {
+ $label.text(" " + label);
+ }
+
+ var $checkbox = $('<input/>').attr('type', inputType);
+
+ var name = this.options.checkboxName($element);
+ if (name) {
+ $checkbox.attr('name', name);
+ }
+
+ $label.prepend($checkbox);
+
+ var selected = $element.prop('selected') || false;
+ $checkbox.val(value);
+
+ if (value === this.options.selectAllValue) {
+ $li.addClass("multiselect-item multiselect-all");
+ $checkbox.parent().parent()
+ .addClass('multiselect-all');
+ }
+
+ $label.attr('title', $element.attr('title'));
+
+ this.$ul.append($li);
+
+ if ($element.is(':disabled')) {
+ $checkbox.attr('disabled', 'disabled')
+ .prop('disabled', true)
+ .closest('a')
+ .attr("tabindex", "-1")
+ .closest('li')
+ .addClass('disabled');
+ }
+
+ $checkbox.prop('checked', selected);
+
+ if (selected && this.options.selectedClass) {
+ $checkbox.closest('li')
+ .addClass(this.options.selectedClass);
+ }
+ },
+
+ /**
+ * Creates a divider using the given select option.
+ *
+ * @param {jQuery} element
+ */
+ createDivider: function(element) {
+ var $divider = $(this.options.templates.divider);
+ this.$ul.append($divider);
+ },
+
+ /**
+ * Creates an optgroup.
+ *
+ * @param {jQuery} group
+ */
+ createOptgroup: function(group) {
+ var label = $(group).attr("label");
+ var value = $(group).attr("value");
+ var $li = $('<li class="multiselect-item multiselect-group"><a href="javascript:void(0);"><label><b></b></label></a></li>');
+
+ var classes = this.options.optionClass(group);
+ $li.addClass(classes);
+
+ if (this.options.enableHTML) {
+ $('label b', $li).html(" " + label);
+ }
+ else {
+ $('label b', $li).text(" " + label);
+ }
+
+ if (this.options.enableCollapsibleOptGroups && this.options.multiple) {
+ $('a', $li).append('<span class="caret-container"><b class="caret"></b></span>');
+ }
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ $('a label', $li).prepend('<input type="checkbox" value="' + value + '"/>');
+ }
+
+ if ($(group).is(':disabled')) {
+ $li.addClass('disabled');
+ }
+
+ this.$ul.append($li);
+
+ $("option", group).each($.proxy(function($, group) {
+ this.createOptionValue(group);
+ }, this))
+ },
+
+ /**
+ * Build the select all.
+ *
+ * Checks if a select all has already been created.
+ */
+ buildSelectAll: function() {
+ if (typeof this.options.selectAllValue === 'number') {
+ this.options.selectAllValue = this.options.selectAllValue.toString();
+ }
+
+ var alreadyHasSelectAll = this.hasSelectAll();
+
+ if (!alreadyHasSelectAll && this.options.includeSelectAllOption && this.options.multiple
+ && $('option', this.$select).length > this.options.includeSelectAllIfMoreThan) {
+
+ // Check whether to add a divider after the select all.
+ if (this.options.includeSelectAllDivider) {
+ this.$ul.prepend($(this.options.templates.divider));
+ }
+
+ var $li = $(this.options.templates.li);
+ $('label', $li).addClass("checkbox");
+
+ if (this.options.enableHTML) {
+ $('label', $li).html(" " + this.options.selectAllText);
+ }
+ else {
+ $('label', $li).text(" " + this.options.selectAllText);
+ }
+
+ if (this.options.selectAllName) {
+ $('label', $li).prepend('<input type="checkbox" name="' + this.options.selectAllName + '" />');
+ }
+ else {
+ $('label', $li).prepend('<input type="checkbox" />');
+ }
+
+ var $checkbox = $('input', $li);
+ $checkbox.val(this.options.selectAllValue);
+
+ $li.addClass("multiselect-item multiselect-all");
+ $checkbox.parent().parent()
+ .addClass('multiselect-all');
+
+ this.$ul.prepend($li);
+
+ $checkbox.prop('checked', false);
+ }
+ },
+
+ /**
+ * Builds the filter.
+ */
+ buildFilter: function() {
+
+ // Build filter if filtering OR case insensitive filtering is enabled and the number of options exceeds (or equals) enableFilterLength.
+ if (this.options.enableFiltering || this.options.enableCaseInsensitiveFiltering) {
+ var enableFilterLength = Math.max(this.options.enableFiltering, this.options.enableCaseInsensitiveFiltering);
+
+ if (this.$select.find('option').length >= enableFilterLength) {
+
+ this.$filter = $(this.options.templates.filter);
+ $('input', this.$filter).attr('placeholder', this.options.filterPlaceholder);
+
+ // Adds optional filter clear button
+ if(this.options.includeFilterClearBtn) {
+ var clearBtn = $(this.options.templates.filterClearBtn);
+ clearBtn.on('click', $.proxy(function(event){
+ clearTimeout(this.searchTimeout);
+
+ this.$filter.find('.multiselect-search').val('');
+ $('li', this.$ul).show().removeClass('multiselect-filter-hidden');
+
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ }, this));
+ this.$filter.find('.input-group').append(clearBtn);
+ }
+
+ this.$ul.prepend(this.$filter);
+
+ this.$filter.val(this.query).on('click', function(event) {
+ event.stopPropagation();
+ }).on('input keydown', $.proxy(function(event) {
+ // Cancel enter key default behaviour
+ if (event.which === 13) {
+ event.preventDefault();
+ }
+
+ // This is useful to catch "keydown" events after the browser has updated the control.
+ clearTimeout(this.searchTimeout);
+
+ this.searchTimeout = this.asyncFunction($.proxy(function() {
+
+ if (this.query !== event.target.value) {
+ this.query = event.target.value;
+
+ var currentGroup, currentGroupVisible;
+ $.each($('li', this.$ul), $.proxy(function(index, element) {
+ var value = $('input', element).length > 0 ? $('input', element).val() : "";
+ var text = $('label', element).text();
+
+ var filterCandidate = '';
+ if ((this.options.filterBehavior === 'text')) {
+ filterCandidate = text;
+ }
+ else if ((this.options.filterBehavior === 'value')) {
+ filterCandidate = value;
+ }
+ else if (this.options.filterBehavior === 'both') {
+ filterCandidate = text + '\n' + value;
+ }
+
+ if (value !== this.options.selectAllValue && text) {
+
+ // By default lets assume that element is not
+ // interesting for this search.
+ var showElement = false;
+
+ if (this.options.enableCaseInsensitiveFiltering) {
+ filterCandidate = filterCandidate.toLowerCase();
+ this.query = this.query.toLowerCase();
+ }
+
+ if (this.options.enableFullValueFiltering && this.options.filterBehavior !== 'both') {
+ var valueToMatch = filterCandidate.trim().substring(0, this.query.length);
+ if (this.query.indexOf(valueToMatch) > -1) {
+ showElement = true;
+ }
+ }
+ else if (filterCandidate.indexOf(this.query) > -1) {
+ showElement = true;
+ }
+
+ // Toggle current element (group or group item) according to showElement boolean.
+ $(element).toggle(showElement)
+ .toggleClass('multiselect-filter-hidden', !showElement);
+
+ // Differentiate groups and group items.
+ if ($(element).hasClass('multiselect-group')) {
+ // Remember group status.
+ currentGroup = element;
+ currentGroupVisible = showElement;
+ }
+ else {
+ // Show group name when at least one of its items is visible.
+ if (showElement) {
+ $(currentGroup).show()
+ .removeClass('multiselect-filter-hidden');
+ }
+
+ // Show all group items when group name satisfies filter.
+ if (!showElement && currentGroupVisible) {
+ $(element).show()
+ .removeClass('multiselect-filter-hidden');
+ }
+ }
+ }
+ }, this));
+ }
+
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ this.options.onFiltering(event.target);
+
+ }, this), 300, this);
+ }, this));
+ }
+ }
+ },
+
+ /**
+ * Unbinds the whole plugin.
+ */
+ destroy: function() {
+ this.$container.remove();
+ this.$select.show();
+
+ // reset original state
+ this.$select.prop('disabled', this.options.wasDisabled);
+
+ this.$select.data('multiselect', null);
+ },
+
+ /**
+ * Refreshs the multiselect based on the selected options of the select.
+ */
+ refresh: function () {
+ var inputs = $.map($('li input', this.$ul), $);
+
+ $('option', this.$select).each($.proxy(function (index, element) {
+ var $elem = $(element);
+ var value = $elem.val();
+ var $input;
+ for (var i = inputs.length; 0 < i--; /**/) {
+ if (value !== ($input = inputs[i]).val())
+ continue; // wrong li
+
+ if ($elem.is(':selected')) {
+ $input.prop('checked', true);
+
+ if (this.options.selectedClass) {
+ $input.closest('li')
+ .addClass(this.options.selectedClass);
+ }
+ }
+ else {
+ $input.prop('checked', false);
+
+ if (this.options.selectedClass) {
+ $input.closest('li')
+ .removeClass(this.options.selectedClass);
+ }
+ }
+
+ if ($elem.is(":disabled")) {
+ $input.attr('disabled', 'disabled')
+ .prop('disabled', true)
+ .closest('li')
+ .addClass('disabled');
+ }
+ else {
+ $input.prop('disabled', false)
+ .closest('li')
+ .removeClass('disabled');
+ }
+ break; // assumes unique values
+ }
+ }, this));
+
+ this.updateButtonText();
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+ },
+
+ /**
+ * Select all options of the given values.
+ *
+ * If triggerOnChange is set to true, the on change event is triggered if
+ * and only if one value is passed.
+ *
+ * @param {Array} selectValues
+ * @param {Boolean} triggerOnChange
+ */
+ select: function(selectValues, triggerOnChange) {
+ if(!$.isArray(selectValues)) {
+ selectValues = [selectValues];
+ }
+
+ for (var i = 0; i < selectValues.length; i++) {
+ var value = selectValues[i];
+
+ if (value === null || value === undefined) {
+ continue;
+ }
+
+ var $option = this.getOptionByValue(value);
+ var $checkbox = this.getInputByValue(value);
+
+ if($option === undefined || $checkbox === undefined) {
+ continue;
+ }
+
+ if (!this.options.multiple) {
+ this.deselectAll(false);
+ }
+
+ if (this.options.selectedClass) {
+ $checkbox.closest('li')
+ .addClass(this.options.selectedClass);
+ }
+
+ $checkbox.prop('checked', true);
+ $option.prop('selected', true);
+
+ if (triggerOnChange) {
+ this.options.onChange($option, true);
+ }
+ }
+
+ this.updateButtonText();
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+ },
+
+ /**
+ * Clears all selected items.
+ */
+ clearSelection: function () {
+ this.deselectAll(false);
+ this.updateButtonText();
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+ },
+
+ /**
+ * Deselects all options of the given values.
+ *
+ * If triggerOnChange is set to true, the on change event is triggered, if
+ * and only if one value is passed.
+ *
+ * @param {Array} deselectValues
+ * @param {Boolean} triggerOnChange
+ */
+ deselect: function(deselectValues, triggerOnChange) {
+ if(!$.isArray(deselectValues)) {
+ deselectValues = [deselectValues];
+ }
+
+ for (var i = 0; i < deselectValues.length; i++) {
+ var value = deselectValues[i];
+
+ if (value === null || value === undefined) {
+ continue;
+ }
+
+ var $option = this.getOptionByValue(value);
+ var $checkbox = this.getInputByValue(value);
+
+ if($option === undefined || $checkbox === undefined) {
+ continue;
+ }
+
+ if (this.options.selectedClass) {
+ $checkbox.closest('li')
+ .removeClass(this.options.selectedClass);
+ }
+
+ $checkbox.prop('checked', false);
+ $option.prop('selected', false);
+
+ if (triggerOnChange) {
+ this.options.onChange($option, false);
+ }
+ }
+
+ this.updateButtonText();
+ this.updateSelectAll();
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+ },
+
+ /**
+ * Selects all enabled & visible options.
+ *
+ * If justVisible is true or not specified, only visible options are selected.
+ *
+ * @param {Boolean} justVisible
+ * @param {Boolean} triggerOnSelectAll
+ */
+ selectAll: function (justVisible, triggerOnSelectAll) {
+
+ var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
+ var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
+ var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');
+
+ if(justVisible) {
+ $('input:enabled' , visibleLis).prop('checked', true);
+ visibleLis.addClass(this.options.selectedClass);
+
+ $('input:enabled' , visibleLis).each($.proxy(function(index, element) {
+ var value = $(element).val();
+ var option = this.getOptionByValue(value);
+ $(option).prop('selected', true);
+ }, this));
+ }
+ else {
+ $('input:enabled' , allLis).prop('checked', true);
+ allLis.addClass(this.options.selectedClass);
+
+ $('input:enabled' , allLis).each($.proxy(function(index, element) {
+ var value = $(element).val();
+ var option = this.getOptionByValue(value);
+ $(option).prop('selected', true);
+ }, this));
+ }
+
+ $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', true);
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ if (triggerOnSelectAll) {
+ this.options.onSelectAll();
+ }
+ },
+
+ /**
+ * Deselects all options.
+ *
+ * If justVisible is true or not specified, only visible options are deselected.
+ *
+ * @param {Boolean} justVisible
+ */
+ deselectAll: function (justVisible, triggerOnDeselectAll) {
+
+ var justVisible = typeof justVisible === 'undefined' ? true : justVisible;
+ var allLis = $("li:not(.divider):not(.disabled):not(.multiselect-group)", this.$ul);
+ var visibleLis = $("li:not(.divider):not(.disabled):not(.multiselect-group):not(.multiselect-filter-hidden):not(.multiselect-collapisble-hidden)", this.$ul).filter(':visible');
+
+ if(justVisible) {
+ $('input[type="checkbox"]:enabled' , visibleLis).prop('checked', false);
+ visibleLis.removeClass(this.options.selectedClass);
+
+ $('input[type="checkbox"]:enabled' , visibleLis).each($.proxy(function(index, element) {
+ var value = $(element).val();
+ var option = this.getOptionByValue(value);
+ $(option).prop('selected', false);
+ }, this));
+ }
+ else {
+ $('input[type="checkbox"]:enabled' , allLis).prop('checked', false);
+ allLis.removeClass(this.options.selectedClass);
+
+ $('input[type="checkbox"]:enabled' , allLis).each($.proxy(function(index, element) {
+ var value = $(element).val();
+ var option = this.getOptionByValue(value);
+ $(option).prop('selected', false);
+ }, this));
+ }
+
+ $('li input[value="' + this.options.selectAllValue + '"]', this.$ul).prop('checked', false);
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ if (triggerOnDeselectAll) {
+ this.options.onDeselectAll();
+ }
+ },
+
+ /**
+ * Rebuild the plugin.
+ *
+ * Rebuilds the dropdown, the filter and the select all option.
+ */
+ rebuild: function() {
+ this.$ul.html('');
+
+ // Important to distinguish between radios and checkboxes.
+ this.options.multiple = this.$select.attr('multiple') === "multiple";
+
+ this.buildSelectAll();
+ this.buildDropdownOptions();
+ this.buildFilter();
+
+ this.updateButtonText();
+ this.updateSelectAll(true);
+
+ if (this.options.enableClickableOptGroups && this.options.multiple) {
+ this.updateOptGroups();
+ }
+
+ if (this.options.disableIfEmpty && $('option', this.$select).length <= 0) {
+ this.disable();
+ }
+ else {
+ this.enable();
+ }
+
+ if (this.options.dropRight) {
+ this.$ul.addClass('pull-right');
+ }
+ },
+
+ /**
+ * The provided data will be used to build the dropdown.
+ */
+ dataprovider: function(dataprovider) {
+
+ var groupCounter = 0;
+ var $select = this.$select.empty();
+
+ $.each(dataprovider, function (index, option) {
+ var $tag;
+
+ if ($.isArray(option.children)) { // create optiongroup tag
+ groupCounter++;
+
+ $tag = $('<optgroup/>').attr({
+ label: option.label || 'Group ' + groupCounter,
+ disabled: !!option.disabled
+ });
+
+ forEach(option.children, function(subOption) { // add children option tags
+ var attributes = {
+ value: subOption.value,
+ label: subOption.label || subOption.value,
+ title: subOption.title,
+ selected: !!subOption.selected,
+ disabled: !!subOption.disabled
+ };
+
+ //Loop through attributes object and add key-value for each attribute
+ for (var key in subOption.attributes) {
+ attributes['data-' + key] = subOption.attributes[key];
+ }
+ //Append original attributes + new data attributes to option
+ $tag.append($('<option/>').attr(attributes));
+ });
+ }
+ else {
+
+ var attributes = {
+ 'value': option.value,
+ 'label': option.label || option.value,
+ 'title': option.title,
+ 'class': option.class,
+ 'selected': !!option.selected,
+ 'disabled': !!option.disabled
+ };
+ //Loop through attributes object and add key-value for each attribute
+ for (var key in option.attributes) {
+ attributes['data-' + key] = option.attributes[key];
+ }
+ //Append original attributes + new data attributes to option
+ $tag = $('<option/>').attr(attributes);
+
+ $tag.text(option.label || option.value);
+ }
+
+ $select.append($tag);
+ });
+
+ this.rebuild();
+ },
+
+ /**
+ * Enable the multiselect.
+ */
+ enable: function() {
+ this.$select.prop('disabled', false);
+ this.$button.prop('disabled', false)
+ .removeClass('disabled');
+ },
+
+ /**
+ * Disable the multiselect.
+ */
+ disable: function() {
+ this.$select.prop('disabled', true);
+ this.$button.prop('disabled', true)
+ .addClass('disabled');
+ },
+
+ /**
+ * Set the options.
+ *
+ * @param {Array} options
+ */
+ setOptions: function(options) {
+ this.options = this.mergeOptions(options);
+ },
+
+ /**
+ * Merges the given options with the default options.
+ *
+ * @param {Array} options
+ * @returns {Array}
+ */
+ mergeOptions: function(options) {
+ return $.extend(true, {}, this.defaults, this.options, options);
+ },
+
+ /**
+ * Checks whether a select all checkbox is present.
+ *
+ * @returns {Boolean}
+ */
+ hasSelectAll: function() {
+ return $('li.multiselect-all', this.$ul).length > 0;
+ },
+
+ /**
+ * Update opt groups.
+ */
+ updateOptGroups: function() {
+ var $groups = $('li.multiselect-group', this.$ul)
+ var selectedClass = this.options.selectedClass;
+
+ $groups.each(function() {
+ var $options = $(this).nextUntil('li.multiselect-group')
+ .not('.multiselect-filter-hidden')
+ .not('.disabled');
+
+ var checked = true;
+ $options.each(function() {
+ var $input = $('input', this);
+
+ if (!$input.prop('checked')) {
+ checked = false;
+ }
+ });
+
+ if (selectedClass) {
+ if (checked) {
+ $(this).addClass(selectedClass);
+ }
+ else {
+ $(this).removeClass(selectedClass);
+ }
+ }
+
+ $('input', this).prop('checked', checked);
+ });
+ },
+
+ /**
+ * Updates the select all checkbox based on the currently displayed and selected checkboxes.
+ */
+ updateSelectAll: function(notTriggerOnSelectAll) {
+ if (this.hasSelectAll()) {
+ var allBoxes = $("li:not(.multiselect-item):not(.multiselect-filter-hidden):not(.multiselect-group):not(.disabled) input:enabled", this.$ul);
+ var allBoxesLength = allBoxes.length;
+ var checkedBoxesLength = allBoxes.filter(":checked").length;
+ var selectAllLi = $("li.multiselect-all", this.$ul);
+ var selectAllInput = selectAllLi.find("input");
+
+ if (checkedBoxesLength > 0 && checkedBoxesLength === allBoxesLength) {
+ selectAllInput.prop("checked", true);
+ selectAllLi.addClass(this.options.selectedClass);
+ }
+ else {
+ selectAllInput.prop("checked", false);
+ selectAllLi.removeClass(this.options.selectedClass);
+ }
+ }
+ },
+
+ /**
+ * Update the button text and its title based on the currently selected options.
+ */
+ updateButtonText: function() {
+ var options = this.getSelected();
+
+ // First update the displayed button text.
+ if (this.options.enableHTML) {
+ $('.multiselect .multiselect-selected-text', this.$container).html(this.options.buttonText(options, this.$select));
+ }
+ else {
+ $('.multiselect .multiselect-selected-text', this.$container).text(this.options.buttonText(options, this.$select));
+ }
+
+ // Now update the title attribute of the button.
+ $('.multiselect', this.$container).attr('title', this.options.buttonTitle(options, this.$select));
+ },
+
+ /**
+ * Get all selected options.
+ *
+ * @returns {jQUery}
+ */
+ getSelected: function() {
+ return $('option', this.$select).filter(":selected");
+ },
+
+ /**
+ * Gets a select option by its value.
+ *
+ * @param {String} value
+ * @returns {jQuery}
+ */
+ getOptionByValue: function (value) {
+
+ var options = $('option', this.$select);
+ var valueToCompare = value.toString();
+
+ for (var i = 0; i < options.length; i = i + 1) {
+ var option = options[i];
+ if (option.value === valueToCompare) {
+ return $(option);
+ }
+ }
+ },
+
+ /**
+ * Get the input (radio/checkbox) by its value.
+ *
+ * @param {String} value
+ * @returns {jQuery}
+ */
+ getInputByValue: function (value) {
+
+ var checkboxes = $('li input:not(.multiselect-search)', this.$ul);
+ var valueToCompare = value.toString();
+
+ for (var i = 0; i < checkboxes.length; i = i + 1) {
+ var checkbox = checkboxes[i];
+ if (checkbox.value === valueToCompare) {
+ return $(checkbox);
+ }
+ }
+ },
+
+ /**
+ * Used for knockout integration.
+ */
+ updateOriginalOptions: function() {
+ this.originalOptions = this.$select.clone()[0].options;
+ },
+
+ asyncFunction: function(callback, timeout, self) {
+ var args = Array.prototype.slice.call(arguments, 3);
+ return setTimeout(function() {
+ callback.apply(self || window, args);
+ }, timeout);
+ },
+
+ setAllSelectedText: function(allSelectedText) {
+ this.options.allSelectedText = allSelectedText;
+ this.updateButtonText();
+ }
+ };
+
+ $.fn.multiselect = function(option, parameter, extraOptions) {
+ return this.each(function() {
+ var data = $(this).data('multiselect');
+ var options = typeof option === 'object' && option;
+
+ // Initialize the multiselect.
+ if (!data) {
+ data = new Multiselect(this, options);
+ $(this).data('multiselect', data);
+ }
+
+ // Call multiselect method.
+ if (typeof option === 'string') {
+ data[option](parameter, extraOptions);
+
+ if (option === 'destroy') {
+ $(this).data('multiselect', false);
+ }
+ }
+ });
+ };
+
+ $.fn.multiselect.Constructor = Multiselect;
+
+ $(function() {
+ $("select[data-role=multiselect]").multiselect();
+ });
+
+}(window.jQuery);
diff --git a/src/main/resources/META-INF/resources/designer/partials/menu.html b/src/main/resources/META-INF/resources/designer/partials/menu.html index dd4dae42f..e4f617cc3 100644 --- a/src/main/resources/META-INF/resources/designer/partials/menu.html +++ b/src/main/resources/META-INF/resources/designer/partials/menu.html @@ -132,7 +132,8 @@ <li ng-repeat="section in tabs[dropDownName]" ng-if="section.name==='Create CL'"><a id="{{section.name}}" role="presentation" - ng-click="emptyMenuClick(section.link,section.name)">{{section.name}}</a> + ng-click="emptyMenuClick(section.link,section.name)" + ng-class="{true:'ThisLink', false:''}[!(userInfo['permissionUpdateCl'])]">{{section.name}}</a> </li> <li ng-repeat="section in tabs[dropDownName]" @@ -142,24 +143,35 @@ </li> <li ng-repeat="section in tabs[dropDownName]" - ng-if="section.name==='Create Template'"><a + ng-if="section.name==='Log Out'"><a id="{{section.name}}" role="presentation" ng-click="emptyMenuClick(section.link,section.name)">{{section.name}}</a> </li> <li ng-repeat="section in tabs[dropDownName]" + ng-if="section.name==='Create Template'"><a + id="{{section.name}}" role="presentation" + ng-click="emptyMenuClick(section.link,section.name)" + ng-class="{true:'ThisLink', false:''}[!(userInfo['permissionUpdateTemplate'])]">{{section.name}}</a> + </li> + + <li ng-repeat="section in tabs[dropDownName]" ng-if="section.name==='Open Template'"><a id="{{section.name}}" role="presentation" ng-click="emptyMenuClick(section.link,section.name)">{{section.name}}</a> </li> <li ng-repeat="section in tabs[dropDownName]" - ng-if="section.name != 'Create CL' && section.name != 'Create Template' && section.name != 'Open CL' && section.name != 'Open Template' && section.name != 'ONAP User Guide - Design Overview' && section.name != 'ONAP User Guide - Closed Loop Design' && section.name != 'ONAP User Guide - CLAMP'"><a + ng-if="section.name != 'Create CL' && section.name != 'Create Template' && section.name != 'Open CL' && section.name != 'Open Template' && section.name != 'ECOMP User Guide - Design Overview' && section.name != 'ECOMP User Guide - Closed Loop Design' && section.name != 'ECOMP User Guide - CLAMP' && section.name != 'User Info'"><a id="{{section.name}}" role="presentation" ng-click="emptyMenuClick(section.link,section.name)" class="ThisLink">{{section.name}}</a> </li> - + <li ng-repeat="section in tabs[dropDownName]" + ng-if="section.name==='User Info'"><a + id="{{section.name}}" role="presentation" + ng-click="emptyMenuClick(section.link,section.name)">{{section.name}}</a> + </li> <li ng-repeat="section in tabs[dropDownName]" ng-if="section.name == 'ONAP User Guide - Design Overview' || section.name == 'ONAP User Guide - Closed Loop Design' || section.name == 'ONAP User Guide - CLAMP'"><a id="{{section.name}}" role="presentation" @@ -181,8 +193,7 @@ <li class="dropdown" style="height: inherit"><a class="navbar-brand logo_name" active-link="active" class="dropdown-toggle dropdownTitle" role="button" - data-toggle="dropdown" style="height: inherit;">Hello: - {{loginuser}} </a></li> + data-toggle="dropdown" style="height: inherit;">Hello:{{loginuser}} </a></li> </ul> </div> diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/PolicyWindow_properties.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/PolicyWindow_properties.html index 7adeb1b4a..5e809ae05 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/PolicyWindow_properties.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/PolicyWindow_properties.html @@ -21,6 +21,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property. --> + <style> #deletePolicy{ height:34px; @@ -59,13 +60,7 @@ margin-top: 17px; } -.form-group { -/* height:24px; */ -/* box-sizing:border-box; */ - margin-bottom:20px; -} - -.glyphicon-search{ +.modelSearchBox{ position:absolute; padding: 25px 12px; } @@ -85,14 +80,26 @@ label{ background-color:#f2bfab; } -#pname{ - height:28px; - margin-left:-5px; +.idError{ + color:red; + padding:50px 0px; + text-align:center; + display:none; } .policyPanel{ background-color: #f5f5f5; - padding: 10px 5px; + padding: 15px 5px 0 5px; +} + +.form-group.clearfix{ + display:-webkit-flex; + display: flex; + align-items: center; +} + +label{ + margin-bottom:0px; } #policySearch{ @@ -131,11 +138,6 @@ label{ overflow:auto; } -#timeout{ - height:28px; - margin-left:10px; -} - </style> <script type="text/javascript"> @@ -170,12 +172,12 @@ label{ </div> - <div class="container"> + <div class="modal-body"> <div attribute-test="policywindowpropertiesb" class="modal-body row"> <div class="leftPolicyPanel"> <div class="panel panel-default"> - <i class="glyphicon glyphicon-search"></i> + <i class="glyphicon glyphicon-search modelSearchBox"></i> <input type="text" id="policySearch" onkeyup="searchPolicyList()" placeholder="Search ..."> <div id="policyTableHolder"> @@ -188,17 +190,30 @@ label{ <div style="float:right"> <button type="button" id="deletePolicy" class="btn btn-sm glyphicon glyphicon-trash" disabled></button></span> </div> + <div id="repeatIdError" class="idError">Error: This Policy name is already taken.</div> + <div id="newIdError" class="idError">Error: Please rename your new Policy.</div> + <div id="spaceError" class="idError">Error: Spaces are not allowed in the ID.</div> </div> <div class="panel panel-default col-sm-9 policyPanel" style="display:none;"> <form id="Timeoutform" class="form-horizontal"> <div> <div class="form-group clearfix row"> - <label style="margin-top:5px;" class="col-sm-2">Name</label> - <input type="text" id="pname"; name="pname"; class="col-sm-4"></span> + <label class="col-sm-2">Name</label> + <div class="col-sm-3" style="padding:0px;"> + <input type="text" id="pname" name="pname" maxlength="48" placeholder="Enter Unique Name" class="form-control"> + </div> - <label for="userID" class="col-sm-3" style="margin-top:5px; padding:0px;">Overall Time Limit</label> - <input type="text" class="col-sm-2" id="timeout" name="timeout"> + <label class="col-sm-1">ID</label> + <div class="col-sm-1" style="padding:0px;"> + <input onkeydown="return false;" type="text" id="pid" name="pid" class="form-control" readonly> + </div> + + <label for="userID" class="col-sm-3" style="padding-left:5px;padding-right:10px;">Overall Time Limit</label> + <div class="col-sm-2" style="padding-left:0px;"> + <input type="text" maxlength="10" onkeypress="return isNumberKey(event)" + class="form-control" id="timeout" name="timeout"> + </div> </div> </div> </form> @@ -219,7 +234,7 @@ label{ <form class="saveProps" class="form-horizontal"> <div> <div class="form-group clearfix" > - <label for="recipe" class="col-sm-4 control-label" >Recipe</label> + <label class="col-sm-4 control-label" for="recipe">Recipe</label> <div class="col-sm-8"> <select class="form-control" name="recipe" id="recipe" enableFilter="false"></select> </div> @@ -228,20 +243,21 @@ label{ <label for="maxRetries" class="col-sm-4 control-label"> Max Retries</label> <div class="col-sm-8"> - <input type="number" min="0" class="form-control" id="maxRetries" + <input type="text" maxlength="5" class="form-control" id="maxRetries" + onkeypress="return isNumberKey(event)" name="maxRetries"> </input> </div> </div> - <br /> <div class="form-group clearfix" > <label for="retryTimeLimit" class="col-sm-4 control-label" > Retry Time Limit</label> <div class="col-sm-8"> - <input type="number" min="0" class="form-control" id="retryTimeLimit" + <input type="text" maxlength="5" class="form-control" id="retryTimeLimit" + onkeypress="return isNumberKey(event)" name="retryTimeLimit"></input> </div> </div> - <div hidden class="form-group clearfix"> + <div style="display:none;" class="form-group clearfix"> <label for="_id" class="col-sm-4 control-label"> PolicyID</label> <div class="col-sm-8"> @@ -262,7 +278,7 @@ label{ Parent Policy Conditions</label> <div class="col-sm-8"> <select class="form-control" id="parentPolicyConditions" - name="parentPolicyConditions" multiple size=2></select> + name="parentPolicyConditions" multiple></select> </div> </div> </div> @@ -283,17 +299,18 @@ label{ // css attribute display:none $("#add_one_more").click(function(event) { event.preventDefault(); - add_one_more(); + var num = add_one_more(); setMultiSelect(); }); loadPropertyWindow("policy") // by default, parentPolicyConditions is disabled - $("#parentPolicyConditions").prop('disabled', 'disabled'); + //$("#parentPolicyConditions").prop('disabled', 'disabled'); var parent_policy={} var policy_ids={} var loadingId=false; var allPolicies={}; + var allPolIds=[]; //Grab saved values for dropdowns var obj = elementMap[lastElementSelected]; @@ -301,12 +318,17 @@ label{ if (!($.isEmptyObject(obj))){ allPolicies = jQuery.extend({}, obj); for (var x in allPolicies){ - $("#policyTable").prepend("<tr id='"+x+"'><td>"+x+"</td></tr>"); + $("#policyTable").prepend("<tr><td>"+x+"</td></tr>"); + if (allPolicies[x][1]['value']){ + allPolIds.push(parseInt(allPolicies[x][1]['value'])); + } } } + $("#pname").val(''); //load recipes for a chosen policy function disperseConfig(policyObj, id){ + parent_policy={}; //remove old gui forms for (var i=1; i<($(".formId").length + 1); i++){ $("#go_properties_tab"+i).parent().remove(); @@ -314,7 +336,7 @@ label{ $(".formId").remove(); if (policyObj !== undefined) { - var el = policyObj[id][2]['policyConfigurations'] + var el = policyObj[id][3]['policyConfigurations'] for (var i = 0; i < el.length; i++) { loadingId=true; var num = add_one_more(); @@ -345,17 +367,33 @@ label{ for(k in parent_policy){ $("#formId"+k+" #parentPolicy").val(parent_policy[k]); + if($("#formId"+k+" #parentPolicy").val() ==""){ + $("#formId" +k+ " #parentPolicyConditions").multiselect("disable"); + } else { + $("#formId" +k+ " #parentPolicyConditions").multiselect("enable"); + } // force the change event $("#formId"+k+" #parentPolicy").change(); } - if(policyObj[id][0] && policyObj[id][1]){ - $("#" + policyObj[id][0].name).val(policyObj[id][0].value); - $("#" + policyObj[id][1].name).val(policyObj[id][1].value); + for (headInd in policyObj[id]){ + if (!(policyObj[id][headInd].hasOwnProperty("policyConfigurations"))){ + $("#" + policyObj[id][headInd].name).val(policyObj[id][headInd].value); + } } } setMultiSelect(); + + if (readOnly||readMOnly){ + $('select[multiple] option').each(function() { + var input = $('input[value="' + $(this).val() + '"]'); + input.prop('disabled', true); + input.parent('li').addClass('disabled'); + }); + $('input[value="multiselect-all"]').prop('disabled', true).parent('li').addClass('disabled'); + } + } @@ -379,11 +417,26 @@ label{ } $("#savePropsBtn").click(function(event) { - + $(".idError").hide(); + if ($("#policyTable .highlight td").html() !== $("#pname").val()){ + //repeated name + if ($.inArray($("#pname").val(), Object.keys(allPolicies)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + delete allPolicies[$("#policyTable .highlight td").html()]; + } + } + if ($("#pname").val().trim() == "New_Policy"){ + $("#newIdError").show(); + return; + } + //Saves edits - if ($("#policyTable .highlight").length > 0){ + /* if ($("#policyTable .highlight").length > 0){ saveLastPolicyLocally($("#policyTable .highlight").attr("id")); - } + } */ + startNextItem(); //Removes outdated (deleted) policies by checking against left menu var finalSaveList = {}; @@ -433,7 +486,7 @@ label{ $("#formId" + count).append(form); $(".formId").not($("#formId" + count)).css("display", "none") addCustListen(count) - addTabListen(count) + //addTabListen(count) // This is for when the process is not loading from map but being created if(!loadingId){ var l=makeid() @@ -443,21 +496,26 @@ label{ for(var i=1;i<=greatestIdNum();i++){ if($("#formId"+i).length>0){ - - answers["#formId"+i+" #parentPolicy"]=$("#formId"+i+" #parentPolicy").val() + answers["#formId"+i+" #parentPolicy"]=$("#formId"+i+" #parentPolicy").val(); $("#formId"+i+" #parentPolicy").empty(); + for(k in policy_ids){ - if($("#formId"+i+" #_id").val().toString()!==policy_ids[k] && $(k+" #recipe").val()!==undefined && $(k+" #recipe").val()!==""){ - $("#formId"+i+" #parentPolicy").append("<option value='"+policy_ids[k]+"''> "+$(k+" #recipe").val()+"</option>") + if(($("#formId"+i+" #_id").val()!==policy_ids[k].toString()) && $(k+" #recipe").val()!==undefined && $(k+" #recipe").val()!==""){ + $("#formId"+i+" #parentPolicy").append("<option value='"+policy_ids[k]+"'>"+$(k+" #recipe").val()+"</option>") } } $("#formId"+i+" #parentPolicy").prepend("<option value=''></option>") } } + + $("#formId"+count+" #parentPolicyConditions").multiselect("disable"); + + //re-populate parent policy with chosen options for(k in answers){ $(k).val(answers[k]) } } + return count; } @@ -468,123 +526,35 @@ label{ } $(".formId").remove(); - //Reset header - var ms = new Date().getTime(); - var defPolName = "Policy" + ms; - $("#pname").val(defPolName); + //Reset headers + //$("#pname").val("0"); + $("#pname").val("New_Policy"); $("#timeout").val(defaults_props.policy.timeout); - //FormSpan contains a block of the form that is not being displayed. We will create clones of that and add them to tabs - var form = $($("#formSpan").children()[0]).clone() - var count = 0; - //Each new tab will have the formId class attached to it. This way we can track how many forms we currently have out there and assign listeners to them - if ($(".formId").length > 0) { - var greatest = 0; - var s = $(".formId"); - //for every recipe - for (var i = 0; i < s.length; i++) { - if (parseInt($(s[i]).attr("id").substring(6)) > greatest) { - greatest = parseInt($(s[i]).attr("id").substring(6)) - } - } - count = greatest + 1; - $("#properties_tab").append( - ('<span class="formId" id="formId'+count+'"></span>')); - } else { - count++; - $("#properties_tab").append( - '<span class="formId" id="formId1"></span>'); - } - - //$(form).find("#policyName").val("Recipe "+makid(2)) - //TODO change up how we auto assign policyName. There could be the case where we do this and it will have repeats - //alert($(form).find("#_id").val()) - //policyNameChangeListener(form) - $("#add_one_more") - .parent() - .before( - ' <li class="active"><a id="go_properties_tab'+count+'">Policy</a><button id="tab_close'+count+'" type="button" class="close tab-close-popup" aria-hidden="true" style="margin-top: -30px;margin-right: 5px">×</button></li>'); - $("#formId" + count).append(form); - $(".formId").not($("#formId" + count)).css("display", "none") - addCustListen(count) - addTabListen(count) - // This is for when the process is not loading from map but being created - if(!loadingId){ - var l=makeid() - $(form).find("#_id").val(l) - policy_ids["#formId" + count]=l - var answers={} - - for(var i=1;i<=greatestIdNum();i++){ - if($("#formId"+i).length>0){ - - answers["#formId"+i+" #parentPolicy"]=$("#formId"+i+" #parentPolicy").val() - $("#formId"+i+" #parentPolicy").empty(); - for(k in policy_ids){ - if($("#formId"+i+" #_id").val().toString()!==policy_ids[k] && $(k+" #recipe").val()!==undefined && $(k+" #recipe").val()!==""){ - $("#formId"+i+" #parentPolicy").append("<option value='"+policy_ids[k]+"''> "+$(k+" #recipe").val()+"</option>") - } - } - $("#formId"+i+" #parentPolicy").prepend("<option value=''></option>") - } - } - for(k in answers){ - $(k).val(answers[k]) - } - } - - - - setMultiSelect(); - return defPolName; + $("#add_one_more").click(); } //listener will change the tab name to the recipe - function addTabListen(count){ - $("#formId"+count+" #recipe").on("change",function(){ - if($("#formId"+count+" #recipe").val().toString()!==""){ - $('#go_properties_tab' + count).text($("#formId"+count+" #recipe").val()) - } - else - $('#go_properties_tab' + count).text("Policy"); - - var answers={} - - for(var i=1;i<=greatestIdNum();i++){ - if($("#formId"+i).length>0){ - - answers["#formId"+i+" #parentPolicy"]=$("#formId"+i+" #parentPolicy").val() - $("#formId"+i+" #parentPolicy").empty(); - - for(k in policy_ids){ - if($("#formId"+i+" #_id").val().toString()!==policy_ids[k] && $(k+" #recipe").val()!=='undefined' && $(k+" #recipe").val()!==""){ - $("#formId"+i+" #parentPolicy").append("<option value='"+policy_ids[k]+"''> "+$(k+" #recipe").val()+"</option>") - } - } - $("#formId"+i+" #parentPolicy").prepend("<option value=''></option>") - } - } - for(k in answers){ - $(k).val(answers[k]) - } - }) + function addTabListen(count){ // disable parentPolicyConditions when a parentPolicy is not selected - $("#formId"+count+" #parentPolicy").on("change",function(){ + //don't think this is used.. + /* $("#formId"+count+" #parentPolicy").on("change",function(){ if($("#formId"+count+" #parentPolicy").val().toString()==""){ // deselect all options $("#formId"+count+" #parentPolicyConditions option:selected").prop("selected", false); // disable the select box - $("#formId"+count+" #parentPolicyConditions").prop('disabled', 'disabled'); + $("#formId"+count+" #parentPolicyConditions").multiselect("disable"); + } else { - $("#formId"+count+" #parentPolicyConditions").prop('disabled', false); + $("#formId"+count+" #parentPolicyConditions").multiselect("enable"); + } - }) + }); */ } - - function addCustListen(count) { + function addCustListen(count) { $('#go_properties_tab' + count).click(function(event) { $("#nav_Tabs li").removeClass("active"); $(this).parent().addClass("active"); @@ -599,7 +569,6 @@ label{ $(this).parent().remove(); for(var i=1;i<=greatestIdNum();i++){ if( $("#formId"+i).length>0){ - //alert("fudge") if(i!==count ){ if( $("#formId"+i+" #parentPolicy").val()===$("#formId"+count+" #_id").val().toString()) $("#formId"+i+" #parentPolicy").val("") @@ -612,7 +581,8 @@ label{ }) } - function greatestIdNum(){ + + function greatestIdNum() { var greatest = 0; var s = $(".formId"); for (var i = 0; i < s.length; i++) { @@ -622,57 +592,58 @@ label{ } return greatest; } - + //Generate random id for each policy //Also made sure ids couldnt be repeated - function makeid(num) - { - - var text = ""; - var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - if(num==null) - num=7; - for( var i=0; i < 7; i++ ) - text += possible.charAt(Math.floor(Math.random() * possible.length)); - var hasValue=false; - for(k in policy_ids){ - if(text===policy_ids[k]) - hasValue=true - } - if (hasValue) + function makeid(num) { + + var text = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + if (num == null) + num = 7; + for (var i = 0; i < 7; i++) + text += possible.charAt(Math.floor(Math.random() + * possible.length)); + var hasValue = false; + for (k in policy_ids) { + if (text === policy_ids[k]) + hasValue = true + } + if (hasValue) return makeid(num); else return text } - - var ParentPolicy=function(id,name){ - this.id=id - this.name=name + + var ParentPolicy = function(id, name) { + this.id = id + this.name = name } - + //Policy table search filter function searchPolicyList() { var search = document.getElementById("policySearch"); var row = document.getElementsByTagName("td"); - for (var i=0; i<row.length; i++){ - if (row[i].innerHTML.toUpperCase().indexOf(search.value.toUpperCase()) > -1){ + for (var i = 0; i < row.length; i++) { + if (row[i].innerHTML.toUpperCase().indexOf( + search.value.toUpperCase()) > -1) { row[i].style.display = ""; } else { row[i].style.display = "none"; } } } - - function saveLastPolicyLocally(lastPolicyId){ + + function saveLastPolicyLocally(lastPolicyId) { var polForm = [] - - var properties = $(".saveProps").not("#formSpan .saveProps") + + var properties = $(".saveProps").not("#formSpan .saveProps"); var timeoutForm = $("#Timeoutform").serializeArray(); - - for (var i=0; i<timeoutForm.length; i++){ + + for (var i = 0; i < timeoutForm.length; i++) { polForm.push(timeoutForm[i]); } - + var d = {} d["policyConfigurations"] = []; for (var i = 0; i < properties.length; i++) { @@ -684,66 +655,179 @@ label{ allPolicies[lastPolicyId] = polForm; } - $("#deletePolicy").on('click', function(){ - var deleteId = $("#policyTable .highlight").attr("id"); - delete allPolicies.deleteId; + function getNextId(){ + var newPolId; + allPolIds.sort(); + if ((Math.min.apply(Math, allPolIds) == 0) + && (allPolIds.length > 0)) { + loop1: + for (var i = 1; i < allPolIds.length; i++) { + if ((allPolIds[i] - allPolIds[i - 1]) != 1) { + newPolId = (allPolIds[i - 1] + 1); + break loop1; + }; + }; + if (!newPolId) { + newPolId = (Math.max.apply(Math, allPolIds)) + 1; + } + } else { + newPolId = 0; + } + allPolIds.push(newPolId); + $("#pid").val(newPolId); + } + + $("#deletePolicy").on('click', function() { + $(".idError").hide(); + //delete policy id + allPolIds.splice((allPolIds.indexOf(parseInt($("#pid").val()))),1); + + //delete policy name + var deleteId = $("#policyTable .highlight td").html(); + delete allPolicies[deleteId]; $("#policyTable .highlight").remove(); + $("#pname").val(''); expandTable(); }); - + $('#policyTable').on('click', 'tr', function(event) { - startNextItem(); - + $(".idError").hide(); + //edited name + if ($("#policyTable .highlight td").html() !== $("#pname").val()){ + //repeated name + if ($.inArray($("#pname").val(), Object.keys(allPolicies)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + $("#repeatIdError").hide(); + delete allPolicies[$("#policyTable .highlight td").html()]; + } + } + //if (parseInt($("#pname").val()) == 0){ + if ($("#pname").val().trim() == "New_Policy"){ + $("#newIdError").show(); + return; + } + if (!(readOnly||readMOnly)){ + startNextItem(); + } else { + if ($("#policyTable .highlight").length == 0){ + collapseTable(); + } + } $(this).addClass('highlight').siblings().removeClass('highlight'); - disperseConfig(allPolicies, $(this).attr("id")); + disperseConfig(allPolicies, $(this).find("td").html()); }); - + $('#createNewPolicy').on('click', function(){ + $(".idError").hide(); + //edited name + if ($("#policyTable .highlight td").html() !== $("#pname").val()){ + //repeated name + if ($.inArray($("#pname").val(), Object.keys(allPolicies)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + $("#repeatIdError").hide(); + delete allPolicies[$("#policyTable .highlight td").html()]; + } + } + //if (parseInt($("#pname").val()) == 0){ + if ($("#pname").val().trim() == "New_Policy"){ + $("#newIdError").show(); + return; + } startNextItem(); - - var defPolName = add_new_policy(); - + add_new_policy(); if (("#policyTable .highlight").length > 0){ $('#policyTable tr.highlight').removeClass('highlight'); } - $("#policyTable").prepend("<tr class='highlight' id='" +defPolName+ "''><td>"+defPolName+"</td></tr>"); + $("#policyTable").prepend("<tr class='highlight'><td>New_Policy</td></tr>"); + + getNextId(); + }); + + $('#pname').on('keypress', function(e){ + /* var newVal = $(this).val() + String.fromCharCode(e.which); + if ((newVal>99) || (($(this).val().length>2) && e.keyCode != 46 && e.keyCode !=8)){ + e.preventDefault(); + } */ + if (e.keyCode == 32){ + $("#spaceError").show(); + e.preventDefault(); + } }); - function startNextItem(){ + function isNumberKey(event){ + var charCode = (event.which) ? event.which : event.keyCode + if (charCode > 31 && (charCode < 48 || charCode > 57)){ + return false; + } + return true; + } + + function startNextItem() { //save last item before transitioning var lastItem = $("#policyTable .highlight"); - if (lastItem.length > 0){ + if (lastItem.length > 0) { saveLastPolicyLocally($("#pname").val()); - - lastItem.attr("id",$("#pname").val()); - $("#"+lastItem.attr("id")+" td").html($("#pname").val()); - } else{ + //lastItem.attr("id", $("#pname").val()); + lastItem.find("td").html($("#pname").val()); + } else { collapseTable(); } - + //allow deleting - if ($("#deletePolicy").prop("disabled")){ + if ($("#deletePolicy").prop("disabled")) { $("#deletePolicy").prop("disabled", false); } } + setASDCFields(); + + //load metrics dropdown + if (elementMap["global"]){ + for (var i = 0; i < (elementMap["global"].length); i++){ + if ((elementMap["global"][i]["name"]) == "actionSet"){ + var asSel = elementMap["global"][i]["value"]; + if (asSel == "vnfRecipe"){ + if (vf_Services["policy"][asSel]){ + $.each((vf_Services["policy"][asSel]), function(val, text) { + $('#recipe').append( + $('<option></option>').val(val).html(text) + ); + }); + } + break; + } else if (asSel == "enbRecipe"){ + if (vf_Services["policy"][asSel]){ + $.each((vf_Services["policy"][asSel]), function(val, text) { + $('#recipe').append( + $('<option></option>').val(val).html(text) + ); + }); + } + break; + } + }; + }; + }; + //Show table panel only - function expandTable(){ - $(".policyPanel").css("display","none"); + function expandTable() { + $(".policyPanel").css("display", "none"); $(".leftPolicyPanel").removeClass("col-sm-3"); - $(".glyphicon-search").css("padding", "25px 12px"); - if (!($("#deletePolicy").prop("disabled"))){ + $(".modelSearchBox").css("padding", "25px 12px"); + if (!($("#deletePolicy").prop("disabled"))) { $("#deletePolicy").prop("disabled", true); } } - + //Show both menus - function collapseTable(){ + function collapseTable() { $(".leftPolicyPanel").addClass("col-sm-3"); - $(".glyphicon-search").css("padding", "10px 12px"); - $(".policyPanel").css("display","unset"); + $(".modelSearchBox").css("padding", "10px 12px"); + $(".policyPanel").css("display", "unset"); } - </script> -</div> - +</div>
\ No newline at end of file diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_create_model_off_Template.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_create_model_off_Template.html index 09aba1354..a4e4607ec 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_create_model_off_Template.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_create_model_off_Template.html @@ -27,63 +27,61 @@ <h4>Model Creation</h4> </div> <div attribute-test="cldsmodelofftemplate" class="modal-body" > - <div style="height: 30px"></div> - <button class="btn btn-primary btn-xs" ng-click="setTypeModel('template')">Template</button> - <button class="btn btn-primary btn-xs" ng-click=" setTypeModel('clone')">Clone</button> - <div ng-show="error.flag">{{error.message}} </div> - <div ng-switch on="typeModel"> - <div ng-switch-when="template"> - <form name="model" class="form-horizontal" novalidate> - <div class="form-group"> - <label for="modelName" class="col-sm-3 control-label">Model Name</label> - <div class="col-sm-8"> - <input type="text" class="form-control" id="modelName" name="modelName" ng-model="modelName" placeholder="Model Name" ng-change="checkExisting();" autofocus="autofocus" ng-pattern="/^\s*[\w\-]*\s*$/" required ng-trim="true"> - <div role="alert"><span ng-show="model.modelName.$error.pattern" style="color: red">Special Characters are not allowed in Model name.</span> <span ng-show="nameinUse" style="color: red"> Model Name Already In Use</span></div> - </div> + + <ul style="margin-bottom:15px;" class="nav nav-tabs"> + <li ng-class="{active : typeModel == 'template'}" ng-click="setTypeModel('template');"><a href="#">Template</a></li> + <li ng-class="{active : typeModel == 'clone'}" ng-click="setTypeModel('clone');"><a href="#">Clone</a></li> + </ul> + <div ng-show="error.flag">{{error.message}} </div> + <div ng-show="(typeModel=='template')"> + <form name="model" class="form-horizontal" novalidate> + <div class="form-group"> + <label for="modelName" class="col-sm-3 control-label">Model Name</label> + <div class="col-sm-8"> + <input type="text" class="form-control" id="modelName" name="modelName" ng-model="modelName" placeholder="Model Name" ng-change="checkExisting();" autofocus="autofocus" ng-pattern="/^\s*[\w\-]*\s*$/" required ng-trim="true"> + <div role="alert"><span ng-show="model.modelName.$error.pattern" style="color: red">Special Characters are not allowed in Model name.</span> <span ng-show="nameinUse" style="color: red"> Model Name Already In Use</span></div> </div> - <div class="form-group"> - <label for="modelName" class="col-sm-3 control-label">Templates</label> - <div class="col-sm-8"> - <select class="form-control" id="templateName" name="templateName" autofocus="autofocus" required ng-trim="true"> - <option ng-repeat="x in templateNamel" value="{{x}}">{{x}}</option> - </select> - </div> + </div> + <div class="form-group"> + <label for="modelName" class="col-sm-3 control-label">Templates</label> + <div class="col-sm-8"> + <select class="form-control" id="templateName" name="templateName" autofocus="autofocus" required ng-trim="true"> + <option ng-repeat="x in templateNamel" value="{{x}}">{{x}}</option> + </select> </div> - </form> - </div> - <div ng-switch-when="clone"> - <form name="model" class="form-horizontal" novalidate> - <div class="form-group"> - <label for="modelName" class="col-sm-3 control-label">Model Name</label> - <div class="col-sm-8"> - <input type="text" class="form-control" id="modelName" name="modelName" ng-model="modelName" placeholder="Model Name" ng-change="checkExisting()" autofocus="autofocus" ng-pattern="/^\s*[\w\-]*\s*$/" required ng-trim="true"> - <div role="alert"><span ng-show="model.modelName.$error.pattern" style="color: red">Special Characters are not allowed in Model name.</span> <span ng-show="nameinUse" style="color: red"> Model Name Already In Use</span></div> - </div> + </div> + </form> + </div> + <div ng-show="(typeModel=='clone')"> + <form name="model" class="form-horizontal" novalidate> + <div class="form-group"> + <label for="modelName" class="col-sm-3 control-label">Model Name</label> + <div class="col-sm-8"> + <input type="text" class="form-control" id="modelName" name="modelName" ng-model="modelName" placeholder="Model Name" ng-change="checkExisting()" autofocus="autofocus" ng-pattern="/^\s*[\w\-]*\s*$/" required ng-trim="true"> + <div role="alert"><span ng-show="model.modelName.$error.pattern" style="color: red">Special Characters are not allowed in Model name.</span> <span ng-show="nameinUse" style="color: red"> Model Name Already In Use</span></div> </div> - <div class="form-group"> - <label for="modelName" class="col-sm-3 control-label">Clone</label> - <div class="col-sm-8"> - <select class="form-control" id="modelList" name="modelList" autofocus="autofocus" required ng-trim="true"> - <option ng-repeat="x in modelNamel" value="{{x}}">{{x}}</option> - </select> - </div> + </div> + <div class="form-group"> + <label for="modelName" class="col-sm-3 control-label">Clone</label> + <div class="col-sm-8"> + <select class="form-control" id="modelList" name="modelList" autofocus="autofocus" required ng-trim="true"> + <option ng-repeat="x in modelNamel" value="{{x}}">{{x}}</option> + </select> </div> - </form> - </div> + </div> + </form> </div> </div> - <div ng-switch on="typeModel"> - <div ng-switch-when="template"> - <div class="modal-footer"> - <button ng-click="createNewModelOffTemplate(model)" class="btn btn-primary" ng-disabled="spcl || nameinUse" class="btn btn-primary">Create</button> - <button ng-click="close(true)" class="btn btn-primary">Cancel</button> - </div> + <div ng-show="(typeModel=='template')"> + <div class="modal-footer"> + <button ng-click="createNewModelOffTemplate(model)" class="btn btn-primary" ng-disabled="spcl || nameinUse" class="btn btn-primary">Create</button> + <button ng-click="close(true)" class="btn btn-primary">Cancel</button> </div> - <div ng-switch-when="clone"> - <div class="modal-footer"> - <button ng-click="cloneModel()" class="btn btn-primary" ng-disabled="model.modelName.$error.pattern || nameinUse" class="btn btn-primary">Clone</button> - <button ng-click="close(true)" class="btn btn-primary">Cancel</button> - </div> + </div> + <div ng-show="(typeModel=='clone')"> + <div class="modal-footer"> + <button ng-click="cloneModel()" class="btn btn-primary" ng-disabled="model.modelName.$error.pattern || nameinUse" class="btn btn-primary">Clone</button> + <button ng-click="close(true)" class="btn btn-primary">Cancel</button> </div> </div> -</div> +</div>
\ No newline at end of file diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_modelling.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_modelling.html index 3f7192e06..aca810c27 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_modelling.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_modelling.html @@ -637,10 +637,14 @@ width: 14px; <div class="panel-heading"> <div style="color: white;"> - <span class="pull-left"> <span id="modeler_name">Closed Loop Modeler</span> - - </span> <span class="pull-right" ng-click="showTDRView=!showTDRView"><i - ng-class="showTDRView == true ?'fa fa-plus-circle':'fa fa-minus-circle'"></i></span> + <span class="pull-left"> + <span id="modeler_name">Closed Loop Modeler</span> + </span> + <span class="pull-right" > + <span id="templa_name"></span> + + <i ng-click="showTDRView=!showTDRView" ng-class="showTDRView == true ?'fa fa-plus-circle':'fa fa-minus-circle'"></i> + </span> </div> <div class="clearfix"></div> diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_model.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_model.html index 7af1d594d..5ebacce88 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_model.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_model.html @@ -31,7 +31,7 @@ <div style="height: 30px"></div> <form name="model" class="form-horizontal"> - <div class="form-group"> + <div class="form-group clearfix"> <label for="modelName" class="col-sm-3 control-label">Model Name</label> <div class="col-sm-8"> <select class="form-control" id="modelName" name="modelName" @@ -41,7 +41,7 @@ <div role="alert"><span ng-show="model.modelName.$error.pattern" style="color: red">Special Characters are not allowed in Model name.</span></div> </div> </div> - <div class="form-group"> + <div class="form-group clearfix"> <label for="modelName" class="col-sm-3 control-label">Read Only</label> <div class="col-sm-8"> <input type="checkbox" class="form-control" id="readOnly" name="readOnly"></input> diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_template.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_template.html index e824a7e02..fceb73692 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_template.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/clds_open_template.html @@ -31,7 +31,7 @@ <div style="height: 30px"></div> <form name="model" class="form-horizontal"> - <div class="form-group"> + <div class="form-group clearfix"> <label for="modelName" class="col-sm-3 control-label">Model Name</label> <div class="col-sm-8"> <select class="form-control" id="modelName" name="modelName" @@ -50,7 +50,7 @@ </div> <script> - /*$.get("/restservices/clds/v1/jaxrsClds/clds/model-names",function(data) { + /*$.get("/restservices/clds/v1/clds/model-names",function(data) { var mySelect = $('#modelName'); mySelect.empty(); mySelect.append("<option value=''>New Diagram</option>") diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/global_properties.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/global_properties.html index e6f20e0fe..755ad7dfd 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/global_properties.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/global_properties.html @@ -21,6 +21,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property. --> + <style> .fileUpload { position: relative; @@ -79,8 +80,9 @@ aria-hidden="true" style="margin-top: -3px">×</button> <h4>Model Properties</h4> </div> + <div class="modal-body" style="height: 280px"> - <div style="height: 10px"></div> + <i hidden id="ridinSpinners" class="fa fa-spinner fa-spin" style="display:none;margin-bottom:10px;width:100%;text-align:center;font-size:24px;color:black;"></i> <form id="saveProps" > <div class="alert alert-danger" role="alert" id='paramsWarn'> <strong>Ooops!</strong> Unable to load properties for <span id='servName'>. Would you like to</span> @@ -94,23 +96,35 @@ <div class="col-sm-8"> <select class="form-control" - name="service" id="service" > + name="service" id="service" onchange="propChangeAlert(this);"> <!-- <option ng-repeat="(key, value) in services" value="{{key}}">{{value}}</option> --> </select> </div> </div> - <div class="form-group"> + <div class="form-group clearfix"> <label for="vf" class="col-sm-4 control-label"> Resource-VF</label> <div class="col-sm-8"> - <select class="form-control" id="vf" name="vf" > + <select class="form-control" id="vf" name="vf" onchange="propChangeAlert(this);"> </select> </div> </div> - <div class="form-group"> + + <div class="form-group clearfix"> + <label for="actionSet" class="col-sm-4 control-label"> + Action Set</label> + + <div class="col-sm-8"> + <select class="form-control" id="actionSet" name="actionSet" onchange="propChangeAlert(this);"> + </select> + + </div> + </div> + + <div class="form-group clearfix"> <label for="location" class="col-sm-4 control-label"> Location</label> @@ -121,15 +135,20 @@ </div> </div> + + + </div> </form> - <i hidden id="ridinSpinners" class="fa fa-spinner fa-spin" style="display:none;width:100%;text-align:center;font-size:24px;color:black;"></i> + <div class="alert alert-warning propChangeWarn" style="display:none;"> + <strong>Warning!</strong> Changing these properties will reset all associated GUI fields. + </div> </div> <div class="modal-footer"> <!--<button ng-click="reset()" class="btn btn-primary" style="float:left">Reset</button>--> - <button id="savePropsBtn" class="btn btn-primary">Close</button> + <button id="savePropsBtn" class="btn btn-primary">Save</button> <button ng-click="close(true)" id="close_button" class="btn btn-primary">Cancel</button> @@ -160,7 +179,7 @@ // $.ajax({ // async:false, // dataType: "json", -// url: '/restservices/clds/v1/jaxrsClds/clds/asdc/services/', +// url: '/restservices/clds/v1/clds/asdc/services/', // success: function(data){ // vf_Services=data; // }, @@ -185,31 +204,52 @@ // $("#" + el[i].name).val(el[i].value); // } // } - - - - - (function () { + + //display message only if global was previously saved + serDiff = false; + vfDiff = false; + asDiff = false; - var previous; + (function () { $("#paramsWarn").hide(); /*Below service method is called for checking the service is being loaded or not*/ - loadSharedPropertyByService(); - - $("#service").on('focus', function () { - // Store the current value on focus and on change - previous = this.value; - - }).change(function(){ - $("#ridinSpinners").css("display","") - var bool=loadSharedPropertyByService($(this).val()) - $("#ridinSpinners").css("display","none") - if(!bool) - $(this).val(previous) - }); + + var intialize = intializeService; + + function intializeService() { + $("#service").off('focus').off('change'); + + $("#service").on('change', function(){ + var chosen = $(this).val(); + (function(spinner){ + $("#ridinSpinners").show(); + setTimeout(spinner, 1); + })(function(){ + loadSharedPropertyByService(chosen, null, intialize); + if (elementMap["global"]){ + if ($("#vf").val() == oldVf){ + vfDiff = false; + if ((!vfDiff)&&(!asDiff)&&(!serDiff)){ + $(".propChangeWarn").hide(); + }; + } else { + vfDiff = true; + $(".propChangeWarn").show(); + } + } + + $("#ridinSpinners").hide(); + }); + }); + + } + + loadSharedPropertyByService(undefined, null, intialize); + intializeService(); + $("#paramsRetry").on('click', function () { //$("#paramsWarn").hide(); - var currentValue = $("#service").val() == null ? previous : $("#service").val(); + var currentValue = $("#service").val(); $("#ridinSpinners").css("display","") var bool=loadSharedPropertyByService(currentValue); $("#ridinSpinners").css("display","none") @@ -219,12 +259,9 @@ $("#paramsWarn").hide(); }); + })(); -// $("#service").on("change",function(){ -// $("#ridinSpinners").css("display","") -// loadSharedPropertyByService($(this).val()) -// $("#ridinSpinners").css("display","none") -// }) + function noRepeats(form){ var select={}; for(var i=0;i<form.length;i++){ @@ -243,14 +280,73 @@ } return arr } + + $(function(){ + if (elementMap["global"]){ + for (var i=0; i< elementMap["global"].length; i++){ + if (elementMap["global"][i]["name"]=="vf"){ + oldVf = elementMap["global"][i]["value"]; + } + } + } else { + oldVf = ""; + } + }); + + function propChangeAlert(actionset){ + //throw warnings only if options were previously chosen + if (elementMap["global"]){ + loop1: + for (var i=0; i< elementMap["global"].length; i++){ + if (elementMap["global"][i]["name"] == actionset.id){ + //user did not change properties + if (elementMap["global"][i]["value"][0] == actionset.value){ + if (elementMap["global"][i]["name"] == "actionSet"){ + asDiff = false; + } else if (elementMap["global"][i]["name"] == "service"){ + serDiff = false; + } else if (elementMap["global"][i]["name"] == "vf"){ + vfDiff = false; + } + if ((!vfDiff)&&(!asDiff)&&(!serDiff)){ + $(".propChangeWarn").hide(); + }; + //user changed properties + } else { + if (elementMap["global"][i]["name"] == "actionSet"){ + asDiff = true; + } else if (elementMap["global"][i]["name"] == "service"){ + serDiff = true; + } else if (elementMap["global"][i]["name"] == "vf"){ + vfDiff = true; + }; + $(".propChangeWarn").show(); + } + break loop1; + } + } + } + } $("#saveProps").on('submit', function(event) { saveGlobalProperties(noRepeats($(this).serializeArray())) event.preventDefault(); + //module reset, based on property updates + if (elementMap["global"]){ + $.each(Object.keys(elementMap), function(i,v){ + if ((v.match(/^Policy/)) && asDiff){ + elementMap[v]={}; + } + if ((v.match(/^TCA/)) && (vfDiff || serDiff)){ + elementMap[v]={}; + } + }); + }; + $("#close_button").click(); - }) + $("#savePropsBtn").click(function(event) { //alert($("#CProp_Target").val()) $("#saveProps").submit(); @@ -259,4 +355,3 @@ </script> </div> - diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/refresh_asdc.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/refresh_asdc.html index 947e41911..c3621f8a8 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/refresh_asdc.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/refresh_asdc.html @@ -111,7 +111,7 @@ // $.ajax({ // async:false, // dataType: "json", -// url: '/services/clds-designer/v1/jaxrsClds/clds/asdc/services/', +// url: '/restservices/clds/v1/clds/asdc/services/', // success: function(data){ // vf_Services=data; // }, diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/stringMatch_properties.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/stringMatch_properties.html index 4b5d22bbe..75491185f 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/stringMatch_properties.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/stringMatch_properties.html @@ -18,10 +18,17 @@ limitations under the License. ============LICENSE_END============================================ =================================================================== - ECOMP is a trademark and service mark of AT&T Intellectual Property. + ECOMP is a trademark and service mark of AT&T Intellectual Property. --> - <style> +#deleteStringMatch{ + height:34px; + background-color:#dddd; +} + +.disabled{ + background-color: #dddd; +} .fileUpload { position: relative; overflow: hidden; @@ -52,19 +59,88 @@ } .form-group { - /* height:24px; */ - /* box-sizing:border-box; */ - margin-bottom: 20px; - +/* height:24px; */ +/* box-sizing:border-box; */ + margin-bottom:20px; +} + +.modelSearchBox{ + position:absolute; + padding: 25px 12px; +} + +label{ + text-align:right; + vertical-align:middle; +} + +.leftStringMatchPanel{ + padding: 0 10px 0 0; +} + +#createNewStringMatch{ + height:34px; + width:120px; /*84*/ + background-color:#f2bfab; } - #paramsWarn { - display: none; + +.idError{ + color:red; + padding:50px 0px; + text-align:center; + display:none; } -label{text-align:right; - padding-top:8px; - } +#rgname{ + height:28px; + margin-left:-5px; +} +.stringMatchPanel{ + background-color: #f5f5f5; + padding: 10px 5px; +} + +#stringMatchSearch{ + height: 33px; + font-size: 12px; + padding: 2px 2px 2px 30px; + margin-bottom: 5px; + width:100%; +} +#stringMatchTable{ + cursor: pointer; + width:100%; +} + +#stringMatchTable tr{ + border-bottom: 1px solid #ddd; + border-collapse: collapse; + text-align: left; + font-size: 12px; + font-weight: normal; +} + +#stringMatchTable td{ + padding: 8px 10px; +} + +#stringMatchTable tr.highlight{ + background-color: #f5f5f5; + font-weight: bold; + font-size: 13px; +} + +#stringMatchTableHolder{ + height:200px; + width: 100%; + overflow:auto; +} + +#timeout{ + height:28px; + margin-left:10px; +} </style> @@ -76,14 +152,12 @@ label{text-align:right; } function disableSVN() { - var selectLength = document.querySelectorAll(".disabled-block-container .tab-close-popup"); + var selectLength = document.querySelectorAll(".disabled-block-container .tab-close-popup"); if(selectLength && selectLength.length>0){ for(var i = 0; i< selectLength.length ; i++){ selectLength[i].disabled = true; } } - - document.getElementById("schemaLocation").disabled = true; document.getElementById("userID").disabled = true; @@ -93,296 +167,351 @@ label{text-align:right; </script> -<div attribute-test="stringmatchproperties" id="configure-widgets" class="disabled-block-container"> - <div attribute-test="stringmatchpropertiesh" class="modal-header"> +<div attribute-test="stringMatchwindowproperties" id="configure-widgets" class="disabled-block-container"> + <div attribute-test="stringMatchwindowpropertiesh" class="modal-header"> <button type="button" class="close" ng-click="close(false)" aria-hidden="true" style="margin-top: -3px">×</button> <h4>String Matching Micro Service</h4> </div> - <div attribute-test="stringmatchpropertiesb" class="modal-body"> - <div class="alert alert-danger" role="alert" id='paramsWarn'> - <strong>Ooops!</strong> Unable to load properties for <span id='servName'>. Would you like to</span> - <a href="javascript:void(0);" class="btn-link" id='paramsRetry'>Retry </a> / - <a href="javascript:void(0);" class="btn-link" id='paramsCancel'>Cancel</a> - </div> - <div style="height: 10px"></div> - <div class="panel panel-default"> - <form id="topicPublish" class="form-horizontal"> - <div> - - <div class="form-group"> - <label for="userID" class="col-sm-4 control-label"> Topic - Publishes</label> - - <div class="col-sm-8"> - <select class="form-control" id="topicPublishes" - name="topicPublishes"> - </select> - </div> + + + <div class="modal-body"> + <div attribute-test="stringMatchwindowpropertiesb" class="modal-body row"> + + <div class="leftStringMatchPanel"> + <div class="panel panel-default"> + <i class="modelSearchBox"></i> <input type="text" + id="stringMatchSearch" onkeyup="searchStringMatchList()" + placeholder="Search ..."> + <div id="stringMatchTableHolder"> + <table id="stringMatchTable"></table> </div> </div> - </form> - <div class="panel-heading"> - <ul id="nav_Tabs" class="nav nav-tabs"> - <li class><a id="add_one_more" href="#desc_tab"><span - class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></li> - </ul> - </div> - <div class="panel-body"> - <div class="tab-content"> - <div id="properties_tab" class="tab-pane fade in active"></div> - + <div style="float: left"> + <button type="button" id="createNewStringMatch" class="btn btn-sm">New Group</button> + </span> </div> - + <div style="float: right"> + <button type="button" id="deleteStringMatch" class="btn btn-sm glyphicon glyphicon-trash" disabled></button> + </span> + </div> + <div id="repeatIdError" class="idError">Error: This Group name is already taken.</div> + <div id="newIdError" class="idError">Error: Please rename your new Group.</div> </div> - </div> - <span id="formSpan" style="display: none"> - <form class="saveProps" class="form-horizontal clearfix"> - <div> - <div class="form-group clearfix"> - <label for="aaiMatchingFields" class="col-sm-4 control-label">AAI - Fields Matching </label> - <div class="col-sm-8"> - <select type="text" class="form-control " - name="aaiMatchingFields" id="aaiMatchingFields" multiple="" size=2></select> - </div> + <div class="panel panel-default col-sm-9 stringMatchPanel" + style="display: none;"> + <form id="topicPublish" class="form-horizontal"> + <div> +<!-- As per the last minute new requirements for 1707 the ID needs to be hidden and we need to have a friendly name instead --> + <div style="display: none;"> + <div class="form-group clearfix"> + <label class="col-sm-4 control-label">Resource Group Id</label> + <div class="col-sm-8"> + <input class="form-control" id="rgname" name="rgname" readOnly> </input> + </div> + </div> + </div> + + <div> + <div class="form-group clearfix"> + <label class="col-sm-4 control-label">Resource Group</label> + <div class="col-sm-8"> + <input class="form-control" maxlength="48" placeholder="Enter Unique Name" id="rgfriendlyname" name="rgfriendlyname"> </input> + </div> + </div> + </div> + + <!--Policy's drop down box --> + <div class="form-group clearfix"> + <label class="col-sm-4 control-label">Ops Policy:</label> + <div class="col-sm-8"> + <select class="form-control" id="policyName" name="policyName" + autofocus="autofocus" required ng-trim="true"> + <option ng-repeat="x in policyNames" value="{{x}}">{{x}}</option> + </select> + </div> + </div> + </div> - <div class="form-group clearfix"> - <label for="aaiSendFields" class="col-sm-4 control-label"> - AAI Fields Send (Select Multiple)</label> - - <div class="col-sm-8 "> - <select class="form-control" - id="aaiSendFields" name="aaiSendFields" multiple size=2> + </form> + + <div class="panel-heading" style="background-color: white;"> + <ul id="nav_Tabs" class="nav nav-tabs"> + <li class><a id="add_one_more" href="#desc_tab"><span + class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></li> + </ul> + </div> + <div class="panel-body"> + <div class="tab-content"> + <div id="properties_tab" class="tab-pane fade in active"></div> + </div> + </div> + </div> - </select> + <span id="formSpan" style="display: none"> + <form class="saveProps" class="form-horizontal"> + <div> + <div class="form-group clearfix"> + <label for="aaiMatchingFields" class="col-sm-4 control-label">AAI Fields Matching </label> + <div class="col-sm-8"> + <select class="form-control" name="aaiMatchingFields" id="aaiMatchingFields" multiple size=2></select> + </div> + </div> - </div> - <div class="form-group clearfix"> - <label for="groupNumber" class="col-sm-4 control-label"> - Resource-Group</label> + <div class="form-group clearfix"> + <label for="aaiSendFields" class="col-sm-4 control-label">AAI Fields Send (Select Multiple)</label> - <div class="col-sm-8"> - <input type="number" class="form-control" id="groupNumber" name="groupNumber" min="0" > - - </input> + <div class="col-sm-8 "> + <select class="form-control" id="aaiSendFields" + name="aaiSendFields" multiple size=2> + </select> + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="vfc" class="col-sm-4 control-label"> - Resource-VFC</label> +<!-- <div class="form-group clearfix"> --> +<!-- <label for="groupNumber" class="col-sm-4 control-label"> --> +<!-- Resource-Group</label> --> - <div class="col-sm-8"> - <select class="form-control" id="vfc" name="vfc"> +<!-- <div class="col-sm-8"> --> +<!-- <input type="number" class="form-control" id="groupNumber" --> +<!-- name="groupNumber" min="0"> </input> --> - </select> +<!-- </div> --> +<!-- </div> --> + <div class="form-group clearfix"> + <label for="vfc" class="col-sm-4 control-label">Resource-VFC</label> + <div class="col-sm-8"> + <select class="form-control" id="vfc" name="vfc"> - </div> - </div> - <div class="form-group clearfix"> - <label for="alarmCondition" class="col-sm-4 control-label"> - Alarm Condition</label> + </select> - <div class="col-sm-8"> - <select class="form-control" id="alarmCondition" - name="alarmCondition"></select> + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="eventSeverity" class="col-sm-4 control-label"> - Event Severity</label> - <div class="col-sm-8"> - <select class="form-control" id="eventSeverity" - name="eventSeverity" enableFilter="false"></select> + <div class="form-group clearfix"> + <label for="alarmCondition" class="col-sm-4 control-label">Alarm Condition</label> + <div class="col-sm-8"> + <select class="form-control" id="alarmCondition" name="alarmCondition"> + + </select> + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="eventSourceType" class="col-sm-4 control-label"> - Event Source Type</label> - <div class="col-sm-8"> - <input type="text" class="form-control" id="eventSourceType" - name="eventSourceType" readOnly ></input> + <div class="form-group clearfix"> + <label for="eventSeverity" class="col-sm-4 control-label">Event Severity</label> + <div class="col-sm-8"> + <select class="form-control" id="eventSeverity" + name="eventSeverity" enableFilter="false"></select> + </div> + </div> + <div class="form-group clearfix"> + <label for="eventSourceType" class="col-sm-4 control-label"> + Event Source Type</label> + <div class="col-sm-8"> + <input type="text" class="form-control" id="eventSourceType" + name="eventSourceType" readOnly></input> + </div> </div> - </div> - - <div class="form-group clearfix"> - <label for="timeWindow" class="col-sm-4 control-label"> - Time Window</label> - - <div class="col-sm-8"> - <input type="number" min="0" class="form-control" id="timeWindow" - name="timeWindow" /> + <div class="form-group clearfix"> + <label for="timeWindow" class="col-sm-4 control-label"> + Time Window</label> + <div class="col-sm-8"> + <input type="text" maxlength="5" class="form-control" + onkeypress="return isNumberKey(event)" + id="timeWindow" name="timeWindow" /> + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="ageLimit" class="col-sm-4 control-label"> Age - Limit</label> - - <div class="col-sm-8"> - <input type="number" min="0" class="form-control" id="ageLimit" - name="ageLimit" /> + <div class="form-group clearfix"> + <label for="ageLimit" class="col-sm-4 control-label"> Age + Limit</label> + + <div class="col-sm-8"> + <input type="text" maxlength="5" class="form-control" id="ageLimit" + onkeypress="return isNumberKey(event)" + name="ageLimit" /> + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="createClosedLoopEventId" - class="col-sm-4 control-label"> Create CL Event ID</label> - <div class="col-sm-8"> - <select class="form-control" id="createClosedLoopEventId" - name="createClosedLoopEventId" enableFilter="false"> - </select> - + <div class="form-group clearfix"> + <label for="createClosedLoopEventId" + class="col-sm-4 control-label"> Create CL Event ID</label> + <div class="col-sm-8"> + <select class="form-control" id="createClosedLoopEventId" + name="createClosedLoopEventId" enableFilter="false"> + </select> + + </div> </div> - </div> - <div class="form-group clearfix"> - <label for="outputEventName" class="col-sm-4 control-label"> - Output Event Name</label> + <div class="form-group clearfix"> + <label for="outputEventName" class="col-sm-4 control-label"> + Output Event Name</label> - <div class="col-sm-8"> - <select class="form-control" id="outputEventName" - name="outputEventName" enableFilter="false"></select> + <div class="col-sm-8"> + <select class="form-control" id="outputEventName" + name="outputEventName" enableFilter="false"></select> + </div> </div> </div> - </div> - </form> - </span> + + + + </form> + </span> + </div> </div> - <div attribute-test="stringmatchpropertiesf" class="modal-footer"> + <div attribute-test="stringMatchwindowpropertiesf" class="modal-footer"> <!--<button ng-click="reset()" class="btn btn-primary" style="float:left">Reset</button>--> <button id="savePropsBtn" class="btn btn-primary">Close</button> <button ng-click="close(true)" id="close_button" class="btn btn-primary">Cancel</button> - </div> + <script> + //Basically this method will add a new form. All forms share the same class. When you want one form to show(active form) the other forms get the // css attribute display:none - $("#paramsRetry").on('click', function () { - $("#paramsWarn").hide(); - $("#ridinSpinners").css("display","") - var bool=loadSharedPropertyByService(); - $("#ridinSpinners").css("display","none") - }); - $("#paramsCancel").on('click', function () { - loadSharedPropertyByServiceProperties(); - $("#paramsWarn").hide(); - - }); - - - $("#add_one_more").click(function(event) { - //alert("lol"); event.preventDefault(); add_one_more(); - //I have uncomment the below code becoz there is no refreshItems method. - - //refreshItems(); setMultiSelect(); - - }) - loadPropertyWindow("string_match") + }); + + + //This method will load the existing Strin Match onto the screen + loadPropertyWindow("string_match"); setASDCFields(); - var arr = elementMap[lastElementSelected]; + + // By default, parentStringMatchConditions is disabled + $("#parentStringMatchConditions").prop('disabled', 'disabled'); + + + var parent_stringMatch = {} + var stringMatch_ids = {} + var loadingId = false; + var allSMatch = {}; var vfc_temp="" var alarm_conditions_temp="" var event_severity_temp="" - var event_type_source_temp="" - if (arr !== undefined && arr[1]!==undefined) { - var el = arr[1]['serviceConfigurations'] - for (var i = 0; i < el.length; i++) { - var num = add_one_more(); - for (var j = 0; j < el[i].length; j++) { - if (el[i][j]["stringSet"] !== undefined) { - var ss = el[i][j]["stringSet"] - for (var o = 0; o < ss.length; o++) { - if(ss[o].hasOwnProperty("name")){ - if(ss[o].name==="alarmCondition"){ - alarm_conditions_temp=ss[o].value - }else if(ss[o].name==="eventSeverity"){ - event_severity_temp=ss[o].value; - }else if(ss[o].name==="eventSourceType"){ - event_type_source_temp=ss[o].value; + var event_type_source_temp="" + + //Grab saved values for dropdowns + var obj = elementMap[lastElementSelected]; + + if (!($.isEmptyObject(obj))) { + allSMatch = jQuery.extend({}, obj); + for ( var x in allSMatch) { + $("#stringMatchTable").prepend( + "<tr><td>" + x + "</td></tr>"); + } + } + + + //Load properties_tab for a chosen String Match + function disperseConfig(stringMatchObj, id) { + //remove old gui forms + for (var i = 1; i < ($(".formId").length + 1); i++) { + $("#go_properties_tab" + i).parent().remove(); + } + $(".formId").remove(); + + if (stringMatchObj !== undefined) { + var el = stringMatchObj[id][4]['serviceConfigurations'] + for (var i = 0; i < el.length; i++) { + loadingId = true; + var num = add_one_more(); + loadingId = false; + for (var j = 0; j < el[i].length; j++) { + if (el[i][j]["stringSet"] !== undefined) { + var ss = el[i][j]["stringSet"] + for (var o = 0; o < ss.length; o++) { + if(ss[o].hasOwnProperty("name")){ + if(ss[o].name==="alarmCondition"){ + alarm_conditions_temp=ss[o].value + }else if(ss[o].name==="eventSeverity"){ + event_severity_temp=ss[o].value; + }else if(ss[o].name==="eventSourceType"){ + event_type_source_temp=ss[o].value; + } + else + $("#formId" + num + " #" + ss[o].name).val(ss[o].value); } - else - $("#formId" + num + " #" + ss[o].name).val(ss[o].value); + + } + }else if(el[i][j].hasOwnProperty("name") && el[i][j].name==="vfc"){ + vfc_temp=el[i][j].value + } + else if (el[i][j].name === 'outputEventName' && el[i][j].value.toString() !== '') { + $("#go_properties_tab" + num).text(el[i][j].value); + $("#formId" + num + " #" + el[i][j].name).val(el[i][j].value); + } + else { + if(el[i][j].hasOwnProperty("name")){ + $("#formId" + num + " #" + el[i][j].name).val( + el[i][j].value); } - } - }else if(el[i][j].hasOwnProperty("name") && el[i][j].name==="vfc"){ - //alert(el[i][j].value) - vfc_temp=el[i][j].value } - else { - if(el[i][j].hasOwnProperty("name")){ - $("#formId" + num + " #" + el[i][j].name).val( - el[i][j].value); + set_vfc_alarm_event(num); + vfc_temp=""; + alarm_conditions_temp=""; + event_severity_temp=""; + event_type_source_temp=""; + } + + //Adding all the ids for parent String options + for (var i = 1; i <= $(".formId").length; i++) { + for (k in stringMatch_ids) { + if ($("#formId" + i + " #_id").val() !== stringMatch_ids[k].toString() && $(k + " #recipe").val() !== undefined && $(k + " #recipe").val() !== "") { + $("#formId" + i + " #parentStringMatch").append("<option value=\""+stringMatch_ids[k]+"\">"+ $(k + " #recipe").val()+ "</option>"); } } } - changeTab(num); - set_vfc_alarm_event(num) - vfc_temp="" - alarm_conditions_temp="" - event_severity_temp="" - event_type_source_temp="" - } - if(arr[0] && arr[0][0] && arr[0][0].name){ - $("#" + arr[0][0].name).val(arr[0][0].value); - } + for (k in parent_stringMatch) { + $("#formId" + k + " #parentStringMatch").val(parent_stringMatch[k]); + // force the change event + $("#formId" + k + " #parentStringMatch").change(); + } - } - - //this will populate alarmcondition,vfc,eventtypesource if they are saved in elementmap - function set_vfc_alarm_event (count){ - //alert("lol") - //alert(alarm_conditions_temp) - //alert(alarm_conditions_temp!=="" && alarm_conditions_temp!==undefined) - if(vfc_temp!=="" && vfc_temp!==undefined){ - $("#formId"+count+" #vfc").val(vfc_temp) + if (stringMatchObj[id][0]) { + $("#" + stringMatchObj[id][0].name).val(stringMatchObj[id][0].value); + } - if(alarm_conditions_temp!=="" && alarm_conditions_temp!==undefined){ - setAlarmConditions(vfc_temp,count) - $("#formId"+count+" #alarmCondition").val(alarm_conditions_temp) - - if(event_severity_temp!=="" && event_severity_temp!==undefined){ - setEventSourceType(alarm_conditions_temp,count) - $("#formId"+count+" #eventSeverity").val(event_severity_temp) - if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ - $("#formId"+count+" #eventSourceType").val(event_type_source_temp) - } - } - if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ - setEventSourceType(alarm_conditions_temp,count) - $("#formId"+count+" #eventSourceType").val(event_type_source_temp) - if(event_severity_temp!=="" && event_severity_temp!==undefined){ - $("#formId"+count+" #eventSeverity").val(event_severity_temp) - } - } + if (stringMatchObj[id][1]) { + $("#" + stringMatchObj[id][1].name).val(stringMatchObj[id][1].value); + } + + if (stringMatchObj[id][2]) { + $("#" + stringMatchObj[id][2].name).val(stringMatchObj[id][2].value); } } + + setMultiSelect(); - + if (readOnly||readMOnly){ + $('select[multiple] option').each(function() { + var input = $('input[value="' + $(this).val() + '"]'); + input.prop('disabled', true); + input.parent('li').addClass('disabled'); + }); + $('input[value="multiselect-all"]').prop('disabled', true).parent('li').addClass('disabled'); + } } - - + + + //This is ensure there are no repeated keys in the map function noRepeats(form) { + //triggered per String. var select = {}; for (var i = 0; i < form.length; i++) { - if(form[i].hasOwnProperty("name")){ if (select[form[i].name] === undefined) select[form[i].name] = [] select[form[i].name].push(form[i].value); } - } var arr = [] for (s in select) { var f = {} @@ -392,84 +521,69 @@ label{text-align:right; } return arr } - function setStringSet(form) { - var arr = [] - var alarmCondition = {} - var eventSeverity = {} - var eventSourceType = {} - for (var i = 0; i < form.length; i++) { - if (form[i].name === "alarmCondition") { - alarmCondition = form[i] - } else if (form[i].name === "eventSeverity") { - eventSeverity = form[i]; - } else if (form[i].name === "eventSourceType") { - eventSourceType = form[i]; - } else { - arr.push(form[i]) + $("#savePropsBtn").click(function(event) { + $(".idError").hide(); + if ($("#stringMatchTable .highlight td").html() !== $("#rgfriendlyname").val()){ + //repeated name + if ($.inArray($("#rgfriendlyname").val(), Object.keys(allSMatch)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + delete allSMatch[$("#stringMatchTable .highlight td").html()]; } - } - var stringSet = {}; - stringSet['stringSet'] = [] - stringSet['stringSet'].push(alarmCondition); - stringSet['stringSet'].push(eventSeverity); - stringSet['stringSet'].push(eventSourceType); - arr.push(stringSet) - - return arr; - } - $("#savePropsBtn").click(function(event) { - - var form = [] - var properties = $(".saveProps").not("#formSpan .saveProps") - var topicP = $("#topicPublish").serializeArray() - form.push(topicP) - var d = {} - d["serviceConfigurations"] = []; - - for (var i = 0; i < properties.length; i++) { - var ser = $(properties[i]).serializeArray(); - var s = noRepeats(ser) - var newSer = setStringSet(s) - - d["serviceConfigurations"].push(newSer) + /* //Saves edits + if ($("#stringMatchTable .highlight").length > 0) { + saveLastStringMatchLocally($("#stringMatchTable .highlight td").html()); + } */ + if ($("#rgfriendlyname").val().trim() == "New_Group"){ + $("#newIdError").show(); + return; } - form.push(d) - saveProperties(form) + startNextItem(); + //Removes outdated (deleted) resource Groups by checking against left menu + var finalSaveList = {}; + $("#stringMatchTable td").each(function() { + var tableVal = $(this).text(); + if (tableVal in allSMatch) { + finalSaveList[tableVal] = allSMatch[tableVal]; + } + }); + saveProperties(finalSaveList); $("#close_button").click(); - }) - - - - - + function add_one_more() { $("#nav_Tabs li").removeClass("active"); + + //FormSpan contains a block of the form that is not being displayed. We will create clones of that and add them to tabs var form = $($("#formSpan").children()[0]).clone() var count = 0; - //alert($(".formId").length>0) + //Each new tab will have the formId class attached to it. This way we can track how many forms we currently have out there and assign listeners to them if ($(".formId").length > 0) { var greatest = 0; var s = $(".formId"); - //alert("here1") for (var i = 0; i < s.length; i++) { if (parseInt($(s[i]).attr("id").substring(6)) > greatest) { greatest = parseInt($(s[i]).attr("id").substring(6)) } } count = greatest + 1; - //alert(count) $("#properties_tab").append( ('<span class="formId" id="formId'+count+'"></span>')); } else { - //alert("here2") count++; $("#properties_tab").append( '<span class="formId" id="formId1"></span>'); } + + //$(form).find("#stringMatchName").val("Recipe "+makid(2)) + //TODO change up how we auto assign stringMatchName. There could be the case where we do this and it will have repeats + //alert($(form).find("#_id").val()) + //stringMatchNameChangeListener(form) + $("#add_one_more") .parent() .before( @@ -477,12 +591,83 @@ label{text-align:right; $("#formId" + count).append(form); $(".formId").not($("#formId" + count)).css("display", "none") addCustListen(count) - addEventNameList(count) - add_vfc_alarm_event_listener(count); + addTabListen(count) + + // This is for when the process is not loading from map but being created + if (!loadingId) { + var l = makeid() + $(form).find("#_id").val(l) + stringMatch_ids["#formId" + count] = l + var answers = {} + + for (k in answers) { + $(k).val(answers[k]) + } + } return count; } - function addCustListen(count) { + function add_new_stringMatch(issueNewNames) { + //remove old gui forms + for (var i = 1; i < ($(".formId").length + 1); i++) { + $("#go_properties_tab" + i).parent().remove(); + } + $(".formId").remove(); + + //Reset header + var ms = new Date().getTime(); + var defSMatch = ms; + $("#rgname").val(defSMatch); + + $("#rgfriendlyname").val("New_Group"); + + $("#add_one_more").click(); + return defSMatch; + } + + //listener will change the tab name to the recipe + function addTabListen(count) { + $("#formId" + count + " #recipe").on("change",function() { + if ($("#formId" + count + " #recipe").val().toString() !== "") { + $('#go_properties_tab' + count).text($("#formId" + count + " #recipe").val()) + } else + $('#go_properties_tab' + count).text("String"); + + var answers = {} + + for (var i = 1; i <= greatestIdNum(); i++) { + if ($("#formId" + i).length > 0) { + + answers["#formId" + i + " #parentStringMatch"] = $("#formId" + i + " #parentStringMatch").val() + $("#formId" + i + " #parentStringMatch").empty(); + + for (k in stringMatch_ids) { + if ($("#formId" + i + " #_id").val().toString() !== stringMatch_ids[k] && $(k + " #recipe").val() !== 'undefined' && $(k + " #recipe").val() !== "") { + $("#formId" + i + " #parentStringMatch").append("<option value='"+stringMatch_ids[k]+"''> "+ $(k+ " #recipe").val()+ "</option>") + } + } + $("#formId" + i + " #parentStringMatch").prepend("<option value=''></option>") + } + } + for (k in answers) { + $(k).val(answers[k]) + } + }) + + // disable parentStringMatchConditions when a parentStringMatch is not selected + $("#formId" + count + " #parentStringMatch").on("change",function() { + if ($("#formId" + count + " #parentStringMatch").val().toString() == "") { + // deselect all options + $("#formId"+ count+ " #parentStringMatchConditions option:selected").prop("selected", false); + // disable the select box + $("#formId"+ count+ " #parentStringMatchConditions").prop('disabled', 'disabled'); + } else { + $("#formId"+ count+ " #parentStringMatchConditions").prop('disabled', false); + } + }) + } + + function addCustListen(count) { $('#go_properties_tab' + count).click(function(event) { $("#nav_Tabs li").removeClass("active"); $(this).parent().addClass("active"); @@ -491,95 +676,300 @@ label{text-align:right; }) $('#tab_close' + count).click(function(event) { - if(document.getElementById("topicPublishes").disabled){ - return false; - } + $(this).parent().remove(); + delete stringMatch_ids["#formId" + count + " #_id"] $("#formId" + count).remove(); }) } + + function setStringSet(form) { + var arr = [] + var alarmCondition = {} + var eventSeverity = {} + var eventSourceType = {} + for (var i = 0; i < form.length; i++) { + if (form[i].name === "alarmCondition") { + alarmCondition = form[i] + } else if (form[i].name === "eventSeverity") { + eventSeverity = form[i]; + } else if (form[i].name === "eventSourceType") { + eventSourceType = form[i]; + } else { - function changeTab(count){ - var output = $('#formId' + count + " #outputEventName"); - var group = $('#formId' + count + " #groupNumber"); - var outputValue=""; - var groupValue=""; - if(output.val()!=="") - outputValue=output.val(); - if(output.val()!=="" && group.val()!=="") - groupValue=group.val()+":"; - else if(group.val()!=="") - groupValue=group.val(); - - var tabText="Condition" - if(groupValue+outputValue!=="") - tabText=groupValue+outputValue; - $("#go_properties_tab" + count).text(tabText); + arr.push(form[i]) + } + + } + var stringSet = {}; + stringSet['stringSet'] = [] + stringSet['stringSet'].push(alarmCondition); + stringSet['stringSet'].push(eventSeverity); + stringSet['stringSet'].push(eventSourceType); + arr.push(stringSet) + + return arr; } - function addEventNameList(count) { + //this will populate alarmcondition,vfc,eventtypesource if they are saved in elementmap + function set_vfc_alarm_event (count){ + if(vfc_temp!=="" && vfc_temp!==undefined){ + $("#formId"+count+" #vfc").val(vfc_temp) + + if(alarm_conditions_temp!=="" && alarm_conditions_temp!==undefined){ + setAlarmConditions(vfc_temp,count) + $("#formId"+count+" #alarmCondition").val(alarm_conditions_temp); + + if(event_severity_temp!=="" && event_severity_temp!==undefined){ + setEventSourceType(alarm_conditions_temp,count) + $("#formId"+count+" #eventSeverity").val(event_severity_temp) + if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ + $("#formId"+count+" #eventSourceType").val(event_type_source_temp) + } + } + if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ + setEventSourceType(alarm_conditions_temp,count) + $("#formId"+count+" #eventSourceType").val(event_type_source_temp) + if(event_severity_temp!=="" && event_severity_temp!==undefined){ + $("#formId"+count+" #eventSeverity").val(event_severity_temp) + } + } + } + } + } + + function setAlarmConditions(vfcID, count){ + var alarmCondition={} + + if($("#formId"+count+" #vfc").val()!==""){ + if(vf_Services['shared'] && vf_Services['shared']['byVfc'] && vf_Services['shared']['byVfc'][vfcID]){ + alarmCondition=vf_Services['shared']['byVfc'][vfcID]['alarmCondition'] + } + } - $('#formId' + count + " #outputEventName").on('change',function(){changeTab(count)}) - $('#formId' + count + " #groupNumber").on('change',function(){changeTab(count)}); + $("#formId"+count+" #alarmCondition").empty(); + $("#formId"+count+" #alarmCondition").append("<option value=\"\"></opton>"); + if(alarmCondition && _.keys(alarmCondition).length>0){ + for(key in alarmCondition){ + var safestring = $('<div>').text(key).html(); + $("#formId"+count+" #alarmCondition").append("<option value='"+safestring+"'>"+alarmCondition[key]+"</opton>"); + } + $("#formId"+count+" #alarmCondition").multiselect("rebuild"); + } + } + function setEventSourceType(alarm, count){ + var eventSourceTypSeverity={} + if($("#formId"+count+" #alarmCondition").val()!==""){ + if(vf_Services && vf_Services['shared'] && vf_Services['shared']['byAlarmCondition'] && vf_Services['shared']['byAlarmCondition'][alarm]){ + eventSourceTypSeverity=vf_Services['shared']['byAlarmCondition'][alarm] + } + + } + + $("#formId"+count+" #eventSourceType").val(eventSourceTypSeverity.eventSourceType); + $("#formId"+count+" #eventSeverity").val(eventSourceTypSeverity.eventSeverity); + $("#formId"+count+" #eventSeverity").multiselect("rebuild"); + } + + function greatestIdNum() { + var greatest = 0; + var s = $(".formId"); + for (var i = 0; i < s.length; i++) { + if (parseInt($(s[i]).attr("id").substring(6)) > greatest) { + greatest = parseInt($(s[i]).attr("id").substring(6)) + } + } + return greatest; } - - -function setAlarmConditions(vfcID, count){ - var alarmCondition={} - - if($("#formId"+count+" #vfc").val()!==""){ - if(vf_Services['shared'] && vf_Services['shared']['byVfc'] && vf_Services['shared']['byVfc'][vfcID]){ - alarmCondition=vf_Services['shared']['byVfc'][vfcID]['alarmCondition'] + + //Generate random id for each String + //Also made sure ids couldnt be repeated + function makeid(num) { + + var text = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + if (num == null) + num = 7; + for (var i = 0; i < 7; i++) + text += possible.charAt(Math.floor(Math.random() + * possible.length)); + var hasValue = false; + for (k in stringMatch_ids) { + if (text === stringMatch_ids[k]) + hasValue = true + } + if (hasValue) + return makeid(num); + else + return text } - - } - - $("#formId"+count+" #alarmCondition").empty(); - $("#formId"+count+" #alarmCondition").append("<option value=\"\"></opton>") - if(alarmCondition && _.keys(alarmCondition).length>0){ - for(key in alarmCondition){ - var safestring = $('<div>').text(key).html(); - $("#formId"+count+" #alarmCondition").append("<option value='"+safestring+"'>"+alarmCondition[key]+"</opton>") + + var ParentStringMatch = function(id, name) { + this.id = id + this.name = name } - } -} -function setEventSourceType(alarm, count){ - var eventSourceTypSeverity={} - if($("#formId"+count+" #alarmCondition").val()!==""){ - if(vf_Services && vf_Services['shared'] && vf_Services['shared']['byAlarmCondition'] && vf_Services['shared']['byAlarmCondition'][alarm]){ - eventSourceTypSeverity=vf_Services['shared']['byAlarmCondition'][alarm] + //String table search filter + function searchStringMatchList() { + var search = document.getElementById("stringMatchSearch"); + var row = document.getElementsByTagName("td"); + for (var i = 0; i < row.length; i++) { + if (row[i].innerHTML.toUpperCase().indexOf( + search.value.toUpperCase()) > -1) { + row[i].style.display = ""; + } else { + row[i].style.display = "none"; + } + } } - - } - - $("#formId"+count+" #eventSourceType").val(eventSourceTypSeverity.eventSourceType); - $("#formId"+count+" #eventSeverity").val(eventSourceTypSeverity.eventSeverity); - -} -function add_vfc_alarm_event_listener(count) { + + function saveLastStringMatchLocally(lastStringMatchId) { + var polForm = [] + + var properties = $(".saveProps").not("#formSpan .saveProps") - $("#formId"+count+" #vfc").on('focus', function () { - // Store the current value on focus and on change - previous = this.value; - }).change(function(){ + var topicPublish = $("#topicPublish").serializeArray(); - setAlarmConditions($("#formId"+count+" #vfc").val(), count); - $("#formId"+count+" #eventSourceType").val(""); - $("#formId"+count+" #eventSeverity").val("") + for (var i = 0; i < topicPublish.length; i++) { + polForm.push(topicPublish[i]); + } + + //The below three lines are added to make sure resource group can be save correctly even if the policy is not present + if (topicPublish.length == 2){ + var pname = {name:"policyName", value:""}; + polForm.push(pname); + var pid = {name:"policyId", value:""}; + polForm.push(pid); + }else{ + var selectedPName = topicPublish[2]["value"]; + var pid = {name:"policyId", value:allPolicies[selectedPName][1]["value"]}; + polForm.push(pid); + } + var d = {} + d["serviceConfigurations"] = []; + for (var i = 0; i < properties.length; i++) { + var ser = $(properties[i]).serializeArray(); + var s = noRepeats(ser) + var newSer = setStringSet(s); + d["serviceConfigurations"].push(newSer); + } + polForm.push(d); + allSMatch[lastStringMatchId] = polForm; + } + + $("#deleteStringMatch").on('click', function() { + $(".idError").hide(); + var deleteId = $("#stringMatchTable .highlight td").html(); + delete allSMatch.deleteId; + $("#stringMatchTable .highlight").remove(); + $("#rgfriendlyname").val(''); + expandTable(); }); - - $("#formId"+count+" #alarmCondition").on('focus', function () { - // Store the current value on focus and on change - previous = this.value; - }).change(function(){ - + + $('#stringMatchTable').on('click', 'tr', function(event) { + $(".idError").hide(); + //edited name + if ($("#stringMatchTable .highlight td").html() !== $("#rgfriendlyname").val()){ + //repeated name + if ($.inArray($("#rgfriendlyname").val(), Object.keys(allSMatch)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + $("#repeatIdError").hide(); + delete allSMatch[$("#stringMatchTable .highlight td").html()]; + } + } + if ($("#rgfriendlyname").val().trim() == "New_Group"){ + $("#newIdError").show(); + return; + } + if (!(readOnly||readMOnly)){ + startNextItem(); + } else { + if ($("#stringMatchTable .highlight").length == 0){ + collapseTable(); + } + } + + $(this).addClass('highlight').siblings().removeClass('highlight'); + disperseConfig(allSMatch, $(this).find("td").html()); + }); + + + $('#createNewStringMatch').on('click', function() { + $(".idError").hide(); + //edited name + if ($("#stringMatchTable .highlight td").html() !== $("#rgfriendlyname").val()){ + //repeated name + if ($.inArray($("#rgfriendlyname").val(), Object.keys(allSMatch)) > -1){ + $("#repeatIdError").show(); + return; + } else { //not repeated + $("#repeatIdError").hide(); + delete allSMatch[$("#stringMatchTable .highlight td").html()]; + } + } + if ($("#rgfriendlyname").val().trim() == "New_Group"){ + $("#newIdError").show(); + return; + } + startNextItem(); + var defSMatch = add_new_stringMatch(); + + if (("#stringMatchTable .highlight").length > 0) { + $('#stringMatchTable tr.highlight').removeClass('highlight'); + } + //$("#stringMatchTable").prepend("<tr class='highlight' id='" +defSMatch+ "''><td>"+ defSMatch + "</td></tr>"); + $("#stringMatchTable").prepend("<tr class='highlight'><td>New_Group</td></tr>"); - setEventSourceType($("#formId"+count+" #alarmCondition").val().toString(),count); }); + + function isNumberKey(event){ + var charCode = (event.which) ? event.which : event.keyCode + if (charCode > 31 && (charCode < 48 || charCode > 57)){ + return false; + } + return true; }; - </script> -</div> + + function startNextItem() { + //save last item before transitioning + var lastItem = $("#stringMatchTable .highlight"); + + + if (lastItem.length > 0) { + saveLastStringMatchLocally($("#rgfriendlyname").val()); + //lastItem.attr("id", $("#rgfriendlyname").val()); + if($("#rgfriendlyname").val() != ''){ + lastItem.find("td").html($("#rgfriendlyname").val()); + } + } else { + collapseTable(); + } + + //allow deleting + if ($("#deleteStringMatch").prop("disabled")) { + $("#deleteStringMatch").prop("disabled", false); + } + } + //Show table panel only + function expandTable() { + $(".stringMatchPanel").css("display", "none"); + $(".leftStringMatchPanel").removeClass("col-sm-3"); + $(".modelSearchBox").css("padding", "25px 12px"); + if (!($("#deleteStringMatch").prop("disabled"))) { + $("#deleteStringMatch").prop("disabled", true); + } + } + + //Show both menus + function collapseTable() { + $(".leftStringMatchPanel").addClass("col-sm-3"); + $(".glyphicon-search").css("padding", "10px 12px"); + $(".stringMatchPanel").css("display", "unset"); + } + </script> +</div>
\ No newline at end of file diff --git a/src/main/resources/META-INF/resources/designer/partials/portfolios/tca_properties.html b/src/main/resources/META-INF/resources/designer/partials/portfolios/tca_properties.html index c0bbe3b4b..3219fe432 100644 --- a/src/main/resources/META-INF/resources/designer/partials/portfolios/tca_properties.html +++ b/src/main/resources/META-INF/resources/designer/partials/portfolios/tca_properties.html @@ -22,6 +22,17 @@ --> <style> +#createNewThresh{ + height:34px; + width:120px; /*84*/ + background-color:#f2bfab; +} + +#deleteThresh{ + height:34px; + background-color:#dddd; +} + .fileUpload { position: relative; overflow: hidden; @@ -52,7 +63,61 @@ } .form-group { - margin-bottom:20px; + margin-bottom:15px; + display:-webkit-flex; + display: flex; + align-items: center; +} + +#tcaEditHolder{ + height:260px; + background-color: #f5f5f5; + padding:10px 0px; + margin: 15px 15px 0 0; + float: right; +} +.tcaErr{ + display:none; + text-align:center; + margin-bottom:20px; + color:red;" +} + +.tcaParentItems { + padding-left: 20px; +} + +.tcaParentItems label{ + margin-bottom: 0px; +} + +#tcaTable{ + cursor: pointer; + width:100%; +} + +#tcaTable tr{ + border-bottom: 1px solid #ddd; + border-collapse: collapse; + text-align: center; + font-size: 12px; + font-weight: normal; +} + +#tcaTable td{ + padding: 8px 10px; +} + +#tcaTable tr.highlight{ + background-color: #f5f5f5; + font-weight: bold; + font-size: 13px; +} + +#tcaTableHolder{ + height:160px; + width: 100%; + overflow:auto; } </style> @@ -88,205 +153,340 @@ </div> <div class="modal-body"> <div style="height: 10px"></div> - <div class="panel panel-default"> - <form id="topicPublish" class="form-horizontal"> - <div> - - <div class="form-group"> - <label for="userID" class="col-sm-4 control-label"> Topic Publishes</label> - - <div class="col-sm-8"> - <select class="form-control" id="topicPublishes" - name="topicPublishes"> - </select> - </div> - </div> - </div> - </form> + <div class="panel panel-default" id="panelHolder"> + <div class="panel-heading"> <ul id="nav_Tabs" class="nav nav-tabs"> <li class><a id="add_one_more" href="#desc_tab"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></a></li> </ul> </div> + + <span id="formSpan" style="display:none;"> <div class="panel-body"> - <div class="tab-content"> - <div id="properties_tab" class="tab-pane fade in active"></div> - - </div> - - </div> - </div> - <span id="formSpan" style="display: none"> - <form class="saveProps" class="form-horizontal"> - <div> - - <div class="form-group"> - <label class="col-sm-4 control-label">Field Path / Counter</label> - <div class="col-sm-8"> - <select class="form-control" id="fieldPath" name="fieldPath"></select> + + <form class="tcaParentItems"> + <div class="row"> + <div class="col-sm-8 form-group"> + <label class="col-sm-3"> Name </label> + <div class="col-sm-9" style="padding:0px;"> + <input class="form-control" type="text" maxlength="48" id="tname" name="tname"></input> + </div> + </div> + + <div class="col-sm-8 form-group" style="display:none;"> + <label class="col-sm-3"> UUID </label> + <div class="col-sm-9" style="padding:0px;"> + <input class="form-control" onkeydown="return false;" type="text" id="tuuid" name="tuuid"></input> + </div> + </div> + + <div class="col-sm-8 form-group" style="display:none;"> + <label class="col-sm-3"> NF Code </label> + <div class="col-sm-9" style="padding:0px;"> + <input class="form-control" onkeydown="return false;" type="text" id="tnfc" name="tnfc"></input> + </div> + </div> + + <div class="col-sm-3 form-group"> + <label class="col-sm-8"> Enable </label> + <input class="col-sm-4" type="checkbox" style="height:21px; + width:21px; margin:6px;" checked="checked" id="tcaEnab" name="tcaEnab"></input> </div> </div> - <div class="form-group"> - <label class="col-sm-4 control-label">Threshold</label> - <div class="col-sm-8"> - <input type="number" min="0" class="form-control" - name="threshold" id="threshold"> - </input> + <div class="row"> + <div class="col-sm-8 form-group"> + <label class="col-sm-3"> Policy </label> + <div class="col-sm-9" style="padding:0px;"> + <select name="tcaPol" id="tcaPol" enableFilter="false"></select> + </div> + </div> + + <div class="col-sm-8 form-group" style="display:none;"> + <label class="col-sm-3"> Policy ID </label> + <div class="col-sm-9" style="padding:0px;"> + <input class="form-control" onkeydown="return false;" type="text" id="tcaPolId" name="tcaPolId"></input> + </div> + </div> + + <div class="col-sm-3 form-group"> + <label class="col-sm-8">Max Intervals</label> + <input class="col-sm-4 form-control" style="width:80%" type="text" maxlength="3" + id="tcaInt" onkeypress="return isNumberKey(event)" name="tcaInt"></input> </div> </div> - - - <div class="form-group"> - <label class="col-sm-4 control-label">Operator</label> - <div class="col-sm-8"> - <select class="form-control" id="operator" name="operator"></select> + <div class="row"> + <div class="col-sm-8 form-group"> + <label class="col-sm-3"> Severity </label> + <div class="col-sm-9" style="padding:0px;"> + <select name="tcaSev" id="tcaSev" enableFilter="false"> + </select> + </div> + </div> + + <div class="col-sm-3 form-group"> + <label class="col-sm-8">Min Violations</label> + <input class="col-sm-4 form-control" style="width:80%" type="text" maxlength="3" + id="tcaVio" onkeypress="return isNumberKey(event)" name="tcaVio"></input> </div> </div> + </form> + + <div class="tcaBody row"> + <div class="col-sm-5" style="padding:0px 5px; margin: 15px;"> + <div class="panel panel-default" id="tcaTableHolder"> + <table id="tcaTable"> + </table> + </div> + <div id="tcaError" class="tcaErr">Error: Please define/delete this new threshold</div> + <div id="tcaUnique" class="tcaErr">Error: Duplicate Set Name Found</div> + <div style="float:left"> + <button type="button" id="createNewThresh" class="btn btn-sm">New Threshold</button> + </div> + <div style="float:right"> + <button type="button" id="deleteThresh" class="btn btn-sm glyphicon glyphicon-trash" disabled></button> + </div> + + </div> - - - <div class="form-group"> - <label class="col-sm-4 control-label">Ops Policy</label> - - <div class="col-sm-8"> - <select class="form-control" id="opsPolicy" name="opsPolicy" - enableFilter="false" ></select> + <div id="tcaEditHolder" class="panel panel-default col-sm-6"> + <div class="tab-content"> + <div id="properties_tab" style="padding:10px;" class="form-horizontal"> + <div style="margin-bottom:20px;"> + <label class="control-label">Metric</label> + <div> + <select id="fieldPathM" name="fieldPathM"></select> + </div> + </div> + <div style="margin-bottom:20px;"> + <label class="control-label">Operator</label> + <div> + <select id="operator" name="operator"></select> + </div> + </div> + <div style="margin-bottom:20px;"> + <label class="control-label">Threshold</label> + <div> + <input type="text" maxlength="10" class="form-control" name="threshold" + onkeypress="return isNumberKey(event)" id="threshold"></input> + </div> + </div> + </div> </div> </div> </div> - - </form> - </span> + + </div> + </span> + + </div> </div> +</div> <div class="modal-footer"> <!--<button ng-click="reset()" class="btn btn-primary" style="float:left">Reset</button>--> <button id="savePropsBtn" class="btn btn-primary">Close</button> <button ng-click="close(true)" id="close_button" class="btn btn-primary">Cancel</button> - </div> + <script> - //Basically this method will add a new form. All forms share the same class. When you want one form to show(active form) the other forms get the - // css attribute display:none - $("#add_one_more").click(function(event) { + var generateTUUID = function(count){ + var d = new Date().getTime(); + var tuuid = 'xxxxxxxx-xxxx-txxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function(c){ + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c == 'x' ? r : (r*0x3|0*8)).toString(16); + }); + $("#formId" + count + " #tuuid").val(tuuid); + } + + $("#add_one_more").click(function(event) { event.preventDefault(); - add_one_more(); - setMultiSelect(); + if ($("#nav_Tabs li.active").length>0){ + var oldCount = $("#nav_Tabs li.active").find("a").attr("id").slice(-1); + if (($('#formId'+oldCount+' #tcaTable .highlight').length > 0 ) && + (!($('#formId'+oldCount+' #threshold').val()) || !($('#formId'+oldCount+' #fieldPathM').val())) ) { + $('#formId'+oldCount+' #tcaError').show(); + return; + } else { + $('#formId'+oldCount+' .tcaErr').hide(); + if ($('#formId'+oldCount+' #tcaTable .highlight').length > 0){ + $('#formId'+oldCount+' #tcaTable .highlight td').text( + $('#formId'+oldCount+' #fieldPathM').val() + ' ' + + $('#formId'+oldCount+' #operator').val() + ' ' + + $('#formId'+oldCount+' #threshold').val()); + } + $("#formId"+oldCount+" #tcaTable .highlight").removeClass("highlight") + } + } + var count = add_one_more(); + generateTUUID(count); }) - loadPropertyWindow("tca") + loadPropertyWindow("tca"); + + //load dropdown with policy options + if (typeof allPolicies !== "undefined"){ + $.each(Object.keys(allPolicies), function(val, text) { + $('#tcaPol').append($('<option></option>').val(text).html(text)); + }); + } else if (typeof elementMap !== "undefined"){ + for (key in elementMap){ + if (key.indexOf("Policy")>-1){ + $.each(Object.keys(elementMap[key]), function(val, text){ + $('#tcaPol').append( + $('<option></option>').val(text).html(text) + ); + }); + } + } + } + setASDCFields(); + + //load metrics dropdown + if (elementMap["global"]){ + for (var i = 0; i < (elementMap["global"].length); i++){ + if ((elementMap["global"][i]["name"]) == "vf"){ + var vfSel = elementMap["global"][i]["value"]; + if (vf_Services["shared"]["byVf"][vfSel]["kpi"]){ + $.each((vf_Services["shared"]["byVf"][vfSel]["kpi"]), function(val, text) { + $('#fieldPathM').append( + $('<option></option>').val(val).html(text) + ); + }); + } + break; + }; + }; + }; + var arr = elementMap[lastElementSelected]; - var vfc_temp="" - var alarm_conditions_temp="" - var event_severity_temp="" - var event_type_source_temp="" + if (arr !== undefined) { - //arr[0] - var el=arr[1]['serviceConfigurations'] - for (var i = 0; i < el.length; i++) { - var num=add_one_more(); - for(var j=0;j<el[i].length;j++){ - if(el[i][j].name==="vfc"){ - vfc_temp=el[i][j].value - }else if(el[i][j].name==="alarmCondition"){ - alarm_conditions_temp=el[i][j].value - }else if(el[i][j].name==="eventSeverity"){ - event_severity_temp=el[i][j].value; - }else if(el[i][j].name==="eventSourceType"){ - event_type_source_temp=el[i][j].value; + for (var x in arr){ + var num = add_one_more(); + var setCheck = true; + for (var i=0; i< arr[x].length; i++){ + if (arr[x][i].name=='tcaEnab'){ + $("#formId" + num + " #tcaEnab").prop("checked","true"); + setCheck = false; } - else - $("#formId"+num+" #" + el[i][j].name).val(el[i][j].value); - - } - - set_vfc_alarm_event(num) - vfc_temp="" - alarm_conditions_temp="" - event_severity_temp="" - event_type_source_temp="" - - } - - $("#"+ arr[0][0].name).val(arr[0][0].value); - - - } - - function set_vfc_alarm_event (count){ - if(vfc_temp!=="" && vfc_temp!==undefined){ - $("#formId"+count+" #vfc").val(vfc_temp) - - if(alarm_conditions_temp!=="" && alarm_conditions_temp!==undefined){ - setAlarmConditions(vfc_temp,count) - $("#formId"+count+" #alarmCondition").val(alarm_conditions_temp) - - if(event_severity_temp!=="" && event_severity_temp!==undefined){ - setEventSourceType(alarm_conditions_temp,count) - $("#formId"+count+" #eventSeverity").val(event_severity_temp) - if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ - $("#formId"+count+" #eventSourceType").val(event_type_source_temp) - } - } - if(event_type_source_temp!=="" && event_type_source_temp!==undefined){ - setEventSourceType(alarm_conditions_temp,count) - $("#formId"+count+" #eventSourceType").val(event_type_source_temp) - if(event_severity_temp!=="" && event_severity_temp!==undefined){ - $("#formId"+count+" #eventSeverity").val(event_severity_temp) + if (arr[x][i].hasOwnProperty('serviceConfigurations')){ + for (var j=0; j<arr[x][i]["serviceConfigurations"].length; j++){ + $("#formId" + num + " #tcaTable").prepend("<tr><td>" + +arr[x][i]["serviceConfigurations"][j][0]+" " + //+(defaults_props['tca']['operator']).getKey(arr[x][i]["serviceConfigurations"][j][1])+" " + +(Object.keys(defaults_props['tca']['operator']).find(key => defaults_props['tca']['operator'][key] == (arr[x][i]["serviceConfigurations"][j][1])))+ " " + +arr[x][i]["serviceConfigurations"][j][2]+"</td></tr>"); } + } else { + $("#formId" + num + " #"+arr[x][i].name).val(arr[x][i].value); } } + if (setCheck){ + $("#formId" + num + " #tcaEnab").prop("checked",false); + } + $('#go_properties_tab'+num).text($('#formId' +num+ ' #tname').val()); + $("#formId"+num + " #properties_tab").hide(); } - - - } - - - function noRepeats(form){ - var select={}; - for(var i=0;i<form.length;i++){ - if(select[form[i].name]===undefined) - select[form[i].name]=[] - select[form[i].name].push(form[i].value); - } - var arr=[] - for(s in select){ - var f={} - f.name=s - f.value=select[s] - arr.push(f) - } - return arr - } + } $("#savePropsBtn").click(function(event) { - var form=[] - var properties=$(".saveProps").not("#formSpan .saveProps") - var topicP=$("#topicPublish").serializeArray() - form.push(topicP) - var d={} - d["serviceConfigurations"]=[]; - - for(var i=0;i<properties.length;i++){ - var ser=$(properties[i]).serializeArray(); - var s=noRepeats(ser) + var num = $('#nav_Tabs .active a').attr('id').slice(-1); + var tabs = []; + $('#nav_Tabs li:not(:last)').each(function(){ + tabs.push($(this).text()); + }); + var nonunique = uniquet(tabs); + if (($('#formId'+num+' #tcaTable .highlight').length > 0 ) && + (!($('#formId'+num+' #threshold').val()) || !($('#formId'+num+' #fieldPathM').val())) ) { + $('#formId'+num+' #tcaError').show(); + return; + } else if (nonunique){ + $('#formId'+num+' #tcaUnique').show(); + return; + } else { + $('#formId'+num+' .tcaErr').hide(); + if ($('#formId'+num+' #tcaTable .highlight').length > 0){ + $('#formId'+num+' #tcaTable .highlight td').text( + $('#formId'+num+' #fieldPathM').val() + ' ' + + $('#formId'+num+' #operator').val() + ' ' + + $('#formId'+num+' #threshold').val()); + } + var saveP = {}; + $('.formId').each(function(){ + var count = $(this).attr('id').slice(-1); + var header = $(this).find('.tcaParentItems').serializeArray(); + var sconf = {}; + var sconfa = []; + var checkNF = true; + $('#formId' +count+' #tcaTable tr').each(function(){ + $('td', this).each(function(){ + var splitTd = $(this).text().split(' '); + splitTd[1]=defaults_props['tca']['operator'][splitTd[1]]; + var checkByKpi = vf_Services["shared"]["byKpi"][splitTd[0].replace(/\s/g, "")]; + if (checkByKpi["fieldPath"]){ + splitTd.push(Object.keys(vf_Services["shared"]["byKpi"][splitTd[0].replace(/\s/g, "")]["fieldPath"])[0]); + }; + if ((checkByKpi["nfNamingCode"]) && (checkNF)){ + $.grep(header, function(e,i){ + if (e.name == "tnfc"){ + header[i]["value"] = (Object.keys(checkByKpi["nfNamingCode"])[0]); + } + }); + checkNF = false; + } + sconfa.push(splitTd); + }); + + }); + var polSel = $(this).find('.tcaParentItems #tcaPol').val(); + $.grep(header, function(e,i){ + if (e.name == "tcaPolId"){ + if (polSel){ + if (typeof allPolicies !== "undefined"){ + header[i]["value"] = allPolicies[polSel][1]["value"]; + } else if (typeof elementMap !== "undefined"){ + for (key in elementMap){ + if (key.indexOf("Policy")>-1){ + header[i]["value"] = elementMap[key][polSel][1]["value"]; + } + } + } + } else { + header[i]["value"]=""; + } + } + }); + + sconf["serviceConfigurations"]=sconfa; + header.push(sconf); + saveP[$(this).find('.tcaParentItems #tname').val()] = header; + }); - - d["serviceConfigurations"].push(s) + saveProperties(saveP); + $("#close_button").click(); } - form.push(d) - saveProperties(form) - - $("#close_button").click(); - }) + function uniquet(arr) { + var a = []; + for (var i=0, l=arr.length; i<l; i++){ + if (a.indexOf(arr[i]) === -1 && arr[i] !== ''){ + a.push(arr[i]); + } + } + if (a.length==arr.length){ + return false; + } else { + return true; + } + } function add_one_more(){ $("#nav_Tabs li").removeClass("active"); - var form=$($("#formSpan").children()[0]).clone() + var form=$($("#formSpan").children()[0]).clone(); var count=0; if($(".formId").length>0){ var greatest=0; @@ -297,96 +497,127 @@ } } count=greatest+1; - $("#properties_tab").append(('<span class="formId" id="formId'+count+'"></span>')); + $("#panelHolder").append(('<span class="formId" id="formId'+count+'"></span>')); }else{ count++; - $("#properties_tab").append('<span class="formId" id="formId1"></span>'); + $("#panelHolder").append('<span class="formId" id="formId1"></span>'); } - $("#add_one_more").parent().before(' <li class="active"><a id="go_properties_tab'+count+'">Condition</a><button id="tab_close'+count+'" type="button" class="close tab-close-popup" aria-hidden="true" style="margin-top: -30px;margin-right: 5px">×</button></li>'); + + $("#add_one_more").parent().before(' <li class="active"><a id="go_properties_tab'+count+'">New_Set</a><button id="tab_close'+count+'" type="button" class="close tab-close-popup" aria-hidden="true" style="margin-top: -30px;margin-right: 5px">×</button></li>'); $("#formId"+count).append(form); - $(".formId").not($("#formId"+count)).css("display","none") - addCustListen(count) - add_vfc_alarm_event_listener(count) + $('#formId'+count+ ' #properties_tab').hide(); + $(".formId").not($("#formId"+count)).css("display","none"); + addCustListen(count); + setMultiSelect(); return count; } - - function addCustListen(count) { + + function isNumberKey(event){ + var charCode = (event.which) ? event.which : event.keyCode + if (charCode > 31 && (charCode < 48 || charCode > 57)){ + return false; + } + return true; + }; + + function addCustListen(count) { $('#go_properties_tab' + count).click(function(event) { + if ($("#nav_Tabs li.active").length>0){ + var oldCount = $("#nav_Tabs li.active").find("a").attr("id").slice(-1); + if (($('#formId'+oldCount+' #tcaTable .highlight').length > 0 ) && + (!($('#formId'+oldCount+' #threshold').val()) || !($('#formId'+oldCount+' #fieldPathM').val())) ) { + $('#formId'+oldCount+' #tcaError').show(); + return; + } else { + $('#formId'+oldCount+' .tcaErr').hide(); + if ($('#formId'+oldCount+' #tcaTable .highlight').length > 0){ + $('#formId'+oldCount+' #tcaTable .highlight td').text( + $('#formId'+oldCount+' #fieldPathM').val() + ' ' + + $('#formId'+oldCount+' #operator').val() + ' ' + + $('#formId'+oldCount+' #threshold').val()); + } + $("#formId"+oldCount+" #tcaTable .highlight").removeClass("highlight") + } + } + $("#nav_Tabs li").removeClass("active"); $(this).parent().addClass("active"); - $("#formId"+count).css("display","") - $(".formId").not($("#formId"+count)).css("display","none") - - }) + $("#formId"+count).css("display",""); + $(".formId").not($("#formId"+count)).css("display","none"); + }); + $('#tab_close'+count).click(function(event){ - if(document.getElementById("topicPublishes").disabled){ - return false; - } $(this).parent().remove(); $("#formId"+count).remove(); - }) - } - -function setAlarmConditions(vfcID, count){ - var alarmCondition={} - - /*if($("#formId"+count+" #vfc").val()!=="") - alarmCondition=vf_Services['shared']['byVfc'][vfcID]['alarmCondition']*/ - - if($("#formId"+count+" #vfc").val()!==""){ - if(vf_Services && vf_Services['shared'] && vf_Services['shared']['byVfc'] && vf_Services['shared']['byVfc'][vfcID]){ - alarmCondition=vf_Services['shared']['byVfc'][vfcID]['alarmCondition']; - } - } - - $("#formId"+count+" #alarmCondition").empty(); - $("#formId"+count+" #alarmCondition").append("<option value=\"\"></opton>") - if(alarmCondition && _.keys(alarmCondition).length>0){ - for(key in alarmCondition){ - var safestring = $('<div>').text(key).html(); - $("#formId"+count+" #alarmCondition").append("<option value='"+safestring+"'>"+alarmCondition[key]+"</opton>") - - } - } - -} - -function setEventSourceType(alarm, count){ - var eventSourceTypSeverity={} - if($("#formId"+count+" #alarmCondition").val()!=="") { - if(vf_Services && vf_Services['shared'] && vf_Services['shared']['byAlarmCondition'] && vf_Services['shared']['byAlarmCondition'][alarm]){ - - eventSourceTypSeverity=vf_Services['shared']['byAlarmCondition'][alarm] - } - } - - $("#formId"+count+" #eventSourceType").val(eventSourceTypSeverity.eventSourceType); - $("#formId"+count+" #eventSeverity").val(eventSourceTypSeverity.eventSeverity); - -} - - function add_vfc_alarm_event_listener(count) { - - $("#formId"+count+" #vfc").on('focus', function () { - // Store the current value on focus and on change - previous = this.value; - }).change(function(){ - - setAlarmConditions($("#formId"+count+" #vfc").val(), count); - $("#formId"+count+" #eventSourceType").val(""); - $("#formId"+count+" #eventSeverity").val("") - - }); - - $("#formId"+count+" #alarmCondition").on('focus', function () { - // Store the current value on focus and on change - previous = this.value; - }).change(function(){ + }); + + $('#formId'+count+' #tcaTable').on('click', 'tr', function(event){ + if (($('#formId'+count+' #tcaTable .highlight').length > 0 ) && + (!($('#formId'+count+' #threshold').val()) || !($('#formId'+count+' #fieldPathM').val())) ) { + $('#formId'+count+' #tcaError').show(); + return; + } else { + $('#formId'+count+' .tcaErr').hide(); + if ($('#formId'+count+' #tcaTable .highlight').length > 0){ + $('#formId'+count+' #tcaTable .highlight td').text( + $('#formId'+count+' #fieldPathM').val() + ' ' + + $('#formId'+count+' #operator').val() + ' ' + + $('#formId'+count+' #threshold').val()); + } + //$('#formId'+count+' #tcaTable .highlight').text(); + $(this).addClass('highlight').siblings().removeClass('highlight'); + var str = $(this).text().split(' '); + $('#formId'+count + ' #properties_tab').show(); + if (str.length == 3){ + $('#formId'+count+' #fieldPathM').val(str[0]).multiselect('refresh'); + $('#formId'+count+' #operator').val(str[1]).multiselect('refresh'); + $('#formId'+count+' #threshold').val(str[2]); + } + if ((!(readOnly||readMOnly)) && ($('#formId'+count + ' #deleteThresh').prop('disabled'))) { + $('#formId'+count + ' #deleteThresh').prop('disabled', false); + } + } + }); + + $('#formId'+count+' #deleteThresh').on('click', function(){ + $('#formId'+num+' .tcaErr').hide(); + $('#formId'+count+ ' #properties_tab').hide(); + $('#formId'+count+ ' #tcaTable .highlight').remove(); + $('#formId'+count+ ' #deleteThresh').prop('disabled', true); + }); + + $('#formId'+count+' #createNewThresh').on('click', function(){ + if (($('#formId'+count+' #tcaTable .highlight').length > 0 ) && + (!($('#formId'+count+' #threshold').val()) || !($('#formId'+count+' #fieldPathM').val())) ){ + $('#formId'+count+' #tcaError').show(); + return; + } else { + $('#formId'+count+' .tcaErr').hide(); + if ($('#formId'+count+' #tcaTable .highlight').length > 0){ + $('#formId'+count+' #tcaTable .highlight td').text( + $('#formId'+count+' #fieldPathM').val() + ' ' + + $('#formId'+count+' #operator').val() + ' ' + + $('#formId'+count+' #threshold').val()); + } + $('#formId'+count+ ' #properties_tab').show(); + if (('#formId'+count+' #tcaTable .highlight').length > 0 ){ + $('#formId'+count+' #tcaTable tr.highlight').removeClass('highlight'); + } + $('#formId'+count+' #tcaTable').prepend('<tr class="highlight"><td>New Threshold</td></tr>'); + $('#formId'+count+' #fieldPathM').prop("selectedIndex", 0).multiselect('refresh'); + $('#formId'+count+' #operator').prop("selectedIndex", 0).multiselect('refresh'); + $('#formId'+count+' #threshold').val(""); - setEventSourceType($("#formId"+count+" #alarmCondition").val().toString(),count); - }); - }; + if ($('#formId'+count + ' #deleteThresh').prop('disabled')) { + $('#formId'+count + ' #deleteThresh').prop('disabled', false); + } + } + }); + + $('#formId'+count+' #tname').on('change',function(){ + $('#go_properties_tab'+count).text($('#formId'+count+' #tname').val()) + }); + } </script> -</div> - +</div>
\ No newline at end of file diff --git a/src/main/resources/META-INF/resources/designer/scripts/ActivityModellingCtrl.js b/src/main/resources/META-INF/resources/designer/scripts/ActivityModellingCtrl.js index 9529ad4f4..2fc3f7553 100644 --- a/src/main/resources/META-INF/resources/designer/scripts/ActivityModellingCtrl.js +++ b/src/main/resources/META-INF/resources/designer/scripts/ActivityModellingCtrl.js @@ -22,7 +22,7 @@ */ app.directive( "contextMenu", function($compile){ - console.log("contextMenu"); + contextMenu = {}; contextMenu.restrict = "AE"; contextMenu.link = function( lScope, lElem, lAttr ){ @@ -49,15 +49,14 @@ app.directive( "contextMenu", function($compile){ }); app.directive('ngRightClick', function($parse) { - console.log("ngRightClick"); - console.log("ngRightClick"); + return function(scope, element, attrs) { - console.log("returnfunction"); + var fn = $parse(attrs.ngRightClick); element.bind('contextmenu', function(event) { - console.log("contextmenu"); + scope.$apply(function() { - console.log("apply"); + event.preventDefault(); fn(scope, {$event:event}); }); @@ -66,16 +65,16 @@ app.directive('ngRightClick', function($parse) { }); app.directive('inputInfoClass', function ($compile) { - console.log("inputInfoClass"); + return { restrict: "C", replace: true, link: function(scope,element,attrs){ - console.log("link"); + var elementHTML = ''; scope.sourceExplorer = 'AM'; angular.forEach(scope.infoType.schemaElements, function(value, key){ - console.log("schemaElement"); + scope.schemaElement = value; @@ -122,12 +121,12 @@ app.directive('inputInfoClass', function ($compile) { }); app.directive('inputInfoClassMember', function ($compile, $timeout) { - console.log("inputInfoClassMember"); + return { restrict: "C", link: function(scope,element,attrs){ - console.log("link"); + var elementHTML = ''; @@ -254,17 +253,13 @@ app.directive('inputInfoClassMember', function ($compile, $timeout) { }); app.directive('expandable', function ($compile) { - console.log("expandable"); + return { restrict: "AE", link: function(scope,element,attrs){ - console.log("link"); + var elementHTML = ''; element.bind("click", function(){ - console.log("bindclick"); - //console.log('directive clicked!!!'); - //console.log(scope.sourceExplorer); - //console.log(scope.parKey); var test1 = document.getElementById(scope.parKey); @@ -273,8 +268,6 @@ app.directive('expandable', function ($compile) { var htmlCount = test1.getElementsByTagName('div').length; var schemaElementCount = scope.schemaElement.type.elements.length; - //console.log(htmlCount); - //console.log(schemaElementCount); if(htmlCount<schemaElementCount){ var x = angular.element(test1).append('<div class="inputInfoClassMember" style="margin-left: 10px" ng-repeat="schemaElement in schemaElement.type.elements" ng-init="currentElementName=schemaElement.element.name;parentName=parKey; parentElement=parElement; heirarchyLevel=heirLevel+1 ;"></div>'); @@ -290,9 +283,7 @@ app.directive('expandable', function ($compile) { if((cElements[i].getElementsByTagName('div') != null)&&(scope.schemaElement.type.elements != null)){ var htmlCount = cElements[i].getElementsByTagName('div').length; var schemaElementCount = scope.schemaElement.type.elements.length; - //console.log(htmlCount); - //console.log(schemaElementCount); - //console.log(cElements[i]); + if(htmlCount<schemaElementCount){ var x = ''; if(scope.sourceExplorer=='SDV'){ @@ -316,7 +307,7 @@ app.directive('expandable', function ($compile) { app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','dialogs', '$filter','Datafactory','soapRequestService', function($scope,$rootScope, $location,dialogs,$filter,Datafactory,soapRequestService){ - console.log("ActivityModellingCtrl"); + $scope.count=0; $scope.depth=0; $scope.parentElementList=[]; @@ -334,14 +325,12 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di $rootScope.initProjectExplorer = function () { - console.log("initProjectExplorer"); + if(map_model_repeatable_heirarchical_elements[selected_model] != null) { $rootScope.repeatableHeirarchicalElementMap = map_model_repeatable_heirarchical_elements[selected_model]; - ////console.log("$scope.repeatableHeirarchicalElementMap :: " + $rootScope.repeatableHeirarchicalElementMap); } - ////console.log("$rootScope.utmModelSchemaExtension :: " + JSON.stringify(list_model_schema_extensions[selected_model])); if(list_model_schema_extensions[selected_model] != null) { $scope.utmModelSchemaExtension = list_model_schema_extensions[selected_model]; if($scope.utmModelSchemaExtension.radioSelection == null || $scope.utmModelSchemaExtension.radioSelection == '') @@ -362,16 +351,12 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di console.log("requiredOnly"); for (var key in $scope.utmModelSchemaExtension.utmSchemaExtentionMap) { - ////console.log(key); - if ($scope.utmModelSchemaExtension.utmSchemaExtentionMap.hasOwnProperty(key)) { - //$scope.utmModelSchemaExtension.utmSchemaExtentionMap[key].checked = $scope.utmModelSchemaExtension.radioSelection == "Required Only" && $rootScope.requiredValues[key] != 0; $scope.utmModelSchemaExtension.utmSchemaExtentionMap[key].checked = $rootScope.requiredValues[key] != 0; } } angular.forEach($scope.utmModelSchemaExtension.utmSchemaExtentionMap, function(value, key) { console.log("forEach"); - //console.log(key + ': ' + value); }); }; @@ -400,17 +385,11 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di } }; -/* $scope.generatedXML = function(xmlValue){ - $scope.generatedXMLVal=xmlValue; - var dlg = dialogs.create('partials/portfolios/generatedXML.html','generateXMLCtrl',{},{size:'lg',keyboard: true,backdrop: true,windowClass: 'my-class'}); - - };*/ - //Functionality for Hierarchical Elements $scope.addHierarchicalElement1 = function(schemaElement, parentElement, elementKey, index){ console.log("addHeirarchicalElement1"); if($rootScope.isHorR){ - //console.log("Entering addHeirarchicalElement1"); + $scope.clonedSchemaElement={}; angular.copy(schemaElement, $scope.clonedSchemaElement); @@ -520,15 +499,13 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di if(schemaElement.type.complexType != null){ for(var i=0;i<$scope.childElements.length;i++){ if(angular.equals($scope.childElements[i],schemaElement)){ - //console.log("Complex Element List Match :" +$scope.childElements[i]); $scope.childElements.splice((i+1),0,$scope.clonedSchemaElement); break; } } } else if(schemaElement.element.name !=null) { for(var j=0;j<$scope.childElements.length;j++){ - if(angular.equals($scope.childElements[j],schemaElement)){ - //console.log("Element List Match :" +$scope.childElements[j]); + if(angular.equals($scope.childElements[j],schemaElement)){ $scope.childElements.splice((j+1),0,$scope.clonedSchemaElement); break; } @@ -591,24 +568,7 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di i++; }); }; - - /*$scope.renameModel = function(){ - console.log("renameModel"); - - console.log("renameModel"); - - var dlg = dialogs.create('partials/portfolios/rename_model.html','CreateModelCtrl',{},{size:'lg',keyboard: true,backdrop: true,windowClass: 'my-class'}); - dlg.result.then(function(name){ - console.log("dlg.result"); - - },function(){ - console.log("...empty"); - }); - - - };*/ - - + $scope.addRepeatableElement = function(schemaElement, parentElement, elementKey){ console.log("addRepeatableElement"); $rootScope.isHorR = false; @@ -727,17 +687,7 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di } } } - - /*if(parentElement.complexType != null){ - var index = parentElement.elements.indexOf(schemaElement); - parentElement.elements.splice(index, 1); - } - else{ - var index = parentElement.type.elements.indexOf(schemaElement); - parentElement.type.elements.splice(index, 1); - }*/ - - + if(list_model_repeatable_heirarchical_elements[selected_model] != null) { for(var i=0;i<list_model_repeatable_heirarchical_elements[selected_model].repeatableHeirachicalSchemaElements.length;i++){ @@ -753,7 +703,6 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di $scope.removeRepeatableHeirarchicalMap= function(modelName,repeatableHeirachicalSchemaElement,elementKey){ console.log("removeRepeatableHeirarchicalMap"); - //console.log("child element length:"+$scope.childElements.length); $scope.repeatableElements = repeatableHeirachicalSchemaElement.repeatableElements; $scope.heirarchicalElements = repeatableHeirachicalSchemaElement.heirarchicalElements; @@ -876,52 +825,4 @@ app.controller('ActivityModellingCtrl', ['$scope', '$rootScope', '$location','di } - - //Execute and display tst results - /*$scope.executeTst = function(index){ - console.log("executeTst"); - Datafactory.setSelectedTestCase($rootScope.modeltestset.activityTestCases[index]); - - var tstInput={}; - console.log("inside generateTST() method"); - var executeTSTUrl ="/utm-service/soa_integration/executeTST"; - var tempActivityTestcase= {}; - angular.copy(Datafactory.getSelectedTestCase(),tempActivityTestcase); - - tstInput.activityTestCase = tempActivityTestcase; - - if(tstInput.activityTestCase.version != null){ - var newTestCaseName = tstInput.activityTestCase.testCaseName + "_"+ tstInput.activityTestCase.version; - tstInput.activityTestCase.testCaseName = newTestCaseName; - - } - - tstInput.projectPreferenceInfo = Datafactory.getProjectPreferenceInfo(); - tstInput.environmentData = $rootScope.environmentData; - tstInput.writeFileToolList=Datafactory.getWriteFileDataList(); - tstInput.fileStreamWriterList=Datafactory.getFileStreamWriterList(); - tstInput.commonPythonScriptList = Datafactory.getCommonPythonScriptList(); - - - soapRequestService.generateTst(tstInput, executeTSTUrl) - .then(function(pars) { - console.log("pars"); - - if(pars != null || pars != undefined){ - - Datafactory.setExecuteResultset(pars); - - var dlg = dialogs.create('partials/SOA/execute-request.html','executeRequestCtrl',{},{size:'lg',keyboard: true,backdrop: true,windowClass: 'my-class'}); - } - else{ - dialogs.error("Some error occured during execution of tst file"); - } - - - }); - - - - - }*/ -}]); +}]);
\ No newline at end of file |