diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.ftl
new file mode 100644
index 0000000000..29c1c15fe5
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.ftl
@@ -0,0 +1,25 @@
+<#macro resultsJSON results>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "totalResults": ${results?size},
+ "overallSuccess": ${overallSuccess?string},
+ "successCount": ${successCount},
+ "failureCount": ${failureCount},
+ "results":
+ [
+ <#list results as r>
+ {
+ <#list r?keys as key>
+ <#assign value = r[key]>
+ <#if value?is_number || value?is_boolean>
+ "${key}": ${value?string}<#if key_has_next>,#if>
+ <#else>
+ "${key}": "${value}"<#if key_has_next>,#if>
+ #if>
+ #list>
+ }<#if r_has_next>,#if>
+ #list>
+ ]
+}
+ #escape>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.js
new file mode 100644
index 0000000000..815eeb45dc
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/action.lib.js
@@ -0,0 +1,181 @@
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Data List Component: action
+ *
+ * For a single-asset action, template paramters address the item.
+ * For multi-item actions, optional template parameters address the source or destination node,
+ * and a JSON body addresses the items involved in the action.
+ *
+ * @param uri {string} node/{store_type}/{store_id}/{id}
+ */
+
+/**
+ * Main script entry point
+ * @method main
+ */
+function main()
+{
+ var nodeRef = null,
+ rootNode = null,
+ params = {};
+
+ if (url.templateArgs.store_type !== null)
+ {
+ /**
+ * nodeRef input: store_type, store_id and id
+ */
+ var storeType = url.templateArgs.store_type,
+ storeId = url.templateArgs.store_id,
+ id = url.templateArgs.id;
+
+ nodeRef = storeType + "://" + storeId + "/" + id;
+ rootNode = resolveVirtualNodeRef(nodeRef);
+ if (rootNode == null)
+ {
+ rootNode = search.findNode(nodeRef);
+ if (rootNode === null)
+ {
+ status.setCode(status.STATUS_NOT_FOUND, "Not a valid nodeRef: '" + nodeRef + "'");
+ return null;
+ }
+ }
+
+ params.nodeRef = nodeRef;
+ params.rootNode = rootNode;
+ }
+
+ // Multiple input files in the JSON body?
+ var items = getMultipleInputValues("nodeRefs");
+ if (typeof items != "string")
+ {
+ params.items = items;
+ }
+
+ // Check runAction function is provided the action's webscript
+ if (typeof runAction != "function")
+ {
+ status.setCode(status.STATUS_BAD_REQUEST, "Action webscript must provide runAction() function.");
+ return;
+ }
+
+ // Actually run the action
+ var results = runAction(params);
+ if (results)
+ {
+ if (typeof results == "string")
+ {
+ status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, results);
+ }
+ else if (typeof results.status == "object")
+ {
+ // Status fields have been manually set
+ status.redirect = true;
+ for (var s in results.status)
+ {
+ status[s] = results.status[s];
+ }
+ }
+ else
+ {
+ /**
+ * NOTE: Webscripts run within one transaction only.
+ * If a single operation fails, the transaction is marked for rollback and all
+ * previous (successful) operations are also therefore rolled back.
+ * We therefore need to scan the results for a failed operation and mark the entire
+ * set of operations as failed.
+ */
+ var overallSuccess = true,
+ successCount = 0,
+ failureCount = 0;
+
+ for (var i = 0, j = results.length; i < j; i++)
+ {
+ overallSuccess = overallSuccess && results[i].success;
+ results[i].success ? ++successCount : ++failureCount;
+ }
+ model.overallSuccess = overallSuccess;
+ model.successCount = successCount;
+ model.failureCount = failureCount;
+ model.results = results;
+ }
+ }
+}
+
+/**
+ * Resolve "virtual" nodeRefs into nodes
+ *
+ * @method resolveVirtualNodeRef
+ * @param virtualNodeRef {string} nodeRef
+ * @return {ScriptNode|null} Node corresponding to supplied virtual nodeRef. Returns null if supplied nodeRef isn't a "virtual" type
+ */
+resolveVirtualNodeRef: function ParseArgs_resolveVirtualNodeRef(nodeRef)
+{
+ var node = null;
+ if (nodeRef == "alfresco://company/home")
+ {
+ node = companyhome;
+ }
+ else if (nodeRef == "alfresco://user/home")
+ {
+ node = userhome;
+ }
+ else if (nodeRef == "alfresco://sites/home")
+ {
+ node = companyhome.childrenByXPath("st:sites")[0];
+ }
+ return node;
+}
+
+/**
+ * Get multiple input values
+ *
+ * @method getMultipleInputValues
+ * @return {array|string} Array containing multiple values, or string error
+ */
+function getMultipleInputValues(param)
+{
+ var values = [],
+ error = null;
+
+ try
+ {
+ // Was a JSON parameter list supplied?
+ if (typeof json != "undefined")
+ {
+ if (!json.isNull(param))
+ {
+ var jsonValues = json.get(param);
+ // Convert from JSONArray to JavaScript array
+ for (var i = 0, j = jsonValues.length(); i < j; i++)
+ {
+ values.push(jsonValues.get(i));
+ }
+ }
+ }
+ }
+ catch(e)
+ {
+ error = e.toString();
+ }
+
+ // Return the values array, or the error string if it was set
+ return (error !== null ? error : values);
+}
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.desc.xml
new file mode 100644
index 0000000000..243f9add69
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.desc.xml
@@ -0,0 +1,8 @@
+
+ duplicate
+ Data List Action - Duplicate single or multiple items
+ /slingshot/datalists/action/duplicate/node/{store_type}/{store_id}/{id}
+ argument
+ user
+ required
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.ftl
new file mode 100644
index 0000000000..e2f0e9da9f
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.ftl
@@ -0,0 +1,2 @@
+<#import "action.lib.ftl" as actionLib />
+<@actionLib.resultsJSON results=results />
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.js
new file mode 100644
index 0000000000..fbc8080ad8
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/duplicate.post.json.js
@@ -0,0 +1,77 @@
+
+
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Duplicate multiple items action
+ * @method POST
+ */
+
+/**
+ * Entrypoint required by action.lib.js
+ *
+ * @method runAction
+ * @param p_params {object} Object literal containing items array
+ * @return {object|null} object representation of action results
+ */
+function runAction(p_params)
+{
+ var results = [],
+ items = p_params.items,
+ item, result, nodeRef;
+
+ // Must have array of items
+ if (!items || items.length == 0)
+ {
+ status.setCode(status.STATUS_BAD_REQUEST, "No items.");
+ return;
+ }
+
+ for (item in items)
+ {
+ nodeRef = items[item];
+ result =
+ {
+ nodeRef: nodeRef,
+ action: "duplicateItem",
+ success: false
+ }
+
+ try
+ {
+ itemNode = search.findNode(nodeRef);
+ if (itemNode != null)
+ {
+ // TODO: DUPLICATE NODE
+ }
+ }
+ catch (e)
+ {
+ result.success = false;
+ }
+
+ results.push(result);
+ }
+
+ return results;
+}
+
+/* Bootstrap action script */
+main();
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.desc.xml
new file mode 100644
index 0000000000..66d1385765
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.desc.xml
@@ -0,0 +1,8 @@
+
+ files
+ Data List Action - Delete single or multiple items
+ /slingshot/datalists/action/items
+ argument
+ user
+ required
+
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.ftl
new file mode 100644
index 0000000000..e2f0e9da9f
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.ftl
@@ -0,0 +1,2 @@
+<#import "action.lib.ftl" as actionLib />
+<@actionLib.resultsJSON results=results />
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.js
new file mode 100644
index 0000000000..de5df33a63
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/action/items.delete.json.js
@@ -0,0 +1,77 @@
+
+
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Delete multiple items action
+ * @method DELETE
+ */
+
+/**
+ * Entrypoint required by action.lib.js
+ *
+ * @method runAction
+ * @param p_params {object} Object literal containing items array
+ * @return {object|null} object representation of action results
+ */
+function runAction(p_params)
+{
+ var results = [],
+ items = p_params.items,
+ item, result, nodeRef;
+
+ // Must have array of items
+ if (!items || items.length == 0)
+ {
+ status.setCode(status.STATUS_BAD_REQUEST, "No items.");
+ return;
+ }
+
+ for (item in items)
+ {
+ nodeRef = items[item];
+ result =
+ {
+ nodeRef: nodeRef,
+ action: "deleteItem",
+ success: false
+ }
+
+ try
+ {
+ itemNode = search.findNode(nodeRef);
+ if (itemNode != null)
+ {
+ result.success = itemNode.remove();
+ }
+ }
+ catch (e)
+ {
+ result.success = false;
+ }
+
+ results.push(result);
+ }
+
+ return results;
+}
+
+/* Bootstrap action script */
+main();
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.desc.xml
new file mode 100644
index 0000000000..b85fd1ee9a
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.desc.xml
@@ -0,0 +1,9 @@
+
+ DataLists - Data retrieval
+ Data Lists Component - retrieve data within a given list
+ /slingshot/datalists/data/site/{site}/{container}/{list}
+ /slingshot/datalists/data/node/{store_type}/{store_id}/{id}
+ argument
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.ftl
new file mode 100644
index 0000000000..95d7957faf
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.ftl
@@ -0,0 +1,36 @@
+<#import "item.lib.ftl" as itemLib />
+<#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "totalRecords": ${data.paging.totalRecords?c},
+ "startIndex": ${data.paging.startIndex?c},
+ "metadata":
+ {
+ "parent":
+ {
+ <#if data.parent??>
+ <#assign parentNode = data.parent.node>
+ "nodeRef": "${parentNode.nodeRef}",
+ "permissions":
+ {
+ "userAccess":
+ {
+ <#list data.parent.userAccess?keys as perm>
+ <#if data.parent.userAccess[perm]?is_boolean>
+ "${perm?string}": ${data.parent.userAccess[perm]?string}<#if perm_has_next>,#if>
+ #if>
+ #list>
+ }
+ }
+ #if>
+ }
+ },
+ "items":
+ [
+ <#list data.items as item>
+ {
+ <@itemLib.itemJSON item />
+ }<#if item_has_next>,#if>
+ #list>
+ ]
+}
+#escape>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.js
new file mode 100644
index 0000000000..6b2b8f8c22
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/data.post.json.js
@@ -0,0 +1,111 @@
+
+
+
+
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Main entry point: Return data list with properties being supplied in POSTed arguments
+ *
+ * @method getData
+ */
+function getData()
+{
+ // Use helper function to get the arguments
+ var parsedArgs = ParseArgs.getParsedArgs();
+ if (parsedArgs === null)
+ {
+ return;
+ }
+
+ var fields = null;
+ // Extract fields (if given)
+ if (json.has("fields"))
+ {
+ // Convert the JSONArray object into a native JavaScript array
+ fields = [];
+ var jsonFields = json.get("fields"),
+ numFields = jsonFields.length();
+
+ for (count = 0; count < numFields; count++)
+ {
+ fields.push(jsonFields.get(count).replace("_", ":"));
+ }
+ }
+
+ // Try to find a filter query based on the passed-in arguments
+ var filter = parsedArgs.filter,
+ allNodes = [], node,
+ items = [];
+
+ var filterParams = Filters.getFilterParams(filter, parsedArgs)
+ query = filterParams.query;
+
+ // Query the nodes - passing in default sort and result limit parameters
+ if (query !== "")
+ {
+ allNodes = search.query(
+ {
+ query: query,
+ language: filterParams.language,
+ page:
+ {
+ maxItems: (filterParams.limitResults ? parseInt(filterParams.limitResults, 10) : 0)
+ },
+ sort: filterParams.sort,
+ templates: filterParams.templates,
+ namespace: (filterParams.namespace ? filterParams.namespace : null)
+ });
+
+ for each (node in allNodes)
+ {
+ try
+ {
+ items.push(Evaluator.run(node, fields));
+ }
+ catch(e) {}
+ }
+ }
+
+ return (
+ {
+ fields: fields,
+ luceneQuery: query,
+ paging:
+ {
+ totalRecords: items.length,
+ startIndex: 0
+ },
+ parent:
+ {
+ node: parsedArgs.listNode,
+ userAccess:
+ {
+ create: parsedArgs.listNode.hasPermission("CreateChildren")
+ }
+ },
+ items: items
+ });
+}
+
+/**
+ * Document List Component: doclist
+ */
+model.data = getData();
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/evaluator.lib.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/evaluator.lib.js
new file mode 100644
index 0000000000..79bc3d6008
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/evaluator.lib.js
@@ -0,0 +1,205 @@
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+var Evaluator =
+{
+ /**
+ * Cache for cm:person objects
+ */
+ PeopleObjectCache: {},
+
+ /**
+ * Gets / caches a person object
+ *
+ * @method getPersonObject
+ * @param nodeRef {string} NodeRef of a cm:person object
+ */
+ getPersonObject: function Evaluator_getPersonObject(nodeRef)
+ {
+ if (nodeRef == null || nodeRef == "")
+ {
+ return null;
+ }
+
+ if (typeof Evaluator.PeopleObjectCache[nodeRef] == "undefined")
+ {
+ var person = search.findNode(nodeRef);
+ Evaluator.PeopleObjectCache[nodeRef] =
+ {
+ userName: person.properties.userName,
+ firstName: person.properties.firstName,
+ lastName: person.properties.lastName,
+ displayName: (person.properties.firstName + " " + person.properties.lastName).replace(/^\s+|\s+$/g, "")
+ };
+ if (person.assocs["cm:avatar"] != null)
+ {
+ Evaluator.PeopleObjectCache[nodeRef].avatar = person.assocs["cm:avatar"][0];
+ }
+ }
+ return Evaluator.PeopleObjectCache[nodeRef];
+ },
+
+ /**
+ * Cache for nodes that are subtypes of cm:cmobject
+ */
+ ContentObjectCache: {},
+
+ /**
+ * Gets / caches a content object
+ *
+ * @method getContentObject
+ * @param nodeRef {string} NodeRef
+ */
+ getContentObject: function Evaluator_getContentObject(nodeRef)
+ {
+ if (nodeRef == null || nodeRef == "")
+ {
+ return null;
+ }
+
+ if (typeof Evaluator.ContentObjectCache[nodeRef] == "undefined")
+ {
+ var node = search.findNode(nodeRef);
+ try
+ {
+ Evaluator.ContentObjectCache[nodeRef] = node;
+ }
+ catch(e)
+ {
+ // Possibly a stale indexed node
+ return null;
+ }
+ }
+ return Evaluator.ContentObjectCache[nodeRef];
+ },
+
+ /**
+ * Generate displayValue and any extra metadata for this field
+ */
+ decorateFieldData: function Evaluator_decorateFieldData(objData, node)
+ {
+ var value = objData.value,
+ type = objData.type,
+ displayValue = value,
+ obj;
+
+ if (type == "cm:person")
+ {
+ obj = Evaluator.getPersonObject(value);
+ if (obj != null)
+ {
+ displayValue = obj.displayName;
+ objData.metadata = obj.userName;
+ }
+ }
+ else if (type == "datetime" || type == "date")
+ {
+ objData.metadata = type;
+ }
+ else if (node.isSubType("cm:folder"))
+ {
+ obj = getContentObject(node.nodeRef);
+ if (obj != null)
+ {
+ displayValue = obj.displayPath.substring(companyhome.name.length() + 1);
+ }
+ }
+ else if (node.isSubType("cm:object"))
+ {
+ obj = getContentObject(node.nodeRef);
+ if (obj != null)
+ {
+ displayValue = obj.properties["cm:name"];
+ }
+ }
+
+ objData.displayValue = displayValue;
+ },
+
+ /**
+ * Node Evaluator - main entrypoint
+ */
+ run: function Evaluator_run(node, fields)
+ {
+ var permissions = {},
+ actionSet = "",
+ actionLabels = {},
+ createdBy = Common.getPerson(node.properties["cm:creator"]),
+ modifiedBy = Common.getPerson(node.properties["cm:modifier"]),
+ nodeData = {};
+
+ /**
+ * PERMISSIONS
+ */
+ permissions =
+ {
+ "create": node.hasPermission("CreateChildren"),
+ "edit": node.hasPermission("Write"),
+ "delete": node.hasPermission("Delete")
+ };
+
+ // Use the form service to parse the required properties
+ scriptObj = formService.getForm("node", node.nodeRef, fields, fields);
+
+ // Make sure we can quickly look-up the Field Definition within the formData loop...
+ var objDefinitions = {};
+ for each (formDef in scriptObj.fieldDefinitions)
+ {
+ objDefinitions[formDef.dataKeyName] = formDef;
+ }
+
+ // Populate the data model
+ var formData = scriptObj.formData.data;
+ for (var k in formData)
+ {
+ var isAssoc = k.indexOf("assoc") == 0,
+ value = formData[k].value,
+ type = isAssoc ? objDefinitions[k].endpointType : objDefinitions[k].dataType,
+ objData =
+ {
+ type: type
+ };
+
+ if (value instanceof java.util.Date)
+ {
+ objData.value = utils.toISO8601(value);
+ }
+ else
+ {
+ // java.util.List instances are returned from ScriptFormData.java as Strings
+ objData.value = value;
+ }
+
+ Evaluator.decorateFieldData(objData, node);
+ nodeData[k] = objData;
+ }
+
+ return(
+ {
+ node: node,
+ nodeData: nodeData,
+ actionSet: actionSet,
+ actionPermissions: permissions,
+ createdBy: createdBy,
+ modifiedBy: modifiedBy,
+ tags: node.tags,
+ actionLabels: actionLabels
+ });
+ }
+};
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/filters.lib.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/filters.lib.js
new file mode 100644
index 0000000000..03eca60717
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/filters.lib.js
@@ -0,0 +1,151 @@
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+var Filters =
+{
+ /**
+ * Create filter parameters based on input parameters
+ *
+ * @method getFilterParams
+ * @param filter {string} Required filter
+ * @param parsedArgs {object} Parsed arguments object literal
+ * @return {object} Object literal containing parameters to be used in Lucene search
+ */
+ getFilterParams: function Filter_getFilterParams(filter, parsedArgs)
+ {
+ var filterParams =
+ {
+ query: "+PARENT:\"" + parsedArgs.nodeRef + "\" ",
+ limitResults: null,
+ sort: [
+ {
+ column: "@{http://www.alfresco.org/model/content/1.0}name",
+ ascending: true
+ }],
+ language: "lucene",
+ templates: null
+ };
+
+ // Max returned results specified?
+ var argMax = args.max;
+ if ((argMax !== null) && !isNaN(argMax))
+ {
+ filterParams.limitResults = argMax;
+ }
+
+ // Create query based on passed-in arguments
+ var filterData = String(filter.filterData || ""),
+ filterQuery = filterParams.query;
+
+ // Common types and aspects to filter from the UI
+ var filterQueryDefaults =
+ " -TYPE:\"{http://www.alfresco.org/model/content/1.0}systemfolder\"" +
+ " -@cm\\:lockType:READ_ONLY_LOCK";
+
+ switch (String(filter.filterId))
+ {
+ case "recentlyAdded":
+ case "recentlyModified":
+ case "recentlyCreatedByMe":
+ case "recentlyModifiedByMe":
+ var onlySelf = (filterData.indexOf("ByMe")) > 0 ? true : false,
+ dateField = (filterData.indexOf("Created") > 0) ? "created" : "modified",
+ ownerField = (dateField == "created") ? "creator" : "modifier";
+
+ // Default to 7 days - can be overridden using "days" argument
+ var dayCount = 7,
+ argDays = args.days;
+ if ((argDays !== null) && !isNaN(argDays))
+ {
+ dayCount = argDays;
+ }
+
+ // Default limit to 50 documents - can be overridden using "max" argument
+ if (filterParams.limitResults === null)
+ {
+ filterParams.limitResults = 50;
+ }
+
+ var date = new Date();
+ var toQuery = date.getFullYear() + "\\-" + (date.getMonth() + 1) + "\\-" + date.getDate();
+ date.setDate(date.getDate() - dayCount);
+ var fromQuery = date.getFullYear() + "\\-" + (date.getMonth() + 1) + "\\-" + date.getDate();
+
+ filterQuery = "+PARENT:\"" + parsedArgs.nodeRef;
+ if (parsedArgs.nodeRef == "alfresco://sites/home")
+ {
+ // Special case for "Sites home" pseudo-nodeRef
+ filterQuery += "/*/cm:dataLists";
+ }
+ filterQuery += "\"";
+ filterQuery += " +@cm\\:" + dateField + ":[" + fromQuery + "T00\\:00\\:00.000 TO " + toQuery + "T23\\:59\\:59.999]";
+ if (onlySelf)
+ {
+ filterQuery += " +@cm\\:" + ownerField + ":" + person.properties.userName;
+ }
+ filterQuery += " -TYPE:\"{http://www.alfresco.org/model/content/1.0}folder\"";
+
+ filterParams.sort = [
+ {
+ column: "@{http://www.alfresco.org/model/content/1.0}" + dateField,
+ ascending: false
+ }];
+ filterParams.query = filterQuery + filterQueryDefaults;
+ break;
+
+ case "createdByMe":
+ // Default limit to 50 documents - can be overridden using "max" argument
+ if (filterParams.limitResults === null)
+ {
+ filterParams.limitResults = 50;
+ }
+
+ filterQuery = "+PARENT:\"" + parsedArgs.nodeRef;
+ if (parsedArgs.nodeRef == "alfresco://sites/home")
+ {
+ // Special case for "Sites home" pseudo-nodeRef
+ filterQuery += "/*/cm:dataLists";
+ }
+ filterQuery += "\"";
+ filterQuery += " +@cm\\:modifier:" + person.properties.userName;
+ filterQuery += " -TYPE:\"{http://www.alfresco.org/model/content/1.0}folder\"";
+ filterParams.query = filterQuery + filterQueryDefaults;
+ break;
+
+ case "node":
+ filterParams.query = "+ID:\"" + parsedArgs.nodeRef + "\"";
+ break;
+
+ case "tag":
+ // Remove any trailing "/" character
+ if (filterData.charAt(filterData.length - 1) == "/")
+ {
+ filterData = filterData.slice(0, -1);
+ }
+ filterParams.query += "+PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(filterData) + "/member\"";
+ break;
+
+ default:
+ filterParams.query = filterQuery + filterQueryDefaults;
+ break;
+ }
+
+ return filterParams;
+ }
+};
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.lib.ftl
new file mode 100644
index 0000000000..fc8d9a0999
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.lib.ftl
@@ -0,0 +1,67 @@
+<#macro itemJSON item>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+ <#assign node = item.node>
+ <#assign tags><#list item.tags as tag>"${tag}"<#if tag_has_next>,#if>#list>#assign>
+ "nodeRef": "${node.nodeRef}",
+ "createdOn": "${xmldate(node.properties.created)}",
+ "createdBy":
+ {
+ "value": "${item.createdBy.userName}",
+ "displayValue": "${item.createdBy.displayName}"
+ },
+ "modifiedOn": "${xmldate(node.properties.modified)}>",
+ "modifiedBy":
+ {
+ "value": "${item.modifiedBy.userName}",
+ "displayValue": "${item.modifiedBy.displayName}"
+ },
+ "actionSet": "${item.actionSet}",
+ "tags": <#noescape>[${tags}]#noescape>,
+ "permissions":
+ {
+ "userAccess":
+ {
+ <#list item.actionPermissions?keys as actionPerm>
+ <#if item.actionPermissions[actionPerm]?is_boolean>
+ "${actionPerm?string}": ${item.actionPermissions[actionPerm]?string}<#if actionPerm_has_next>,#if>
+ #if>
+ #list>
+ }
+ },
+ <#if item.custom??>"custom": <#noescape>${item.custom}#noescape>,#if>
+ "actionLabels":
+ {
+ <#if item.actionLabels??>
+ <#list item.actionLabels?keys as actionLabel>
+ "${actionLabel?string}": "${item.actionLabels[actionLabel]}"<#if actionLabel_has_next>,#if>
+ #list>
+ #if>
+ },
+ "itemData":
+ {
+ <#list item.nodeData?keys as key>
+ <#assign data = item.nodeData[key]>
+ "${key}":
+ {
+ <#if data.value?is_boolean>
+ "value": ${data.value?string},
+ <#elseif data.value?is_number>
+ "value": ${data.value?c},
+ <#else>
+ "value": "${data.value}",
+ #if>
+ <#if data.metadata??>
+ "metadata": "${data.metadata}",
+ #if>
+ <#if data.displayValue?is_boolean>
+ "displayValue": ${data.displayValue?string}
+ <#elseif data.displayValue?is_number>
+ "displayValue": ${data.displayValue?c}
+ <#else>
+ "displayValue": "${data.displayValue}"
+ #if>
+ }<#if key_has_next>,#if>
+ #list>
+ }
+ #escape>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.desc.xml
new file mode 100644
index 0000000000..ff31516a8d
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.desc.xml
@@ -0,0 +1,8 @@
+
+ DataLists - Single item data retrieval
+ Data Lists Component - retrieve data for a single item by nodeRef
+ /slingshot/datalists/item/node/{store_type}/{store_id}/{id}
+ argument
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.ftl
new file mode 100644
index 0000000000..0ed6ae7c0b
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.ftl
@@ -0,0 +1,30 @@
+<#import "item.lib.ftl" as itemLib />
+<#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "metadata":
+ {
+ "parent":
+ {
+ <#if data.parent??>
+ <#assign parentNode = data.parent.node>
+ "nodeRef": "${parentNode.nodeRef}",
+ "permissions":
+ {
+ "userAccess":
+ {
+ <#list data.parent.userAccess?keys as perm>
+ <#if data.parent.userAccess[perm]?is_boolean>
+ "${perm?string}": ${data.parent.userAccess[perm]?string}<#if perm_has_next>,#if>
+ #if>
+ #list>
+ }
+ }
+ #if>
+ }
+ },
+ "item":
+ {
+ <@itemLib.itemJSON data.item />
+ }
+}
+#escape>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.js
new file mode 100644
index 0000000000..0ca5bf49d7
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/item.post.json.js
@@ -0,0 +1,83 @@
+
+
+
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Main entry point: Return data list with properties being supplied in POSTed arguments
+ *
+ * @method getData
+ */
+function getData()
+{
+ // Use helper function to get the arguments
+ var parsedArgs = ParseArgs.getParsedArgs();
+ if (parsedArgs === null)
+ {
+ return;
+ }
+
+ var fields = null;
+ // Extract fields (if given)
+ if (json.has("fields"))
+ {
+ // Convert the JSONArray object into a native JavaScript array
+ fields = [];
+ var jsonFields = json.get("fields"),
+ numFields = jsonFields.length();
+
+ for (count = 0; count < numFields; count++)
+ {
+ fields.push(jsonFields.get(count).replace("_", ":"));
+ }
+ }
+
+ // Try to find a filter query based on the passed-in arguments
+ var node = search.findNode(parsedArgs.nodeRef),
+ items = [];
+
+ if (node != null)
+ {
+ try
+ {
+ item = Evaluator.run(node, fields);
+ }
+ catch(e) {}
+ }
+
+ return (
+ {
+ fields: fields,
+ parent:
+ {
+ node: parsedArgs.listNode,
+ userAccess:
+ {
+ create: parsedArgs.listNode.hasPermission("CreateChildren")
+ }
+ },
+ item: item
+ });
+}
+
+/**
+ * Document List Component: doclist
+ */
+model.data = getData();
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/list.lib.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/list.lib.ftl
new file mode 100644
index 0000000000..1fc5e5e73b
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/list.lib.ftl
@@ -0,0 +1,11 @@
+<#macro listJSON list>
+ <#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "name": "${list.name}",
+ "title": "${list.properties.title!list.name}",
+ "description": "${list.properties.description!""}",
+ "nodeRef": "${list.nodeRef}",
+ "itemType": "${list.properties["dl:dataListItemType"]!""}"
+}
+ #escape>
+#macro>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.desc.xml
new file mode 100644
index 0000000000..2559e84268
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.desc.xml
@@ -0,0 +1,10 @@
+
+ DataLists
+ Data Lists Component - retrieve data lists within a given site and container, or by container nodeRef
+ /slingshot/datalists/lists/site/{site}/{container}/
+ /slingshot/datalists/lists/site/{site}/{container}
+ /slingshot/datalists/lists/node/{store_type}/{store_id}/{id}
+ argument
+ user
+ required
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.js
new file mode 100644
index 0000000000..aba59374c3
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.js
@@ -0,0 +1,46 @@
+
+
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+/**
+ * Main entry point: Return list of Data Lists
+ *
+ * @method getDataLists
+ */
+function getDataLists()
+{
+ // Use helper function to get the arguments
+ var parsedArgs = ParseArgs.getParsedArgs();
+ if (parsedArgs === null)
+ {
+ return;
+ }
+
+ return (
+ {
+ container: parsedArgs.rootNode,
+ lists: parsedArgs.rootNode.children
+ });
+}
+
+/**
+ * Document List Component: doclist
+ */
+model.datalists = getDataLists();
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.json.ftl
new file mode 100644
index 0000000000..a7c477e328
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/lists.get.json.ftl
@@ -0,0 +1,12 @@
+<#import "list.lib.ftl" as listLib />
+<#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "container": "${datalists.container.nodeRef?string}",
+ "datalists":
+ [
+ <#list datalists.lists as list>
+ <@listLib.listJSON list /><#if list_has_next>,#if>
+ #list>
+ ]
+}
+#escape>
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/parse-args.lib.js b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/parse-args.lib.js
new file mode 100644
index 0000000000..7e9e355797
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/slingshot/datalists/parse-args.lib.js
@@ -0,0 +1,208 @@
+/**
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+var Common =
+{
+ /**
+ * Cache for person objects
+ */
+ PeopleCache: {},
+
+ /**
+ * Gets / caches a person object
+ *
+ * @method getPerson
+ * @param username {string} User name
+ */
+ getPerson: function Common_getPerson(username)
+ {
+ if (username == null || username == "")
+ {
+ return null;
+ }
+
+ if (typeof Common.PeopleCache[username] == "undefined")
+ {
+ var person = people.getPerson(username);
+ if (person == null && username == "System")
+ {
+ person =
+ {
+ properties:
+ {
+ userName: "System",
+ firstName: "System",
+ lastName: "User"
+ },
+ assocs: {}
+ };
+ }
+ Common.PeopleCache[username] =
+ {
+ userName: person.properties.userName,
+ firstName: person.properties.firstName,
+ lastName: person.properties.lastName,
+ displayName: (person.properties.firstName + " " + person.properties.lastName).replace(/^\s+|\s+$/g, "")
+ };
+ if (person.assocs["cm:avatar"] != null)
+ {
+ Common.PeopleCache[username].avatar = person.assocs["cm:avatar"][0];
+ }
+ }
+ return Common.PeopleCache[username];
+ }
+};
+
+var ParseArgs =
+{
+ /**
+ * Get and parse arguments
+ *
+ * @method getParsedArgs
+ * @param containerType {string} Optional: Node Type of container to create if it doesn't exist, defaults to "cm:folder"
+ * @return {array|null} Array containing the validated input parameters
+ */
+ getParsedArgs: function ParseArgs_getParsedArgs(containerType)
+ {
+ var rootNode = null,
+ nodeRef = null,
+ listNode = null;
+
+ if (url.templateArgs.store_type !== null)
+ {
+ /**
+ * nodeRef input: store_type, store_id and id
+ */
+ var storeType = url.templateArgs.store_type,
+ storeId = url.templateArgs.store_id,
+ id = url.templateArgs.id;
+
+ nodeRef = storeType + "://" + storeId + "/" + id;
+ rootNode = ParseArgs.resolveVirtualNodeRef(nodeRef);
+ if (rootNode == null)
+ {
+ rootNode = search.findNode(nodeRef);
+ if (rootNode === null)
+ {
+ status.setCode(status.STATUS_NOT_FOUND, "Not a valid nodeRef: '" + nodeRef + "'");
+ return null;
+ }
+ }
+
+ listNode = rootNode;
+ }
+ else
+ {
+ /**
+ * Site and container input
+ */
+ var siteId = url.templateArgs.site,
+ containerId = url.templateArgs.container,
+ listId = url.templateArgs.list,
+ siteNode = siteService.getSite(siteId);
+
+ if (siteNode === null)
+ {
+ status.setCode(status.STATUS_NOT_FOUND, "Site not found: '" + siteId + "'");
+ return null;
+ }
+
+ rootNode = siteNode.getContainer(containerId);
+ if (rootNode === null)
+ {
+ rootNode = siteNode.createContainer(containerId, containerType || "cm:folder");
+ if (rootNode === null)
+ {
+ status.setCode(status.STATUS_NOT_FOUND, "Data Lists container '" + containerId + "' not found in '" + siteId + "'. (No permission?)");
+ return null;
+ }
+
+ rootNode.properties["cm:description"] = "Data Lists";
+ rootNode.save();
+ }
+ listNode = rootNode;
+
+ if (listId !== null)
+ {
+ listNode = rootNode.childByNamePath(listId);
+ if (listNode === null)
+ {
+ status.setCode(status.STATUS_NOT_FOUND, "List not found: '" + listId + "'");
+ return null;
+ }
+ }
+ }
+
+ // Filter
+ var filter = null;
+ if (args.filter)
+ {
+ filter =
+ {
+ filterId: args.filter
+ };
+ }
+ else if (typeof json !== "undefined" && json.has("filter"))
+ {
+ filter = jsonUtils.toObject(json.get("filter"));
+ if (filter == null)
+ {
+ filter =
+ {
+ filterId: ""
+ }
+ }
+ }
+
+ var objRet =
+ {
+ rootNode: rootNode,
+ listNode: listNode,
+ nodeRef: String(listNode.nodeRef),
+ filter: filter
+ };
+
+ return objRet;
+ },
+
+ /**
+ * Resolve "virtual" nodeRefs into nodes
+ *
+ * @method resolveVirtualNodeRef
+ * @param virtualNodeRef {string} nodeRef
+ * @return {ScriptNode|null} Node corresponding to supplied virtual nodeRef. Returns null if supplied nodeRef isn't a "virtual" type
+ */
+ resolveVirtualNodeRef: function ParseArgs_resolveVirtualNodeRef(nodeRef)
+ {
+ var node = null;
+ if (nodeRef == "alfresco://company/home")
+ {
+ node = companyhome;
+ }
+ else if (nodeRef == "alfresco://user/home")
+ {
+ node = userhome;
+ }
+ else if (nodeRef == "alfresco://sites/home")
+ {
+ node = companyhome.childrenByXPath("st:sites")[0];
+ }
+ return node;
+ }
+};