/*
* Copyright 2016 Anyware Services
*
* 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.
*/
/**
* Tool that display the list of projects
* @private
*/
Ext.define('Ametys.plugins.workspaces.project.tool.ProjectsTool', {
extend: 'Ametys.tool.Tool',
constructor: function(config)
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onMessageCreatedOrModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onMessageCreatedOrModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onSiteModified, this);
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
createPanel: function()
{
this._store = Ext.create('Ext.data.Store', {
model: 'Ametys.plugins.workspaces.project.tool.ProjectsTool.ProjectEntry',
proxy: {
type: 'ametys',
role: 'org.ametys.plugins.workspaces.project.ProjectManager',
methodName: 'getProjectsForClientSide',
methodArguments: [],
reader: {
type: 'json'
}
},
sorters: [{property: 'title', direction: 'ASC'}]
});
this._grid = Ext.create('Ext.grid.Panel', {
stateful: true,
stateId: this.self.getName() + "$grid",
// Languages combo box
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
layout: {
type: 'hbox',
align: 'stretch'
},
border: false,
defaults : {
cls: 'ametys',
labelWidth: 55,
labelSeparator: ''
},
items: [{
// Search input
xtype: 'textfield',
itemId: 'search-filter-input',
cls: 'ametys',
flex: 1,
maxWidth: 300,
emptyText: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_FILTER_EMPTY_TEXT}}",
enableKeyEvents: true,
minLength: 3,
minLengthText: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_FILTER_MIN_LENGTH_INVALID}}",
msgTarget: 'qtip',
listeners: {change: Ext.Function.createBuffered(this._filterByTitle, 300, this)}
}, {
// Clear filter
tooltip: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_FILTER_CLEAR}}",
handler: Ext.bind (this._clearFilter, this),
iconCls: 'a-btn-glyph ametysicon-eraser11 size-16',
cls: 'a-btn-light'
}]
}],
store: this._store,
selModel: {
mode: 'SINGLE'
},
columns: [
{stateId: 'grid-column-title', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_TITLE}}", width: 200, sortable: true, dataIndex: 'title', renderer: Ametys.plugins.workspaces.project.tool.ProjectsGridHelper.renderTitle},
{stateId: 'grid-column-name', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_NAME}}", flex: 0.1, sortable: true, dataIndex: 'name', hidden: true},
{stateId: 'grid-column-description', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_DESCRIPTION}}", flex: 0.3, sortable: true, dataIndex: 'description', renderer: function (v) { return Ext.util.Format.nl2br(v.replace(/&/g, '&').replace(/</g, '<')) }},
{stateId: 'grid-column-categories', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_CATEGORIES}}", flex: 0.2, sortable: true, dataIndex: 'categories', renderer: this._renderTags},
{stateId: 'grid-column-tags', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_TAGS}}", flex: 0.2, sortable: true, dataIndex: 'tags', renderer: this._renderTags, hidden: true},
{stateId: 'grid-column-managers', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_MANAGERS}}", flex: 0.3, sortable: false, dataIndex: 'managers', renderer: Ametys.grid.GridColumnHelper.renderUser},
{stateId: 'grid-column-creationDate', header: "{{i18n PLUGINS_WORKSPACES_PROJECT_LIST_TOOL_COLUMN_CREATION}}", flex: 0.1, sortable: true, dataIndex: 'creationDate', xtype: 'datecolumn', format: Ext.Date.patterns.FriendlyDateTime}
],
listeners: {
'selectionchange': Ext.bind(this.sendCurrentSelection, this)
}
});
return this._grid;
},
/**
* @private
* Filters queries by input field value.
* @param {Ext.form.Field} field The field
*/
_filterByTitle: function (field)
{
var value = Ext.String.trim(field.getValue());
if (this._filterValue == value)
{
// Do nothing
return;
}
this._filterValue = value;
var regexFilter = new RegExp(value, 'i');
if (value.length > 2)
{
var currentSelection = this._grid.getSelection();
this._store.clearFilter();
this._store.filterBy(function(record){
return regexFilter.test(record.data.title) || regexFilter.test(record.data.name);
});
if (currentSelection.length > 0)
{
var me = this;
Ext.Array.each(currentSelection, function (sel) {
if (me._store.findExact(me._store.getModel().idProperty, sel.getId()) == -1)
{
// The current selection is not visible, clear the selection
me._grid.getSelectionModel().deselect([sel]);
}
})
}
}
else
{
// We do not call _clearFilter that will also empty the filter and prevent from typing
this._filterValue = null;
this._store.clearFilter();
}
},
/**
* Clear the current filter
*/
_clearFilter: function()
{
this._grid.down("#search-filter-input").reset();
this._filterValue = null;
this._store.clearFilter();
},
/**
* @private
* Renderer for tags
* @param {String} value the value
* @param {Object} metadata A collection of metadata about the current cell
* @param {Ext.data.Model} record The record for the current row
* @return {String} the html string used for the rendering of the label
*/
_renderTags: function(value, metadata, record)
{
var names = [];
Ext.Array.each(value, function (item, index) {
names.push(item.title);
})
return names.join(", ");
},
sendCurrentSelection: function()
{
var selection = this._grid.getSelectionModel().getSelection();
var targets = [];
for (var i = 0; i < selection.length; i++)
{
targets.push({
id: Ametys.message.MessageTarget.WORKSPACES_PROJECT,
parameters: {
id: selection[i].id
}
});
}
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: targets
});
},
setParams: function (params)
{
this.callParent(arguments);
this.refresh();
},
/**
* Refreshes the tool
*/
refresh: function ()
{
this.showRefreshing();
this._store.load({callback: this._refreshCb, scope: this});
},
/**
* Function invoked after loading the store
* @private
*/
_refreshCb: function ()
{
this.showRefreshed();
},
/**
* Listener on creation or edition message.
* @param {Ametys.message.Message} message The edition message.
* @private
*/
_onMessageCreatedOrModified: function(message)
{
var targets = message.getTargets(Ametys.message.MessageTarget.WORKSPACES_PROJECT);
if (targets.length > 0)
{
this.showOutOfDate();
}
},
/**
* Listener on deletion message.
* @param {Ametys.message.Message} message The deletion message.
* @private
*/
_onMessageDeleted: function(message)
{
var targets = message.getTargets(Ametys.message.MessageTarget.WORKSPACES_PROJECT);
for (var i = 0; i < targets.length; i++)
{
var record = this._store.getById(targets[i].getParameters().id);
this._store.remove(record);
}
},
/**
* @private
* Listener on project modification
* @param {Ametys.message.Message} message The edition message
*/
_onSiteModified: function(message)
{
var targets = message.getTargets(Ametys.message.MessageTarget.SITE);
if (targets.length > 0)
{
// ideally, we would like to check if the site correspond to a
// project, and if it is the case, just reload the project
this.showOutOfDate();
}
}
});