aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/components/SelectList/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/components/SelectList/index.js')
-rw-r--r--server/sonar-web/src/main/js/components/SelectList/index.js450
1 files changed, 450 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/components/SelectList/index.js b/server/sonar-web/src/main/js/components/SelectList/index.js
new file mode 100644
index 00000000000..b02014c4015
--- /dev/null
+++ b/server/sonar-web/src/main/js/components/SelectList/index.js
@@ -0,0 +1,450 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import $ from 'jquery';
+import _ from 'underscore';
+import Backbone from 'backbone';
+import { translate } from '../../helpers/l10n';
+import ItemTemplate from './templates/item.hbs';
+import ListTemplate from './templates/list.hbs';
+
+var showError = null;
+
+/*
+ * SelectList Collection
+ */
+
+var SelectListCollection = Backbone.Collection.extend({
+
+ initialize: function (options) {
+ this.options = options;
+ },
+
+ parse: function (r) {
+ return this.options.parse.call(this, r);
+ },
+
+ fetch: function (options) {
+ var data = $.extend({
+ page: 1,
+ pageSize: 100
+ }, options.data || {}),
+ settings = $.extend({}, options, { data: data });
+
+ this.settings = {
+ url: settings.url,
+ data: data
+ };
+
+ Backbone.Collection.prototype.fetch.call(this, settings);
+ },
+
+ fetchNextPage: function (options) {
+ if (this.more) {
+ var nextPage = this.settings.data.page + 1,
+ settings = $.extend(this.settings, options);
+
+ settings.data.page = nextPage;
+ settings.remove = false;
+ this.fetch(settings);
+ } else {
+ options.error();
+ }
+ }
+
+});
+
+
+/*
+ * SelectList Item View
+ */
+
+var SelectListItemView = Backbone.View.extend({
+ tagName: 'li',
+ template: ItemTemplate,
+
+ events: {
+ 'change .select-list-list-checkbox': 'toggle'
+ },
+
+ initialize: function (options) {
+ this.listenTo(this.model, 'change', this.render);
+ this.settings = options.settings;
+ },
+
+ render: function () {
+ this.$el.html(this.template(this.settings.format(this.model.toJSON())));
+ this.$('input').prop('name', this.model.get('name'));
+ this.$el.toggleClass('selected', this.model.get('selected'));
+ this.$('.select-list-list-checkbox')
+ .prop('title',
+ this.model.get('selected') ?
+ this.settings.tooltips.deselect :
+ this.settings.tooltips.select)
+ .prop('checked', this.model.get('selected'));
+
+ if (this.settings.readOnly) {
+ this.$('.select-list-list-checkbox').prop('disabled', true);
+ }
+ },
+
+ remove: function (postpone) {
+ if (postpone) {
+ var that = this;
+ that.$el.addClass(this.model.get('selected') ? 'added' : 'removed');
+ setTimeout(function () {
+ Backbone.View.prototype.remove.call(that, arguments);
+ }, 500);
+ } else {
+ Backbone.View.prototype.remove.call(this, arguments);
+ }
+ },
+
+ toggle: function () {
+ var selected = this.model.get('selected'),
+ that = this,
+ url = selected ? this.settings.deselectUrl : this.settings.selectUrl,
+ data = $.extend({}, this.settings.extra || {});
+
+ data[this.settings.selectParameter] = this.model.get(this.settings.selectParameterValue);
+
+ that.$el.addClass('progress');
+ $.ajax({
+ url: url,
+ type: 'POST',
+ data: data,
+ statusCode: {
+ // do not show global error
+ 400: null,
+ 401: null,
+ 403: null,
+ 500: null
+ }
+ })
+ .done(function () {
+ that.model.set('selected', !selected);
+ })
+ .fail(function (jqXHR) {
+ that.render();
+ showError(jqXHR);
+ })
+ .always(function () {
+ that.$el.removeClass('progress');
+ });
+ }
+});
+
+
+/*
+ * SelectList View
+ */
+
+var SelectListView = Backbone.View.extend({
+ template: ListTemplate,
+
+ events: {
+ 'click .select-list-control-button[name=selected]': 'showSelected',
+ 'click .select-list-control-button[name=deselected]': 'showDeselected',
+ 'click .select-list-control-button[name=all]': 'showAll'
+ },
+
+ initialize: function (options) {
+ this.listenTo(this.collection, 'add', this.renderListItem);
+ this.listenTo(this.collection, 'reset', this.renderList);
+ this.listenTo(this.collection, 'remove', this.removeModel);
+ this.listenTo(this.collection, 'change:selected', this.confirmFilter);
+ this.settings = options.settings;
+
+ var that = this;
+ this.showFetchSpinner = function () {
+ that.$listContainer.addClass('loading');
+ };
+ this.hideFetchSpinner = function () {
+ that.$listContainer.removeClass('loading');
+ };
+
+ var onScroll = function () {
+ that.showFetchSpinner();
+
+ that.collection.fetchNextPage({
+ success: function () {
+ that.hideFetchSpinner();
+ },
+ error: function () {
+ that.hideFetchSpinner();
+ }
+ });
+ };
+ this.onScroll = _.throttle(onScroll, 1000);
+ },
+
+ render: function () {
+ var that = this,
+ keyup = function () {
+ that.search();
+ };
+
+ this.$el.html(this.template(this.settings.labels))
+ .width(this.settings.width);
+
+ this.$listContainer = this.$('.select-list-list-container');
+ if (!this.settings.readOnly) {
+ this.$listContainer
+ .height(this.settings.height)
+ .css('overflow', 'auto')
+ .on('scroll', function () {
+ that.scroll();
+ });
+ } else {
+ this.$listContainer.addClass('select-list-list-container-readonly');
+ }
+
+ this.$list = this.$('.select-list-list');
+
+ var searchInput = this.$('.select-list-search-control input')
+ .on('keyup', _.debounce(keyup, 250))
+ .on('search', _.debounce(keyup, 250));
+
+ if (this.settings.focusSearch) {
+ setTimeout(function () {
+ searchInput.focus();
+ }, 250);
+ }
+
+ this.listItemViews = [];
+
+ showError = function (jqXHR) {
+ var message = translate('default_error_message');
+ if (jqXHR != null && jqXHR.responseJSON != null && jqXHR.responseJSON.errors != null) {
+ message = _.pluck(jqXHR.responseJSON.errors, 'msg').join('. ');
+ }
+
+ that.$el.prevAll('.alert').remove();
+ $('<div>')
+ .addClass('alert alert-danger').text(message)
+ .insertBefore(that.$el);
+ };
+
+ if (this.settings.readOnly) {
+ this.$('.select-list-control').remove();
+ }
+ },
+
+ renderList: function () {
+ this.listItemViews.forEach(function (view) {
+ view.remove();
+ });
+ this.listItemViews = [];
+ if (this.collection.length > 0) {
+ this.collection.each(this.renderListItem, this);
+ } else {
+ if (this.settings.readOnly) {
+ this.renderEmpty();
+ }
+ }
+ this.$listContainer.scrollTop(0);
+ },
+
+ renderListItem: function (item) {
+ var itemView = new SelectListItemView({
+ model: item,
+ settings: this.settings
+ });
+ this.listItemViews.push(itemView);
+ this.$list.append(itemView.el);
+ itemView.render();
+ },
+
+ renderEmpty: function () {
+ this.$list.append('<li class="empty-message">' + this.settings.labels.noResults + '</li>');
+ },
+
+ confirmFilter: function (model) {
+ if (this.currentFilter !== 'all') {
+ this.collection.remove(model);
+ }
+ },
+
+ removeModel: function (model, collection, options) {
+ this.listItemViews[options.index].remove(true);
+ this.listItemViews.splice(options.index, 1);
+ },
+
+ filterBySelection: function (filter) {
+ var that = this;
+ filter = this.currentFilter = filter || this.currentFilter;
+
+ if (filter != null) {
+ this.$('.select-list-check-control').toggleClass('disabled', false);
+ this.$('.select-list-search-control').toggleClass('disabled', true);
+ this.$('.select-list-search-control input').val('');
+
+ this.$('.select-list-control-button').removeClass('active')
+ .filter('[name=' + filter + ']').addClass('active');
+
+ this.showFetchSpinner();
+
+ this.collection.fetch({
+ url: this.settings.searchUrl,
+ reset: true,
+ data: { selected: filter },
+ success: function () {
+ that.hideFetchSpinner();
+ },
+ error: showError
+ });
+ }
+ },
+
+ showSelected: function () {
+ this.filterBySelection('selected');
+ },
+
+ showDeselected: function () {
+ this.filterBySelection('deselected');
+ },
+
+ showAll: function () {
+ this.filterBySelection('all');
+ },
+
+ search: function () {
+ var query = this.$('.select-list-search-control input').val(),
+ hasQuery = query.length > 0,
+ that = this,
+ data = {};
+
+ this.$('.select-list-check-control').toggleClass('disabled', hasQuery);
+ this.$('.select-list-search-control').toggleClass('disabled', !hasQuery);
+
+ if (hasQuery) {
+ this.showFetchSpinner();
+ this.currentFilter = 'all';
+
+ data[this.settings.queryParam] = query;
+ data.selected = 'all';
+ this.collection.fetch({
+ url: this.settings.searchUrl,
+ reset: true,
+ data: data,
+ success: function () {
+ that.hideFetchSpinner();
+ },
+ error: showError
+ });
+ } else {
+ this.filterBySelection();
+ }
+ },
+
+ searchByQuery: function (query) {
+ this.$('.select-list-search-control input').val(query);
+ this.search();
+ },
+
+ clearSearch: function () {
+ this.filterBySelection();
+ },
+
+ scroll: function () {
+ var scrollBottom = this.$listContainer.scrollTop() >=
+ this.$list[0].scrollHeight - this.$listContainer.outerHeight();
+
+ if (scrollBottom && this.collection.more) {
+ this.onScroll();
+ }
+ }
+
+});
+
+
+/*
+ * SelectList Entry Point
+ */
+
+window.SelectList = function (options) {
+ this.settings = $.extend(window.SelectList.defaults, options);
+
+ this.collection = new SelectListCollection({
+ parse: this.settings.parse
+ });
+
+ this.view = new SelectListView({
+ el: this.settings.el,
+ collection: this.collection,
+ settings: this.settings
+ });
+
+ this.view.render();
+ this.filter('selected');
+ return this;
+};
+
+
+/*
+ * SelectList API Methods
+ */
+
+window.SelectList.prototype.filter = function (filter) {
+ this.view.filterBySelection(filter);
+ return this;
+};
+
+window.SelectList.prototype.search = function (query) {
+ this.view.searchByQuery(query);
+ return this;
+};
+
+
+/*
+ * SelectList Defaults
+ */
+
+window.SelectList.defaults = {
+ width: '50%',
+ height: 400,
+
+ readOnly: false,
+ focusSearch: true,
+
+ format: function (item) {
+ return item.value;
+ },
+
+ parse: function (r) {
+ this.more = r.more;
+ return r.results;
+ },
+
+ queryParam: 'query',
+
+ labels: {
+ selected: 'Selected',
+ deselected: 'Deselected',
+ all: 'All',
+ noResults: ''
+ },
+
+ tooltips: {
+ select: 'Click this to select item',
+ deselect: 'Click this to deselect item'
+ },
+
+ errorMessage: 'Something gone wrong, try to reload the page and try again.'
+};