/*
* Copyright 2015 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 handles the access to node properties.
* See {@link Ametys.repository.RepositoryNode}.
*/
Ext.define('Ametys.repository.RepositoryDao',
{
singleton: true,
/**
* Retrieve a node by its id
* @param {String} path The node path. Cannot be null.
* * @param {String} workspaceName the jcr workspace name
* @param {Function} callback The callback function called when the node is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
* @param {Ametys.explorer.Resource} callback.node The node retrieved. Can be null if node does not exist.
* @param {Object} [errorMessage] The error message
* @return {Ametys.explorer.Resource} The node retrieved if no callback function is specified or null otherwise.
*/
getNode: function(path, workspaceName, callback, errorMessage)
{
if (Ext.isEmpty(path) || Ext.isEmpty(workspaceName))
{
callback(null);
return;
}
this._sendRequest([path], workspaceName, Ext.bind(this._getNodeCb, this, [callback], 1), errorMessage);
},
/**
* @private
* Callback function called after #getNode is processed
* @param {Ametys.explorer.Resource[]} nodes The nodes retrieved
* @param {Function} callback The callback function called
*/
_getNodeCb: function(nodes, callback)
{
callback((nodes.length == 0) ? null : nodes[0]);
},
/**
* Retrieve nodes by their ids
* @param {String[]} paths The nodes paths. Cannot be null.
* @param {String} workspaceName the jcr workspace name
* @param {Function} callback The callback function called when the node is retrieved. Can be null for synchronous mode (not recommended!). Parameters are
* @param {Ametys.explorer.Resource} callback.node The node retrieved. Can be null if node does not exist.
* @param {Object} [errorMessage] The error message
* @return {Ametys.explorer.Resource} The node retrieved if no callback function is specified or null otherwise.
*/
getNodes: function(paths, workspaceName, callback, errorMessage)
{
if (Ext.isEmpty(paths) || Ext.isEmpty(workspaceName))
{
callback([]);
return;
}
this._sendRequest(paths, workspaceName, Ext.bind(this._getNodesCb, this, [callback], 1), errorMessage);
},
/**
* @private
* Callback function called after #getNodes is processed
* @param {Ametys.explorer.Resource[]} nodes The nodes retrieved
* @param {Function} callback The callback function called
*/
_getNodesCb: function(nodes, callback)
{
callback(nodes);
},
/**
* Get the repository node store.
* @return {Ext.data.TreeStore} the repository node store.
*/
getNodeStore: function()
{
var store = Ext.getStore('Ametys.repository.data.RepositoryNodeStore');
if (store == null)
{
store = this._createNodeStore();
}
return store;
},
/**
* Create the repository node store.
* @return {Ext.data.TreeStore} the repository node store.
*/
_createNodeStore: function()
{
return Ext.create('Ext.data.TreeStore', {
model: 'Ametys.repository.data.RepositoryNode',
storeId: 'Ametys.repository.data.RepositoryNodeStore',
proxy: {
type: 'ametys',
workspace: 'repository',
url: 'repository/nodes',
reader: {
type: 'xml',
rootProperty: 'repository',
record: 'node/node,node/group'
}
},
root: {
text: "{{i18n workspace.repository:WORKSPACE_REPOSITORY_JCR_ROOT_NODE_TEXT}}",
iconCls: 'ametysicon-document28',
id: '/',
path: '',
type: 'node',
expanded: true
},
folderSort: true,
listeners: {
beforeload: {fn: this.onBeforeLoad, scope: this}
}
});
},
/**
* Add additional parameters to the Operation before loading the store.
* @param {Ext.data.TreeStore} store The tree store.
* @param {Ext.data.Operation} operation The operation object that will be passed to the Proxy to load the Store.
* @param {Object} eOpts Options added to the addListener
* @private
*/
onBeforeLoad: function(store, operation, eOpts)
{
var node = operation.node;
// Get the first node which is not a group.
var jcrNode = node;
while (jcrNode.isGroup())
{
jcrNode = jcrNode.parentNode;
}
var path = jcrNode.get('path');
var start = node.get('start');
var end = node.get('end');
var params = {};
params.workspaceName = Ametys.repository.RepositoryApp.getCurrentWorkspace() || 'default';
params.path = path.substring(1);
if (start && end)
{
params.start = start;
params.end = end;
}
if (jcrNode.get('order') != null)
{
params.order = jcrNode.get('order');
}
operation.setParams(params);
},
/**
* @private
* Send request to server to retrieved nodes
* @param {String[]} paths The path of nodes to retrieve
* @param {String} workspaceName the jcr workspace name
* @param {Function} callback The callback function to be called after server process
* @param {Object} [errorMessage] The error message
*/
_sendRequest: function(paths, workspaceName, callback, errorMessage)
{
if (errorMessage === undefined)
{
errorMessage = "{{i18n plugin.repositoryapp:PLUGINS_REPOSITORYAPP_REPOSITORY_DAO_GET_NODES_ERROR}}";
}
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.workspaces.repository.jcr.RepositoryDao',
methodName: 'getNodesByPath',
parameters: [paths, workspaceName],
callback: {
handler: this._sendRequestCb,
scope: this,
arguments: {callback: callback, silent: errorMessage === false}
},
errorMessage: errorMessage
});
},
/**
* @private
* Callback function called after #_sendRequest is processed
* @param {Object} result The node retrieval result (found and not found).
* @param {Object} arguments The callback arguments.
*/
_sendRequestCb: function(result, arguments)
{
var objects = [];
for (var i=0; i < result.nodes.length; i++)
{
objects.push(Ext.create('Ametys.repository.RepositoryNode', result.nodes[i]));
}
var objectsNotFound = result.notFound;
if (objectsNotFound.length > 0
&& !arguments.silent) // skip error message
{
Ametys.log.ErrorDialog.display({
title: "{{i18n plugin.repositoryapp:PLUGINS_REPOSITORYAPP_REPOSITORY_DAO_NODES_NOT_FOUND_TITLE}}",
text: "{{i18n plugin.repositoryapp:PLUGINS_REPOSITORYAPP_REPOSITORY_DAO_NODES_NOT_FOUND_MESSAGE}}",
details: "{{i18n plugin.repositoryapp:PLUGINS_REPOSITORYAPP_REPOSITORY_DAO_NODES_NOT_FOUND_DETAILS}}\n" + objectsNotFound.join('\n'),
category: 'Ametys.repository.RepositoryDao'
});
}
if (typeof arguments.callback == 'function')
{
arguments.callback(objects);
}
}
});
/**
* Model for repository node.
* @private
*/
Ext.define('Ametys.repository.data.RepositoryNode', {
extend: 'Ext.data.TreeModel',
fields: [
{name: 'text', mapping: '@name'},
{name: 'name', mapping: '@name'},
{name: 'parentPath', mapping: '@parentPath'},
{name: 'nodePath', mapping: '@path'}, // Only on groups, indicates the path of the "real" node.
{name: 'type', mapping: '@type'},
{name: 'index', mapping: '@index'},
{name: 'hasOrderableChildNodes', mapping: '@hasOrderableChildNodes', type: 'boolean'},
{name: 'order'},
{name: 'start', mapping: '@start'},
{name: 'end', mapping: '@end'},
{name: 'isNew', mapping: '@isNew', type: 'boolean'},
{name: 'isModified', mapping: '@isModified', type: 'boolean'},
{name: 'loaded', mapping: '@noChild', type: 'boolean' },
{
name: 'path',
calculate: function(data) {
if (data.id == '/') {
return '';
}
else if (data.type == 'group') {
// Useless for groups but calculate anyway.
return data.nodePath + '/' + data.name;
}
else if (data.parentPath == '/') {
return '/' + data.name;
}
else {
return data.parentPath + '/' + data.name;
}
}
},
{
name: 'iconCls',
depends: ['type', 'isNew', 'isModified'],
calculate: function(data)
{
if (data.type == 'group') {
return 'a-tree-glyph ametysicon-file98';
}
else if (data.root) {
return 'a-tree-glyph ametysicon-document28';
}
else if (data.isNew || data.isModified) {
return 'a-tree-glyph ametysicon-document112 decorator-ametysicon-clock56';
}
else {
return 'a-tree-glyph ametysicon-document112';
}
}
},
{
name: 'cls',
calculate: function(data) {
if (data.isNew || data.isModified) {
return 'jcr-tree-node-new';
}
return '';
}
}
],
/**
* Test if the tree node is a JCR node (and not a node group).
* @return {Boolean} True if the tree node is a real JCR node, false if it's a group.
*/
isNode: function()
{
return this.get('type') == 'node';
},
/**
* Test if the tree node is a node group.
* @return {Boolean} True if the tree node is a node group, false if it's a real JCR node.
*/
isGroup: function()
{
return this.get('type') == 'group';
}
});