/*
* 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.
*/
/**
* This class provides a TreePanel for tags
* @private
*/
Ext.define('Ametys.plugins.cms.tag.TagsTreePanel', {
extend: 'Ext.tree.Panel',
scrollable: true,
animate: true,
rootVisible: false,
cls: 'tags-tree',
/**
* @protected
* @property {Ext.Template} _tagTooltipTpl The template used for tags' tooltip
*/
_tagTooltipTpl : Ext.create('Ext.XTemplate', [
'<tpl if="description && description != \'\'">',
'{description}<br/>',
'</tpl>',
'<u>{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_VISIBILITY}}</u> : <span style="white-space: nowrap">{visibility}</span><br/>',
'<tpl if="target && target != \'\'">',
'<u>{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_TARGET}}</u> : <span style="white-space: nowrap">{target}</span><br/>',
'</tpl>',
'<tpl if="isColorable">',
'<tpl if="color && color != \'\'">',
'<u>{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_COLOR}}</u> : <span class="{class}-tooltip-{color}" /><br/>',
'<tpl else>',
'<u>{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_COLOR}}</u> : <span class="{class}-tooltip-default" /><br/>',
'</tpl>',
'</tpl>'
]),
/**
* @protected
* @property {String} messageNoTagMatches Message when no tag matches
*/
messageNoTagMatches : "{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_NO_MATCH}}",
/**
* @protected
* @property {String} messageNoTagMatchesAction Message of the action to do when no tag matches
*/
messageNoTagMatchesAction : "{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_NO_MATCH_ACTION}}",
/**
* @cfg {String[]} [taggableObjects=null] The current object's ids to be tagged, used to check user rights on private tags. Can be null.
*/
taggableObjects: null,
/**
* @cfg {Boolean} checkMode To select tags by checkboxes. Defaults to 'false'.
*/
checkMode : false,
/**
* @cfg {String[]} values List of checkboxes name to check, if checkMode=true.
*/
values : [],
/**
* @cfg {Boolean} [allowCreation=false] 'true' to allow tag creation. Defaults to 'false'.
*/
allowCreation: false,
/**
* @cfg {Boolean} [allowProviders=false] 'true' to allow to select the tags providers. Defaults to 'false'.
*/
allowProviders: false,
/**
* @cfg {Boolean} [onlyTagsWithChildren=false] 'true' to allow to select only tags with children. Defaults to 'false'
*/
onlyTagsWithChildren: false,
/**
* @cfg {Boolean} [onlyCustomTags=false] 'true' to get only tags from the JCR provider
*/
onlyCustomTags: false,
/**
* @cfg {String} [targetType] The type of tag to display. Set to target type to display only matching tags. Set to null to display all tags
*/
targetType: null,
/**
* @cfg {String/String[]} filterTarget Filters on target type.
* Set to 'TARGET_TYPE' to disable tags with the target type.
* Set to 'TARGET_TYPE_PRIVATE' to disable private tags with the target type.
* Set to null or empty array to enable all tags.
*/
filterTarget: null,
/**
* @cfg {Object} [contextualParameters] Optional contextual parameters to be passed to the server requests. Will be merged with the current app parameters.
*/
contextualParameters: null,
/**
* @cfg {String} [tagModel] The tag model id
*/
tagModel: "Ametys.plugins.cms.tag.TagsTreePanel.TagNode",
/**
* @cfg {String} [tagsDAO] The tags DAO
*/
tagsDAO: "org.ametys.cms.tag.TagsDAO",
/**
* @cfg {String} [plugin="cms"] The plugin for the store.
*/
plugin: "cms",
/**
* @cfg {String} [url="tags.json"] The url for the store.
*/
url: 'tags.json',
/**
* @cfg {String} [toolbarFilterText="{{i18n PLUGINS_CMS_TAGS_TREE_FILTER}}"] The text inside the filter.
*/
toolbarFilterText: "{{i18n PLUGINS_CMS_TAGS_TREE_FILTER}}",
/**
* @cfg {String} [toolbarFilterInvalidText="{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_INVALID}}"] The message when the filter is invalid.
*/
toolbarFilterInvalidText: "{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_INVALID}}",
/**
* @cfg {String} [toolbarFilterClearText="{{i18n PLUGINS_CMS_TAGS_TREE_CLEAR_FILTER}}"] The tooltip to clear the filter.
*/
toolbarFilterClearText: "{{i18n PLUGINS_CMS_TAGS_TREE_CLEAR_FILTER}}",
/**
* @cfg {String} [toolbarFilterByCheckText="{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_BY_CHECK}}"] The tooltip to display only selected tags.
*/
toolbarFilterByCheckText: "{{i18n PLUGINS_CMS_TAGS_TREE_FILTER_BY_CHECK}}",
/**
* @cfg {String} [toolbarCollapseAllText="{{i18n PLUGINS_CMS_TAGS_TREE_COLLAPSE_ALL}}"] The tooltip to collapse all tags.
*/
toolbarCollapseAllText: "{{i18n PLUGINS_CMS_TAGS_TREE_COLLAPSE_ALL}}",
initComponent: function ()
{
this.filterTarget = Ext.Array.from(this.filterTarget);
Ext.apply(this, {
folderSort: false,
root: {
hasChild: true,
editable: false,
allowDrag: false,
allowDrop: false,
expanded: true,
name: 'tag-root',
id: 'tag-root',
type: 'tag-root',
iconCls : 'ametysicon-tag25'
},
store: this.createTreeStore(),
rootVisible: false
});
this.on('load', this._onLoad, this);
this.on('checkchange', this._onCheckChange, this);
this.on('itemexpand', this._onItemExpand, this);
this.on('viewready', this._onViewReady, this);
this.on('itemmouseenter', this._createQtip, this);
this.contextualParameters = Ext.applyIf(this.contextualParameters || {}, Ametys.getAppParameters());
this.callParent();
},
constructor: function(config)
{
config.rootVisible = config.rootVisible || false;
config.toolbarFilterText = config.toolbarFilterText || this.toolbarFilterText;
config.toolbarFilterInvalidText = config.toolbarFilterInvalidText || this.toolbarFilterInvalidText;
config.toolbarFilterClearText = config.toolbarFilterClearText || this.toolbarFilterClearText;
config.toolbarFilterByCheckText = config.toolbarFilterByCheckText || this.toolbarFilterByCheckText;
config.toolbarCollapseAllText = config.toolbarCollapseAllText || this.toolbarCollapseAllText;
this._counter = {};
config.dockedItems = this._getDockedItems(config);
this.callParent(arguments);
},
/**
* @protected
* Get the docked items
* @param {Object} config The initial tree panel configuration
* @return {Object[]} The docked items configuration
*/
_getDockedItems: function (config)
{
var dockedItems = config.dockedItems || [];
// No result panel
var topToolbarCfg = this._getTopToolbarCfg(config);
if (topToolbarCfg)
{
topToolbarCfg.dock = topToolbarCfg.dock || 'top';
dockedItems.push(topToolbarCfg);
}
var noResultPanelCfg = this._getNoResultPanelCfg();
if (noResultPanelCfg)
{
noResultPanelCfg.dock = noResultPanelCfg.dock || 'top';
dockedItems.push(noResultPanelCfg);
}
return dockedItems;
},
/**
* Set values
* @param [values] the tag names
*/
setValues: function (values)
{
this.values = values;
this._checkValuesExist();
var values = (Ext.isArray(this.values) ? this.values : [ this.values ]);
Ametys.data.ServerComm.callMethod({
role: this.tagsDAO,
methodName: 'getTagPaths',
parameters: [ values, Ametys.getAppParameters()],
errorMessage: "{{i18n PLUGINS_CMS_HANDLE_TAGS_TAG_ERROR}}",
callback: {
handler: this._getTagPathsCb,
ignoreOnError: false,
scope: this
},
waitMessage: {
target: this,
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
}
});
},
/**
* @private
* Callback function invoked after getting path of selected path.
* Selects or checks nodes.
* @param {String[]} paths The paths of selected tags.
*/
_getTagPathsCb: function(paths)
{
var me = this;
Ext.Array.each (paths, function (path) {
// don't expand last node
path = path.substr(0, path.lastIndexOf("/"));
me.expandNodeByPath(path, function (sucessfull, node) {
if (sucessfull)
{
if (me.multiple)
{
node.set('checked', true);
}
else
{
me.getSelectionModel().select(node);
}
}
});
});
},
/**
* @protected
* @param {Object} config The initial tree panel configuration
* Retrieves the 'no result' panel config
*/
_getNoResultPanelCfg: function(config)
{
return {
dock: 'top',
xtype: 'button',
hidden: true,
itemId: 'noresult',
ui: 'tool-hintmessage',
text: this.messageNoTagMatches + this.messageNoTagMatchesAction,
scope: this,
handler: this._clearSearchFilter
};
},
/**
* @protected
* Create the tree store
* @param {Object} config The tree panel configuration
* @return {Ext.data.TreeStore} The created tree store
*/
createTreeStore: function (config)
{
var store = Ext.create('Ext.data.TreeStore', {
model : this.tagModel,
proxy: {
type: 'ametys',
plugin: this.plugin,
url: this.url,
reader: {
type: 'json'
}
},
sorters: [{property: 'priority', direction:'DESC'}, {property: 'text', direction:'ASC'}]
});
store.addListener ('beforeload', this._onStoreBeforeLoad, this);
return store;
},
/**
* @private
* Listener for the view, set an interceptor on check for disabled node
*/
_onViewReady: function()
{
var view = this.getView();
// onCheckChange interceptor. When this function return false, the onCheckChange method of the view is not called, hence the value of the checkbox does not change.
var onCheckChangeInterceptor = function(event)
{
if (event.record.get('disabled') || event.record.get('authorized') === false)
{
return false;
}
};
Ext.apply(view, {
onCheckChange: Ext.Function.createInterceptor(view.onCheckChange, onCheckChangeInterceptor)
});
},
/**
* @private
* Set the request parameters before loading the store.
* @param {Ext.data.Store} store The store.
* @param {Ext.data.operation.Operation} operation The Ext.data.operation.Operation object that will be passed to the Proxy to load the Store.
*/
_onStoreBeforeLoad: function (store, operation)
{
var params = operation.getParams() || {};
Ext.apply(params, {
nodeName: (operation.node !== undefined ? operation.node.get('name') : ""),
checkMode: this.checkMode,
onlyCustomTags: this.onlyCustomTags,
objectTargetIds: this.taggableObjects,
targetType: this.targetType,
contextualParameters: this.contextualParameters
});
operation.setParams(params);
},
/**
* @private
* Function after tree loading
* @param {Ext.data.TreeStore} store The tree store
* @param {Ext.data.TreeModel[]} records The records
* @param {Boolean} successful True if the operation was successful.
* @param {Ext.data.Operation} operation The operation that triggered this load.
* @param {Ext.data.NodeInterface} node The loaded node
*/
_onLoad: function (store, records, successful, operation, node)
{
this._setInfos(node);
if (this.checkMode === true)
{
this._setCheckboxes(node);
}
this._checkValuesExist();
},
/**
* @private
* On node expand, filter nodes based on the "checked only" filter
* @param {Ext.data.NodeInterface} node the node expanded
*/
_onItemExpand: function(node)
{
if (this._checkFilter === true)
{
var childs = node.childNodes;
for (var i in childs)
{
if (Ext.Array.contains(this.values, childs[i].get('name')) === false)
{
var view = this.getView();
var uiNode = view ? view.getNodeByRecord(childs[i]) : null;
if (uiNode)
{
Ext.get(uiNode).setDisplayed('none');
}
}
}
}
},
/**
* @protected
* Retrieves the top toolbar config object.
* @param {Object} config The initial tree panel configuration
* @return {Boolean} config.checkMode if true, display the filter button "checked only"
*/
_getTopToolbarCfg: function(config)
{
return {
dock: 'top',
xtype: 'toolbar',
layout: {
type: 'hbox',
align: 'stretch'
},
border: false,
defaultType: 'button',
items: [{
// Search input
xtype: 'textfield',
cls: 'ametys',
flex: 1,
minWidth: 170,
maxWidth: 300,
itemId: 'search-filter-input',
emptyText: config.toolbarFilterText,
minLength: 3,
minLengthText: config.toolbarFilterInvalidText,
msgTarget: 'qtip',
listeners: {change: Ext.Function.createBuffered(this._searchFilter, 500, this)},
style: {
marginRight: '0px'
}
},
{
// Clear filter
tooltip: config.toolbarFilterClearText,
handler: Ext.bind (this._clearSearchFilter, this),
iconCls: 'a-btn-glyph ametysicon-eraser11 size-16',
cls: 'a-btn-light'
},
'->',
{
tooltip: config.toolbarFilterByCheckText,
enableToggle: true,
toggleHandler: Ext.bind(this._filterByCheckedNodes, this),
hidden: !config.checkMode,
iconCls: 'a-btn-glyph ametysicon-check51 size-16',
cls: 'a-btn-light'
},
{
// Collapse all
tooltip: config.toolbarCollapseAllText,
handler: Ext.bind (this._collapseAll, this),
iconCls: 'a-btn-glyph ametysicon-minus-sign4 size-16',
cls: 'a-btn-light'
}
]
};
},
/**
* This listener is called on 'keyup' event on filter input field.
* Filters the tree by text input.
* @param {Ext.form.Field} field The field
* @private
*/
_searchFilter: function (field)
{
var value = new String(field.getValue()).trim();
this._filterField = field;
if (this._filterValue == value)
{
// Do nothing
return;
}
this._filterValue = value;
if (this._checkFilter)
{
this._filterByCheckedNodes(null, true);
}
else if (value.length > 2)
{
this._getFilteredTags (value);
}
else
{
this.clearFilter(true);
}
},
/**
* Get the tags the name matches the given value
* @param {String} value The value to match
* @private
*/
_getFilteredTags: function (value)
{
Ametys.data.ServerComm.callMethod({
role: this.tagsDAO,
methodName: 'filterTagsByRegExp',
parameters: [value, Ametys.getAppParameters()],
errorMessage: "{{i18n PLUGINS_CMS_TAGS_TREE_SEARCH_ERROR}}",
callback: {
handler: this._filterTagsCb,
scope: this
}
});
},
/**
* @private
* Callback function after searching terms
* @param {String[]} paths The result paths
* @param {Object[]} args The callback arguments
*/
_filterTagsCb: function(paths, args)
{
var hasResult = false;
var rootNode = this.getRootNode();
if (!paths)
{
return;
}
if (paths.length == 0)
{
this.filterBy (function () {return false});
}
else
{
hasResult = true;
var childs = rootNode.childNodes;
this._expandAndFilter (paths, rootNode);
}
if (!hasResult)
{
this._showNoResultPanel();
if (this._filterField)
{
Ext.defer (this._filterField.markInvalid, 100, this._filterField, [this.messageNoTagMatches]);
}
}
else
{
this._hideNoResultPanel();
if (this._filterField)
{
this._filterField.clearInvalid();
}
}
},
/**
* Hide the panel showing there is no result.
* @private
*/
_hideNoResultPanel: function ()
{
var noResultPanel = this.getDockedItems('#noresult')[0];
if (noResultPanel)
{
noResultPanel.hide();
}
},
/**
* Show the panel showing there is no result.
* @private
*/
_showNoResultPanel: function ()
{
var noResultPanel = this.getDockedItems('#noresult')[0];
if (noResultPanel)
{
noResultPanel.show();
}
},
/**
* Clear the filter search
* @param {Ext.Button} btn The button
* @private
*/
_clearSearchFilter: function(btn)
{
this.clearFilter();
var topItems = this.getDockedItems('toolbar[dock="top"]');
topItems[topItems.length - 1].down('#search-filter-input').reset();
var selection = this.getSelectionModel().getSelection()[0];
if (selection)
{
this.ensureVisible(selection.getPath('name'), {field: 'name'});
}
},
/**
* Show the tree nodes without considering the filter value
* @param {Boolean} keepCheckFilter keep the "filter by checked node" toogled or not
*/
clearFilter: function(keepCheckFilter)
{
this.getStore().clearFilter();
this._hideNoResultPanel();
if (!keepCheckFilter)
{
this._checkFilter = false;
var topItems = this.getDockedItems('toolbar[dock="top"]');
var checkboxFilter = topItems.length > 0 ? topItems[topItems.length - 1].child("component[cls~=checkFilter]") : null;
if (checkboxFilter)
{
checkboxFilter.toggle(false);
}
}
},
/**
* Expand the tree to the given paths. Then filter nodes matching the given paths by calling the #_filterPaths method
* @param {Object[]} paths The paths to expand
* @param {Ext.data.Model} rootNode The concerned root node
* @param {Ext.data.Model} node The node from which apply filter
* @private
*/
_expandAndFilter: function(paths, rootNode, node)
{
node = node || rootNode;
this._counter[rootNode.getId()] = paths.length;
for (var i=0; i < paths.length; i++)
{
var path = paths[i].substr(0, paths[i].lastIndexOf("/"));
this.expandPath (rootNode.getPath('name') + '/' + path, 'name', null, Ext.bind (this._filterPaths, this, [paths, rootNode, node], false));
}
},
/**
* Filter nodes by path once the last expand has been processed
* @param {String[]} paths The path to filter by
* @param {Ext.data.Model} rootNode The concerned root node
* @param {Ext.data.Model} node The node from which apply filter
* @private
*/
_filterPaths: function (paths, rootNode, node)
{
// only execute the filterBy after the last expandPath()
if (--this._counter[rootNode.getId()] == 0)
{
var filterFn = Ext.bind (this._filterByPath, this, [paths, rootNode], true);
// FIXME Ensure that expand is complete by deferring the filterBy function ...
Ext.defer(this.filterBy, 50, this, [filterFn, node]);
}
},
/**
* Returns true if the node path is a part of given paths
* @param {Ext.data.Model} node The node to test
* @param {String[]} paths The paths
* @param {Ext.data.Model} rootNode The root node to build the complete paths
* @private
*/
_filterByPath: function (node, paths, rootNode)
{
var currentPath = node.getPath('name');
for (var i=0; i < paths.length; i++)
{
var path = rootNode.getPath('name') + '/' + paths[i] + '/';
if (path.indexOf(currentPath + '/') == 0)
{
return true;
}
}
return false;
},
/**
* Filters by a function. The specified function will be called for each Record in this Store.
* If the function returns true the Record is included, otherwise it is filtered out.
* @param {Function} filterFn A function to be called.
*/
filterBy: function (filterFn)
{
this.clearFilter();
this.getStore().filterBy(filterFn);
},
/**
* Triggered by the button "filter by checked only". Call the server to get the tags which matches the filter
* @param {Ext.button.Button} button The button which triggered this method. Parameter not used.
* @param {Boolean} state If true, filter by "checked only"
* @private
*/
_filterByCheckedNodes: function (button, state)
{
this._checkFilter = state;
var filterValue = "";
if (this._filterField !== undefined)
{
filterValue = new String(this._filterField.getValue()).trim();
}
if (filterValue && filterValue.length < 3)
{
filterValue = "";
}
if (filterValue === "" && state === false)
{
this.clearFilter();
}
else if (state === false)
{
Ametys.data.ServerComm.callMethod({
role: this.tagsDAO,
methodName: 'filterTagsByRegExp',
parameters: [filterValue, Ametys.getAppParameters()],
errorMessage: "{{i18n PLUGINS_CMS_TAGS_TREE_SEARCH_ERROR}}",
callback: {
handler: this._filterTagsCb,
scope: this
},
waitMessage: {
target: this,
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
}
});
}
else
{
Ametys.data.ServerComm.callMethod({
role: this.tagsDAO,
methodName: 'filterTagsFromListByRegExp',
parameters: [filterValue, this.values, Ametys.getAppParameters()],
errorMessage: "{{i18n PLUGINS_CMS_TAGS_TREE_SEARCH_ERROR}}",
callback: {
handler: this._filterTagsCb,
scope: this
},
waitMessage: {
target: this,
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_LOADMASK_DEFAULT_MESSAGE}}"
}
});
}
},
/**
* Collapse the whole tree
* @private
*/
_collapseAll: function ()
{
this.getRootNode().collapseChildren(true);
},
/**
* Load the root node
*/
onRender: function(ct, position)
{
this.callParent(arguments);
this.getRootNode().expand();
},
/**
* Iterate through the node childs, and call #_setInfo
* @param {Ext.data.Model} node The node to iterate
* @private
*/
_setInfos: function (node)
{
var childNodes = node.childNodes;
for (var i=0; i < childNodes.length; i++)
{
this._setInfo (childNodes[i]);
this._setInfos (childNodes[i]);
}
},
/**
* Initialize the node, by setting the tooltip and autoexpand the providers
* @param {Ext.data.Model} node The node to initialize
* @private
*/
_setInfo: function (node)
{
// auto expand providers
if (node.get('type') == 'provider')
{
this.expandNode(node);
}
if (this.filterTarget != null && this._isFilteredTarget(node))
{
node.set("disabled", true);
}
if (node.get("disabled") == true)
{
var cls = node.get('cls');
cls += (cls ? ' ' : '') + 'disabled';
node.set('cls', cls);
}
},
/**
* @private
* Destroy and create the node tooltip when the mouse enters the node
* @param {Ext.view.View} view The tree view
* @param {Ext.data.Model} node The tree node
* @param {HTMLElement} el The node's element
*/
_createQtip: function (view, node, el)
{
Ext.QuickTips.unregister(el);
Ext.QuickTips.register(Ext.apply({target: el, id: el.id + '-tooltip'}, this._getTooltip(node)));
},
/**
* Get the tooltip configuration
* @param {Ext.data.Model} node The tree node
* @returns {Object} The tooltip configuration. See Ametys.ui.fluent.Tooltip.
*/
_getTooltip: function(node)
{
var text = this._tagTooltipTpl.applyTemplate ({
description: (Ext.String.escapeHtml(node.get('description')) || "").replace(/\n/g, "<br/>"),
visibility : (node.get('visibility') == 'PRIVATE' ? "{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_VISIBILITY_PRIVATE}}" : "{{i18n PLUGINS_CMS_UITOOL_TAG_TOOLTIP_VISIBILITY_PUBLIC}}"),
target: node.get('target') && Ext.isObject(node.get('target')) ? node.get('target').label || node.get('target').name : null,
color: node.get('color'),
class: node.get('class'),
isColorable: node.get('isColorable')
});
return {
title: Ext.String.escapeHtml(node.get('title')) + " (" + node.get('name') + ")",
glyphIcon: node.get('tooltipIconCls'),
imageWidth: 48,
imageHeight: 48,
text: text,
inribbon: false
};
},
/**
* @private
* Check if a node match the specified filters for the target type
* @param {Ext.data.Model} node The node to initialize
* @return {Boolean} returns true if the filter is matched
*/
_isFilteredTarget: function(node)
{
for (var i = 0; i < this.filterTarget.length; i++)
{
var target = Ext.isObject(node.get('target')) ? node.get("target").name : node.get("target");
var filter = this.filterTarget[i];
if (target == filter || (node.get('visibility') == "PRIVATE" && target + "_PRIVATE" == filter))
{
return true;
}
}
return false;
},
/**
* Iterate through the children nodes, and call #_setCheckbox
* @param {Ext.data.Model} node The node to iterate
* @private
*/
_setCheckboxes: function (node)
{
var childNodes = node.childNodes;
for (var i=0; i < childNodes.length; i++)
{
this._setCheckbox (childNodes[i]);
this._setCheckboxes (childNodes[i]);
}
},
/**
* Put a checkbox on nodes that can be checked, with the corresponding state. Does not verify any rights.
* @param {Ext.data.Model} node The node
* @private
*/
_setCheckbox: function (node)
{
if ((this.allowProviders === true || node.get('type') !== 'provider') &&
(this.onlyTagsWithChildren === false || node.get('leaf') === false))
{
node.set('checked', Ext.Array.contains(this.values, node.get('name')));
}
else
{
node.set('checked', null);
}
},
/**
* Verify if a node can be checked. If it can, his value is updated
* @param {Ext.data.Model} node The node which state was updated
* @param {Boolean} checked The new node state
* @private
*/
_onCheckChange: function(node, checked)
{
if (node.get('disabled') === true)
{
node.set('checked', !checked);
return ;
}
if (checked === true && Ext.Array.contains(this.values, node.get('name')) === false)
{
this.values.push(node.get('name'));
}
else if (checked === false && Ext.Array.contains(this.values, node.get('name')) === true)
{
Ext.Array.remove(this.values, node.get('name'));
if (this._checkFilter === true)
{
this._filterByCheckedNodes(null, true);
}
}
},
/**
* Expand the tree to the given path.
* @param {String[]} path The path to expand
* @param {Function} callback The callback function to call after expand. Can be null.
*/
expandNodeByPath: function(path, callback)
{
var rootNode = this.getRootNode();
this.expandPath (rootNode.getPath('name') + '/' + path, 'name', null, callback);
},
/**
* @private
* Ensure that the values exists
*/
_checkValuesExist: function()
{
Ametys.data.ServerComm.callMethod({
role: this.tagsDAO,
methodName: 'checkTags',
parameters: [this.values, this.onlyCustomTags, {target: this.targetType}, this.contextualParameters],
callback: {
handler: this._checkValuesExistCb,
scope: this
}
});
},
/**
* @private
* Callback of #_checkValuesExist
* Updates the list of values
*/
_checkValuesExistCb: function (result)
{
if (result)
{
this.values = result;
}
}
});