1
0
Fork 0
This commit is contained in:
Heiko Kernbach 2013-05-31 19:54:56 +02:00
commit ed932e153f
70 changed files with 2183 additions and 526 deletions

View File

@ -15,6 +15,8 @@ v1.4
v1.3.1 (2013-XX-XX)
-------------------
* issue #540: suppress return of temporary internal variables in AQL
* issue #530: ReferenceError: ArangoError is not a constructor
* issue #535: Problem with AQL user functions javascript API

View File

@ -310,7 +310,7 @@ CLEANUP += \
swagger:
python @srcdir@/Documentation/Scripts/generateSwagger.py \
< @srcdir@/arangod/RestHandler/RestEdgeHandler.cpp > @srcdir@/html/admin/api-docs/edges
< @srcdir@/arangod/RestHandler/RestEdgeHandler.cpp > @srcdir@/html/admin/api-docs/edge
python @srcdir@/Documentation/Scripts/generateSwagger.py \
< @srcdir@/arangod/RestHandler/RestDocumentHandler.cpp > @srcdir@/html/admin/api-docs/document

View File

@ -209,8 +209,7 @@ Server Statistics {#NewFeatures11ServerStatistics}
--------------------------------------------------
ArangoDB 1.1 allows querying the server status via the administration
front-end (see @ref UserManualWebInterfaceStatistics) or via REST API
methods.
front-end or via REST API methods.
The following methods are available:
- `GET /_admin/connection-statistics`: provides connection statistics

View File

@ -7,7 +7,7 @@ ArangoDB's Web-Interface {#UserManualWebInterface}
Accessing the Web-Interface {#UserManualWebInterfaceAccess}
===========================================================
The web interfaced can be access as
The web interface can be accessed via the URL
http://localhost:8529
@ -20,64 +20,55 @@ application instead. In this case use
Collections Tab {#UserManualWebInterfaceCollections}
----------------------------------------------------
The collection tabs shows an overview about the loaded and unloaded
collections of the database.
The *Collections* tab shows an overview of the loaded and unloaded
collections present in ArangoDB. System collections (i.e. collections
whose names start with an underscore) are not shown by default.
@htmlonly <img src="images/fe-collections.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-collections.png}@endlatexonly
The list of collections can be restricted using the search bar, or by
using the filtering at the top. The filter can also be used to show or
hide system collections.
You can load, unloaded, delete, or inspect the collections. Please
note that you should not delete or change system collections, i. e.,
collections starting with an underscore.
Clicking on a collection will show the documents contained in it.
Clicking the small icon on a collection's badge will bring up a dialog
that allows loading/unloading, renaming and deleting the collection.
If you click on the magnifying glass, you will get a list of all documents
in the collection.
Please note that you should not change or delete system collections.
@htmlonly <img src="images/fe-documents.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-documents.png}@endlatexonly
In the list of documents of a collection, you can click on the *Add document*
line to add a new document to the collection. The document will be created
instantly, with a system-defined key. The key and all other attributes of the
document can be adjusted in the following view.
Using the pencil you can edit the document.
Query Tab {#UserManualWebInterfaceQuery}
----------------------------------------
AQL Editor Tab {#UserManualWebInterfaceQuery}
---------------------------------------------
The query tabs allows you to execute AQL queries.
The *AQL Editor* tab allow to execute AQL queries.
@htmlonly <img src="images/fe-query.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-query.png}@endlatexonly
Type in a query in the bottom box and execute it by pressing the *Submit* button.
The query result will be shown in the box at the top.
Type in a query and execute it.
Shell Tab {#UserManualWebInterfaceShell}
----------------------------------------
JS Shell Tab {#UserManualWebInterfaceShell}
-------------------------------------------
The shell tabs give you access to a JavaScript shell connection to the
The *JS Shell* tab provides access to a JavaScript shell connection to the
database server.
@htmlonly <img src="images/fe-shell.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-shell.png}@endlatexonly
Any valid JavaScript code can be executed inside the shell. The code will be
executed inside your browser. To contact the ArangoDB server, you can use the
`db` object, for example as follows:
JSH> db._create("mycollection");
JSH> db.mycollection.save({ _key: "test", value: "something" });
Use the OK button or return to execute a command.
Logs Tab {#UserManualWebInterfaceLogs}
--------------------------------------
You can browse the log files.
@htmlonly <img src="images/fe-logs.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-logs.png}@endlatexonly
You can use the *Logs* tab to browse the most recent log entries provided by the
ArangoDB database server.
Note that the server only keeps a limited number of log entries. For
real log analyses write the logs to disk using syslog or a similar
mechanism.
Statistics Tab {#UserManualWebInterfaceStatistics}
--------------------------------------------------
Use the statistics tab to display information about the server.
@htmlonly <img src="images/fe-statistics.png" alt="ArangoDB Front-End">@endhtmlonly
@latexonly\includegraphics[width=12cm]{images/fe-statistics.png}@endlatexonly
Initially no statistics will be display. You must use the add button
to configure what type of information should be displayed.
mechanism. ArangoDB provides several startup options for this.

View File

@ -6,4 +6,3 @@ TOC {#UserManualWebInterfaceTOC}
- @ref UserManualWebInterfaceQuery
- @ref UserManualWebInterfaceShell
- @ref UserManualWebInterfaceLogs
- @ref UserManualWebInterfaceStatistics

View File

@ -668,7 +668,7 @@ static void InitArray (TRI_aql_codegen_js_t* const generator,
static void EnterSymbol (TRI_aql_codegen_js_t* const generator,
const char* const name,
const TRI_aql_codegen_register_t registerIndex) {
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
TRI_aql_codegen_variable_t* variable = CreateVariable(name, registerIndex);
if (variable == NULL) {
@ -890,7 +890,8 @@ static void CloseLoops (TRI_aql_codegen_js_t* const generator) {
////////////////////////////////////////////////////////////////////////////////
static TRI_vector_string_t StoreSymbols (TRI_aql_codegen_js_t* const generator,
const TRI_aql_codegen_register_t rowRegister) {
const TRI_aql_codegen_register_t rowRegister,
bool suppressTemporaries) {
TRI_vector_string_t variableNames;
size_t i = generator->_scopes._length;
@ -907,7 +908,12 @@ static TRI_vector_string_t StoreSymbols (TRI_aql_codegen_js_t* const generator,
TRI_aql_codegen_variable_t* variable = (TRI_aql_codegen_variable_t*) peek->_variables._table[j];
char* copy;
if (! variable) {
if (variable == NULL) {
continue;
}
if (suppressTemporaries && *variable->_name == '_') {
// don't emit temporary variables
continue;
}
@ -957,6 +963,7 @@ static void RestoreSymbols (TRI_aql_codegen_js_t* const generator,
// iterate over all variables passed
n = variableNames->_length;
for (i = 0; i < n; ++i) {
// create a new register for each variable
TRI_aql_codegen_register_t registerIndex = IncRegister(generator);
@ -2001,7 +2008,7 @@ static void ProcessSort (TRI_aql_codegen_js_t* const generator,
InitArray(generator, rowRegister);
// save symbols
variableNames = StoreSymbols(generator, rowRegister);
variableNames = StoreSymbols(generator, rowRegister, false);
// result.push(row)
ScopeOutputRegister(generator, scope->_resultRegister);
@ -2050,13 +2057,17 @@ static void ProcessCollect (TRI_aql_codegen_js_t* const generator,
TRI_aql_node_t* list;
size_t i, n;
#if AQL_VERBOSE
ScopeOutput(generator, "\n/* collect start */\n");
#endif
// var row = { };
InitArray(generator, rowRegister);
// we are not interested in the variable names here, but
// StoreSymbols also generates code to save the current state in
// a rowRegister, and we need that
variableNames = StoreSymbols(generator, rowRegister);
variableNames = StoreSymbols(generator, rowRegister, true);
TRI_DestroyVectorString(&variableNames);
// result.push(row)
@ -2133,6 +2144,10 @@ static void ProcessCollect (TRI_aql_codegen_js_t* const generator,
EnterSymbol(generator, TRI_AQL_NODE_STRING(nameNode), intoRegister);
}
#if AQL_VERBOSE
ScopeOutput(generator, "\n/* collect end */\n");
#endif
}
////////////////////////////////////////////////////////////////////////////////
@ -2152,7 +2167,7 @@ static void ProcessLimit (TRI_aql_codegen_js_t* const generator,
InitArray(generator, rowRegister);
// save symbols
variableNames = StoreSymbols(generator, rowRegister);
variableNames = StoreSymbols(generator, rowRegister, false);
// result.push(row)
ScopeOutputRegister(generator, scope->_resultRegister);

View File

@ -510,7 +510,7 @@ bool RestDocumentHandler::readDocument () {
///
/// Use a document handle:
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocument}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocument}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -527,7 +527,7 @@ bool RestDocumentHandler::readDocument () {
///
/// Use a document handle and an etag:
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocumentIfNoneMatch}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocumentIfNoneMatch}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -545,7 +545,7 @@ bool RestDocumentHandler::readDocument () {
///
/// Unknown document handle:
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocumentUnknownHandle}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocumentUnknownHandle}
/// var url = "/_api/document/products/unknownhandle";
///
/// var response = logCurlRequest('GET', url);
@ -666,7 +666,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
///
/// Returns a collection.
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocumentAll}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocumentAll}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -685,7 +685,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
///
/// Collection does not exist.
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocumentAllCollectionDoesNotExist}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocumentAllCollectionDoesNotExist}
/// var cn = "doesnotexist";
/// db._drop(cn);
/// var url = "/_api/document/?collection=" + cn;
@ -811,7 +811,7 @@ bool RestDocumentHandler::readAllDocuments () {
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestReadDocumentHead}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerReadDocumentHead}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -962,7 +962,7 @@ bool RestDocumentHandler::checkDocument () {
///
/// Using document handle:
///
/// @EXAMPLE_ARANGOSH_RUN{RestUpdateDocument}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerUpdateDocument}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -979,7 +979,7 @@ bool RestDocumentHandler::checkDocument () {
///
/// Unknown document handle:
///
/// @EXAMPLE_ARANGOSH_RUN{RestUpdateDocumentUnknownHandle}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerUpdateDocumentUnknownHandle}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -997,7 +997,7 @@ bool RestDocumentHandler::checkDocument () {
///
/// Produce a revision conflict:
///
/// @EXAMPLE_ARANGOSH_RUN{RestUpdateDocumentIfMatchOther}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerUpdateDocumentIfMatchOther}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -1016,7 +1016,7 @@ bool RestDocumentHandler::checkDocument () {
///
/// Last write wins:
///
/// @EXAMPLE_ARANGOSH_RUN{RestUpdateDocumentIfMatchOtherLastWriteWins}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerUpdateDocumentIfMatchOtherLastWriteWins}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -1034,7 +1034,7 @@ bool RestDocumentHandler::checkDocument () {
///
/// Alternative to header field:
///
/// @EXAMPLE_ARANGOSH_RUN{RestUpdateDocumentRevOther}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerUpdateDocumentRevOther}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -1151,7 +1151,7 @@ bool RestDocumentHandler::replaceDocument () {
///
/// patches an existing document with new content.
///
/// @EXAMPLE_ARANGOSH_RUN{RestPatchDocument}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerPatchDocument}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -1392,7 +1392,7 @@ bool RestDocumentHandler::modifyDocument (bool isPatch) {
///
/// Using document handle:
///
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerDELETEDocument}
/// @EXAMPLE_ARANGOSH_RUN{RestDocumentHandlerDeleteDocument}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn, { waitForSync: true });

View File

@ -75,30 +75,63 @@ RestEdgeHandler::RestEdgeHandler (HttpRequest* request, TRI_vocbase_t* vocbase)
///
/// @RESTHEADER{POST /_api/edge,creates an edge}
///
/// @REST{POST /_api/edge?collection=`collection-name`&from=`from-handle`&to=`to-handle`}
/// @RESTQUERYPARAMETERS
///
/// Creates a new edge in the collection identified by `collection-name`.
/// @RESTQUERYPARAM{collection,string,required}
/// Creates a new edge in the collection identified by `collection` name.
///
/// @RESTQUERYPARAM{from,string,required}
/// The document handle of the start point must be passed in `from` handle.
///
/// @RESTQUERYPARAM{to,string,required}
/// The document handle of the end point must be passed in `to` handle.
///
/// @RESTBODYPARAM{edge-document,json,required}
/// A JSON representation of the edge document must be passed as the body of
/// the POST request. This JSON object may contain the edge's document key in
/// the `_key` attribute if needed.
/// The document handle of the start point must be passed in `from-handle`.
/// The document handle of the end point must be passed in `to-handle`.
///
/// `from-handle` and `to-handle` are immutable once the edge has been
/// @RESTDESCRIPTION
/// `from` handle and `to` handle are immutable once the edge has been
/// created.
///
/// In all other respects the method works like `POST /document`, see
/// @ref RestDocument for details.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{202}
/// is returned if the edge was created successfully.
///
/// @RESTRETURNCODE{404}
/// is returned if the edge collection was not found.
///
/// @EXAMPLES
///
/// Create an edge:
/// Create an edge and reads it back:
///
/// @verbinclude rest-edge-create-edge
/// @EXAMPLE_ARANGOSH_RUN{RestEdgeCreateEdge}
/// db._drop("edges");
/// db._drop("vertices");
/// var Graph = require("org/arangodb/graph").Graph;
/// var g = new Graph("graph", "vertices", "edges");
/// g.addVertex(1);
/// g.addVertex(2);
/// var url = "/_api/edge/?collection=edges&from=vertices/1&to=vertices/2";
///
/// var response = logCurlRequest("POST", url, { "name": "Emil" });
///
/// assert(response.code === 202);
///
/// Read an edge:
/// logJsonResponse(response);
/// var body = response.body.replace(/\\/g, '');
/// var edge_id = JSON.parse(body)._id;
/// var response2 = logCurlRequest("GET", "/_api/edge/" + edge_id);
///
/// assert(response2.code === 200);
///
/// @verbinclude rest-edge-read-edge
/// logJsonResponse(response2);
/// @END_EXAMPLE_ARANGOSH_RUN
////////////////////////////////////////////////////////////////////////////////
bool RestEdgeHandler::createDocument () {

View File

@ -1,5 +1,5 @@
{
"apiVersion":"1.3",
"apiVersion":"1.4",
"swaggerVersion":"1.1",
"apis":[ {
"path": "api-docs/document",
@ -9,6 +9,10 @@
"path": "api-docs/edges",
"description": "Interface für Edges"
},
{
"path": "api-docs/edge",
"description": "Interface für Edge"
},
{
"path": "api-docs/collection",
"description": "Interface for Collections"

View File

@ -1,10 +1,11 @@
.footer {
position: fixed;
background: url("../img/footer_hd_bg.png") repeat-x scroll left 10px #4A4A4A;
font-size: 14px;
text-align: center;
left: 0;
right: 0;
margin-top:500px;
bottom: 0px;
}
.footerExtra {

View File

@ -22,11 +22,27 @@
background-color: rgb(56, 52, 52);
}
.searchByAttribute {
.searchByAttribute, .searchEqualsLabel {
margin-top: 3px;
margin-right: 10px;
margin-right: 6px;
}
svg.graphViewer text {
font: 11px Arial;
pointer-events: none;
stroke: #000;
}
.capitalize {
text-transform:capitalize;
}
svg.graphViewer {
border-style: groove;
}
div.mousepointer {
position: absolute;
margin: 0;
padding: 5px;
}

View File

@ -162,6 +162,10 @@ function JSONAdapter(jsonPath, nodes, edges, width, height) {
};
self.setChildLimit = function (limit) {
};
self.expandCommunity = function (commNode, callback) {
};

View File

@ -53,13 +53,16 @@ function ArangoAdapter(nodes, edges, config) {
api = {},
queries = {},
cachedCommunities = {},
joinedInCommunities = {},
nodeCollection,
edgeCollection,
limit,
childLimit,
reducer,
arangodb,
width,
height,
direction,
setWidth = function(w) {
initialX.range = w / 2;
@ -93,12 +96,22 @@ function ArangoAdapter(nodes, edges, config) {
if (config.height !== undefined) {
setHeight(config.height);
}
if (config.undirected !== undefined) {
if (config.undirected === true) {
direction = "any";
} else {
direction = "outbound";
}
} else {
direction = "outbound";
}
},
findNode = function(id) {
var res = $.grep(nodes, function(e){
return e._id === id;
});
var intId = joinedInCommunities[id] || id,
res = $.grep(nodes, function(e){
return e._id === intId;
});
if (res.length === 0) {
return false;
}
@ -145,7 +158,8 @@ function ArangoAdapter(nodes, edges, config) {
_data: data,
_id: data._id
},
e = findEdge(edge._id);
e = findEdge(edge._id),
edgeToPush;
if (e) {
return e;
}
@ -160,8 +174,32 @@ function ArangoAdapter(nodes, edges, config) {
edge.source = source;
edge.target = target;
edges.push(edge);
source._outboundCounter++;
target._inboundCounter++;
if (cachedCommunities[source._id] !== undefined) {
edgeToPush = {};
edgeToPush.type = "s";
edgeToPush.id = edge._id;
edgeToPush.source = $.grep(cachedCommunities[source._id].nodes, function(e){
return e._id === data._from;
})[0];
edgeToPush.source._outboundCounter++;
cachedCommunities[source._id].edges.push(edgeToPush);
} else {
source._outboundCounter++;
}
if (cachedCommunities[target._id] !== undefined) {
edgeToPush = {};
edgeToPush.type = "t";
edgeToPush.id = edge._id;
edgeToPush.target = $.grep(cachedCommunities[target._id].nodes, function(e){
return e._id === data._to;
})[0];
edgeToPush.target._inboundCounter++;
cachedCommunities[target._id].edges.push(edgeToPush);
} else {
target._inboundCounter++;
}
return edge;
},
@ -275,6 +313,9 @@ function ArangoAdapter(nodes, edges, config) {
if (query !== queries.connectedEdges) {
bindVars["@nodes"] = nodeCollection;
}
if (query !== queries.childrenCentrality) {
bindVars.dir = direction;
}
bindVars["@edges"] = edgeCollection;
var data = {
query: query,
@ -317,8 +358,10 @@ function ArangoAdapter(nodes, edges, config) {
cachedCommunities[commId] = {};
cachedCommunities[commId].nodes = nodesToRemove;
cachedCommunities[commId].edges = [];
combineCommunityEdges(nodesToRemove, commNode);
_.each(nodesToRemove, function(n) {
joinedInCommunities[n._id] = commId;
removeNode(n);
});
nodes.push(commNode);
@ -335,6 +378,7 @@ function ArangoAdapter(nodes, edges, config) {
collapseCommunity(com);
}
_.each(nodesToAdd, function(n) {
delete joinedInCommunities[n._id];
nodes.push(n);
});
_.each(edgesToChange, function(e) {
@ -358,23 +402,38 @@ function ArangoAdapter(nodes, edges, config) {
parseResultOfTraversal = function (result, callback) {
result = result[0];
var inserted = {},
n = insertNode(result[0].vertex),
com, buckets;
_.each(result, function(visited) {
var node = insertNode(visited.vertex),
path = visited.path;
path = visited.path;
inserted[node._id] = node;
_.each(path.vertices, function(connectedNode) {
insertNode(connectedNode);
var ins = insertNode(connectedNode);
inserted[ins._id] = ins;
});
_.each(path.edges, function(edge) {
insertEdge(edge);
});
});
});
delete inserted[n._id];
if (_.size(inserted) > childLimit) {
buckets = reducer.bucketNodes(_.values(inserted), childLimit);
_.each(buckets, function(b) {
if (b.length > 1) {
var ids = _.map(b, function(n) {
return n._id;
});
collapseCommunity(ids);
}
});
}
if (limit < nodes.length) {
com = reducer.getCommunity(limit, n);
collapseCommunity(com);
}
if (callback) {
var n = insertNode(result[0].vertex),
com;
if (limit < nodes.length) {
com = reducer.getCommunity(limit, n);
collapseCommunity(com);
}
callback(n);
}
},
@ -421,7 +480,7 @@ function ArangoAdapter(nodes, edges, config) {
_.each(res, self.deleteEdge);
});
};
parseConfig(config);
api.base = arangodb.lastIndexOf("http://", 0) === 0
@ -447,7 +506,7 @@ function ArangoAdapter(nodes, edges, config) {
+ "@@nodes, "
+ "@@edges, "
+ "@id, "
+ "\"outbound\", {"
+ "@dir, {"
+ "strategy: \"depthfirst\","
+ "maxDepth: 1,"
+ "paths: true"
@ -460,7 +519,7 @@ function ArangoAdapter(nodes, edges, config) {
+ "@@nodes, "
+ "@@edges, "
+ "n._id, "
+ "\"outbound\", {"
+ "@dir, {"
+ "strategy: \"depthfirst\","
+ "maxDepth: 1,"
+ "paths: true"
@ -478,8 +537,9 @@ function ArangoAdapter(nodes, edges, config) {
+ " || e._from == @id"
+ " RETURN e";
reducer = new NodeReducer(nodes, edges);
childLimit = Number.POSITIVE_INFINITY;
reducer = new NodeReducer(nodes, edges);
self.oldLoadNodeFromTreeById = function(nodeId, callback) {
sendQuery(queries.nodeById, {
@ -639,9 +699,16 @@ function ArangoAdapter(nodes, edges, config) {
});
};
self.changeTo = function (nodesCol, edgesCol ) {
self.changeTo = function (nodesCol, edgesCol, dir) {
nodeCollection = nodesCol;
edgeCollection = edgesCol;
if (dir !== undefined) {
if (dir === true) {
direction = "any";
} else {
direction = "outbound";
}
}
api.node = api.base + "document?collection=" + nodeCollection;
api.edge = api.base + "edge?collection=" + edgeCollection;
};
@ -657,6 +724,10 @@ function ArangoAdapter(nodes, edges, config) {
}
};
self.setChildLimit = function (pLimit) {
childLimit = pLimit;
};
self.expandCommunity = function (commNode, callback) {
expandCommunity(commNode);
if (callback !== undefined) {
@ -664,4 +735,34 @@ function ArangoAdapter(nodes, edges, config) {
}
};
self.getCollections = function(callback) {
if (callback && callback.length >= 2) {
$.ajax({
cache: false,
type: "GET",
url: api.collection,
contentType: "application/json",
dataType: "json",
processData: false,
success: function(data) {
var cols = data.collections,
docs = [],
edgeCols = [];
_.each(cols, function(c) {
if (!c.name.match(/^_/)) {
if (c.type === 3) {
edgeCols.push(c.name);
} else if (c.type === 2){
docs.push(c.name);
}
}
});
callback(docs, edgeCols);
},
error: function(data) {
throw data.statusText;
}
});
}
};
}

View File

@ -50,7 +50,8 @@ function EdgeShaper(parent, flags, idfunc) {
edges = [],
toplevelSVG,
visibleLabels = true,
followEdge = {},
followEdgeG,
idFunction = function(d) {
return d.source._id + "-" + d.target._id;
},
@ -70,7 +71,9 @@ function EdgeShaper(parent, flags, idfunc) {
dblclick: noop,
mousedown: noop,
mouseup: noop,
mousemove: noop
mousemove: noop,
mouseout: noop,
mouseover: noop
};
addUpdate = noop;
},
@ -317,6 +320,8 @@ function EdgeShaper(parent, flags, idfunc) {
idFunction = idfunc;
}
followEdgeG = toplevelSVG.append("g");
/////////////////////////////////////////////////////////
/// Public functions
@ -349,6 +354,24 @@ function EdgeShaper(parent, flags, idfunc) {
}
shapeEdges();
};
self.addAnEdgeFollowingTheCursor = function(x, y) {
followEdge = followEdgeG.append("line");
followEdge.attr("stroke", "black")
.attr("id", "connectionLine")
.attr("x1", x)
.attr("y1", y)
.attr("x2", x)
.attr("y2", y);
return function(x, y) {
followEdge.attr("x2", x).attr("y2", y);
};
};
self.removeCursorFollowingEdge = function() {
followEdge.remove();
followEdge = {};
};
}
EdgeShaper.shapes = Object.freeze({

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global _*/
/*global _, $, window*/
/*global EventLibrary*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
@ -32,6 +32,9 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
var eventlib,
expandConfig,
svgBase,
svgTemp,
svgObj,
self = this,
parseNodeEditorConfig = function(config) {
if (config.shaper === undefined) {
@ -77,11 +80,14 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
self.events.STARTCREATEEDGE = function(callback) {
return function(node) {
var e = d3.event || window.event;
edgeStart = node;
didInsert = false;
if (callback !== undefined) {
callback();
callback(node, e);
}
// Necessary to omit dragging of the graph
e.stopPropagation();
};
};
@ -118,6 +124,20 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
};
};
}
},
bindSVGEvents = function() {
svgObj = svgObj || $("svg");
_.each(svgBase, function(fs, ev) {
svgObj.bind(ev, function(trigger) {
_.each(fs, function(f) {
f(trigger);
});
if (!! svgTemp[ev]) {
svgTemp[ev](trigger);
}
});
});
};
if (nodeShaper === undefined) {
@ -130,6 +150,17 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
eventlib = new EventLibrary();
svgBase = {
click: [],
dblclick: [],
mousedown: [],
mouseup: [],
mousemove: [],
mouseout: [],
mouseover: []
};
svgTemp = {};
self.events = {};
if (config !== undefined) {
@ -171,6 +202,10 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
actions: actions
});
break;
case "svg":
svgTemp[event] = func;
bindSVGEvents();
break;
default:
if (object.bind !== undefined) {
object.unbind(event);
@ -196,11 +231,28 @@ function EventDispatcher(nodeShaper, edgeShaper, config) {
actions: actions
});
break;
case "svg":
svgTemp = {};
_.each(actions, function(fs, ev) {
if (ev !== "reset") {
svgTemp[ev] = fs;
}
});
bindSVGEvents();
break;
default:
throw "Sorry cannot rebind to object. Please give either "
+ "\"nodes\" or \"edges\"";
+ "\"nodes\", \"edges\" or \"svg\"";
}
};
self.fixSVG = function(event, action) {
if (svgBase[event] === undefined) {
throw "Sorry unkown event";
}
svgBase[event].push(action);
bindSVGEvents();
};
/*
self.unbind = function () {
throw "Not implemented";

View File

@ -47,9 +47,9 @@ function ForceLayouter(config) {
"use strict";
var self = this,
force = d3.layout.force(),
distance = config.distance || 80,
gravity = config.gravity || 0.08,
charge = config.charge || -240,
distance = config.distance || 240, // 80
gravity = config.gravity || 0.01, // 0.08
charge = config.charge || -1000, // -240
onUpdate = config.onUpdate || function () {},
width = config.width || 940,
height = config.height || 640,

View File

@ -265,9 +265,34 @@ function NodeReducer(nodes, edges) {
joinCommunities(l.sID, l.lID, coms, heap, l.val);
updateValues(l, dQ, a, heap);
return true;
},
addNode = function(bucket, node) {
bucket.push(node);
},
getSimilarityValue = function(bucket, node) {
if (bucket.length === 0) {
return 1;
}
var comp = bucket[0],
props = _.union(_.keys(comp), _.keys(node)),
countMatch = 0,
propCount = 0;
_.each(props, function(key) {
if (comp[key] !== undefined && node[key]!== undefined) {
countMatch++;
if (comp[key] === node[key]) {
countMatch += 4;
}
}
});
propCount = props.length * 5;
propCount++;
countMatch++;
return countMatch / propCount;
};
self.getCommunity = function(limit, focus) {
var dQ = {},
@ -305,4 +330,34 @@ function NodeReducer(nodes, edges) {
}
return res[0];
};
self.bucketNodes = function(toSort, numBuckets) {
var res = [],
threshold = 0.5;
if (toSort.length <= numBuckets) {
res = _.map(toSort, function(n) {
return [n];
});
return res;
}
_.each(toSort, function(n) {
var i, shortest, sLength;
shortest = 0;
sLength = Number.POSITIVE_INFINITY;
for (i = 0; i < numBuckets; i++) {
res[i] = res[i] || [];
if (getSimilarityValue(res[i], n) > threshold) {
addNode(res[i], n);
return;
}
if (sLength > res[i].length) {
shortest = i;
sLength = res[i].length;
}
}
addNode(res[shortest], n);
});
return res;
};
}

View File

@ -62,7 +62,7 @@
*/
function NodeShaper(parent, flags, idfunc) {
"use strict";
var self = this,
communityRegEx = /^\*community/,
nodes = [],
@ -114,7 +114,9 @@ function NodeShaper(parent, flags, idfunc) {
drag: noop,
mousedown: noop,
mouseup: noop,
mousemove: noop
mousemove: noop,
mouseout: noop,
mouseover: noop
};
addUpdate = noop;
},
@ -227,12 +229,14 @@ function NodeShaper(parent, flags, idfunc) {
addLabel = function (node) {
node.append("text") // Append a label for the node
.attr("text-anchor", "middle") // Define text-anchor
.attr("stroke", "black") // Foce a black color20*75)
.text(label);
};
} else {
addLabel = function (node) {
node.append("text") // Append a label for the node
.attr("text-anchor", "middle") // Define text-anchor
.attr("stroke", "black") // Foce a black color20*75)
.text(function(d) {
return d._data[label] !== undefined ? d._data[label] : "";
});

View File

@ -105,7 +105,7 @@ function ZoomManager(width, height, svg, g, nodeShaper, edgeShaper, config, limi
var fontMax = conf.maxFont || 16,
fontMin = conf.minFont || 6,
rMax = conf.maxRadius || 25,
rMin = conf.minRadius || 1;
rMin = conf.minRadius || 4;
baseDist = conf.focusZoom || 1;
baseDRadius = conf.focusRadius || 100;

View File

@ -1,6 +1,6 @@
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
/*global _*/
/*global EventDispatcher, ArangoAdapter, JSONAdapter */
/*global ArangoAdapter, JSONAdapter */
/*global ForceLayouter, EdgeShaper, NodeShaper, ZoomManager */
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
@ -56,7 +56,6 @@ function GraphViewer(svg, width, height, adapterConfig, config) {
edgeContainer,
zoomManager,
fixedSize,
dispatcher,
edges = [],
nodes = [],
@ -101,7 +100,6 @@ function GraphViewer(svg, width, height, adapterConfig, config) {
nsConf = config.nodeShaper || {},
idFunc = nsConf.idfunc || undefined,
zConf = config.zoom || false;
parseLayouterConfig(config.layouter);
edgeContainer = graphContainer.append("g");
self.edgeShaper = new EdgeShaper(edgeContainer, esConf);
@ -113,13 +111,14 @@ function GraphViewer(svg, width, height, adapterConfig, config) {
switch (adapterConfig.type.toLowerCase()) {
case "arango":
adapterConfig.width = width;
adapterConfig.height = height;
adapterConfig.width = width;
adapterConfig.height = height;
self.adapter = new ArangoAdapter(
nodes,
edges,
adapterConfig
);
self.adapter.setChildLimit(5);
break;
case "json":
self.adapter = new JSONAdapter(

View File

@ -33,6 +33,14 @@ var helper = helper || {};
(function eventHelper() {
"use strict";
helper.simulateMouseMoveEvent = function(objectId, x, y) {
var evt = document.createEvent("MouseEvents"),
testee = document.getElementById(objectId);
evt.initMouseEvent("mousemove", true, true, window,
0, 0, 0, x, y, false, false, false, false, 0, null);
testee.dispatchEvent(evt);
};
helper.simulateDragEvent = function (objectId) {
helper.simulateMouseEvent("mousedown", objectId);
var e1 = document.createEvent("MouseEvents"),

View File

@ -286,6 +286,7 @@
apibase = host + "/_api/",
apiCursor = apibase + 'cursor';
self.fakeReducerRequest = function() {};
self.fakeReducerBucketRequest = function() {};
spyOn(window, "NodeReducer").andCallFake(function(v, e) {
return {
getCommunity: function(limit, focus) {
@ -293,6 +294,9 @@
return self.fakeReducerRequest(limit, focus);
}
return self.fakeReducerRequest(limit);
},
bucketNodes: function(toSort, numBuckets) {
return self.fakeReducerBucketRequest(toSort, numBuckets);
}
};
});
@ -306,26 +310,40 @@
height: 40
}
);
traversalQuery = function(id, nods, edgs) {
traversalQuery = function(id, nods, edgs, undirected) {
var dir;
if (undirected === true) {
dir = "any";
} else {
dir = "outbound";
}
return JSON.stringify({
query: "RETURN TRAVERSAL(@@nodes, @@edges, @id, \"outbound\","
query: "RETURN TRAVERSAL(@@nodes, @@edges, @id, @dir,"
+ " {strategy: \"depthfirst\",maxDepth: 1,paths: true})",
bindVars: {
id: id,
"@nodes": nods,
dir: dir,
"@edges": edgs
}
});
};
filterQuery = function(v, nods, edgs) {
filterQuery = function(v, nods, edgs, undirected) {
var dir;
if (undirected === true) {
dir = "any";
} else {
dir = "outbound";
}
return JSON.stringify({
query: "FOR n IN @@nodes FILTER n.id == @value"
+ " RETURN TRAVERSAL(@@nodes, @@edges, n._id, \"outbound\","
+ " RETURN TRAVERSAL(@@nodes, @@edges, n._id, @dir,"
+ " {strategy: \"depthfirst\",maxDepth: 1,paths: true})",
bindVars: {
value: v,
"@nodes": nods,
"@edges": edgs
dir: dir,
"@edges": edgs
}
});
};
@ -424,9 +442,45 @@
};
};
});
it('should offer lists of available collections', function() {
var collections = [],
sys1 = {id: "1", name: "_sys1", status: 3, type: 2},
sys2 = {id: "2", name: "_sys2", status: 2, type: 2},
doc1 = {id: "3", name: "doc1", status: 3, type: 2},
doc2 = {id: "4", name: "doc2", status: 2, type: 2},
doc3 = {id: "5", name: "doc3", status: 3, type: 2},
edge1 = {id: "6", name: "edge1", status: 3, type: 3},
edge2 = {id: "7", name: "edge2", status: 2, type: 3};
collections.push(sys1);
collections.push(sys2);
collections.push(doc1);
collections.push(doc2);
collections.push(doc3);
collections.push(edge1);
collections.push(edge2);
spyOn($, "ajax").andCallFake(function(request) {
request.success({collections: collections});
});
adapter.getCollections(function(docs, edge) {
expect(docs).toContain("doc1");
expect(docs).toContain("doc2");
expect(docs).toContain("doc3");
expect(docs.length).toEqual(3);
expect(edge).toContain("edge1");
expect(edge).toContain("edge2");
expect(edge.length).toEqual(2);
});
});
it('should be able to load a tree node from '
+ 'ArangoDB by internal _id attribute', function() {
+ 'ArangoDB by internal _id attribute', function() {
var c0, c1, c2, c3, c4;
@ -466,8 +520,14 @@
});
});
it('should map loadNode to loadByID', function() {
spyOn(adapter, "loadNodeFromTreeById");
adapter.loadNode("a", "b");
expect(adapter.loadNodeFromTreeById).toHaveBeenCalledWith("a", "b");
});
it('should be able to load a tree node from ArangoDB'
+ ' by internal attribute and value', function() {
+ ' by internal attribute and value', function() {
var c0, c1, c2, c3, c4;
@ -649,6 +709,170 @@
});
it('should be able to switch to different collections and change to directed', function() {
runs(function() {
spyOn($, "ajax");
adapter.changeTo(altNodesCollection, altEdgesCollection, false);
adapter.loadNode("42");
expect($.ajax).toHaveBeenCalledWith(
requests.cursor(traversalQuery("42", altNodesCollection, altEdgesCollection, false))
);
});
});
it('should be able to switch to different collections'
+ ' and change to undirected', function() {
runs(function() {
spyOn($, "ajax");
adapter.changeTo(altNodesCollection, altEdgesCollection, true);
adapter.loadNode("42");
expect($.ajax).toHaveBeenCalledWith(
requests.cursor(traversalQuery("42", altNodesCollection, altEdgesCollection, true))
);
});
});
it('should add at most the upper bound of children in one step', function() {
var inNodeCol, callNodes;
runs(function() {
var addNNodes = function(n) {
var i = 0,
res = [];
for (i = 0; i < n; i++) {
res.push(insertNode(nodesCollection, i));
}
return res;
},
connectToAllButSelf = function(source, ns) {
_.each(ns, function(target) {
if (source !== target) {
insertEdge(edgesCollection, source, target);
}
});
};
inNodeCol = addNNodes(21);
connectToAllButSelf(inNodeCol[0], inNodeCol);
adapter.setChildLimit(5);
spyOn($, "ajax").andCallFake(function(request) {
var vars = JSON.parse(request.data).bindVars;
if (vars !== undefined) {
request.success({result: loadGraph(vars)});
}
});
spyOn(this, "fakeReducerBucketRequest").andCallFake(function(ns) {
var i = 0,
res = [],
pos;
callNodes = ns;
for (i = 0; i < 5; i++) {
pos = i*4;
res.push(ns.slice(pos, pos + 4));
}
return res;
});
callbackCheck = false;
adapter.loadNodeFromTreeById(inNodeCol[0], checkCallbackFunction);
});
waitsFor(function() {
return callbackCheck;
});
runs(function() {
var callNodesIds = _.map(callNodes, function(n) {
return n._id;
});
expect(this.fakeReducerBucketRequest).toHaveBeenCalledWith(
jasmine.any(Array),
5
);
expect(callNodesIds).toEqual(inNodeCol.slice(1));
expect(nodes.length).toEqual(6);
expect(getCommunityNodes().length).toEqual(5);
});
});
it('should not replace single nodes by communities', function() {
var inNodeCol, callNodes;
runs(function() {
var addNNodes = function(n) {
var i = 0,
res = [];
for (i = 0; i < n; i++) {
res.push(insertNode(nodesCollection, i));
}
return res;
},
connectToAllButSelf = function(source, ns) {
_.each(ns, function(target) {
if (source !== target) {
insertEdge(edgesCollection, source, target);
}
});
};
inNodeCol = addNNodes(7);
connectToAllButSelf(inNodeCol[0], inNodeCol);
adapter.setChildLimit(5);
spyOn($, "ajax").andCallFake(function(request) {
var vars = JSON.parse(request.data).bindVars;
if (vars !== undefined) {
request.success({result: loadGraph(vars)});
}
});
spyOn(this, "fakeReducerBucketRequest").andCallFake(function(ns) {
var i = 0,
res = [],
pos;
for (i = 0; i < 4; i++) {
res.push([ns[i]]);
}
res.push([ns[4], ns[5]]);
return res;
});
callbackCheck = false;
adapter.loadNodeFromTreeById(inNodeCol[0], checkCallbackFunction);
});
waitsFor(function() {
return callbackCheck;
});
runs(function() {
var callNodesIds = _.map(callNodes, function(n) {
return n._id;
});
expect(this.fakeReducerBucketRequest).toHaveBeenCalledWith(
jasmine.any(Array),
5
);
expect(nodes.length).toEqual(6);
expect(getCommunityNodes().length).toEqual(1);
});
});
describe('that has already loaded one graph', function() {
var c0, c1, c2, c3, c4, c5, c6, c7,
@ -971,6 +1195,167 @@
});
describe('expanding after a while', function() {
it('should connect edges of internal nodes accordingly', function() {
var commNode, called, counterCallback,
v0, v1, v2, v3, v4,
e0_1, e0_2, e1_3, e1_4, e2_3, e2_4;
runs(function() {
var v = "vertices",
e = "edges";
nodes.length = 0;
edges.length = 0;
v0 = insertNode(v, 0);
v1 = insertNode(v, 1);
v2 = insertNode(v, 2);
v3 = insertNode(v, 3);
v4 = insertNode(v, 4);
e0_1 = insertEdge(e, v0, v1);
e0_2 = insertEdge(e, v0, v2);
e1_3 = insertEdge(e, v1, v3);
e1_4 = insertEdge(e, v1, v4);
e2_3 = insertEdge(e, v2, v3);
e2_4 = insertEdge(e, v2, v4);
called = 0;
counterCallback = function() {
called++;
};
spyOn(this, "fakeReducerRequest").andCallFake(function() {
return [v1, v3, v4];
});
adapter.setNodeLimit(3);
adapter.changeTo(v, e);
adapter.loadNode(v0, counterCallback);
adapter.loadNode(v1, counterCallback);
});
waitsFor(function() {
return called === 2;
});
runs(function() {
adapter.loadNode(v2, counterCallback);
commNode = getCommunityNodes()[0];
});
waitsFor(function() {
return called === 3;
});
runs(function() {
var commId = commNode._id;
// Check start condition
existNodes([commId, v0, v2]);
expect(nodes.length).toEqual(3);
existEdge(v0, v2);
existEdge(v0, commId);
existEdge(v2, commId);
expect(edges.length).toEqual(4);
adapter.setNodeLimit(20);
adapter.expandCommunity(commNode, counterCallback);
});
waitsFor(function() {
return called === 4;
});
runs(function() {
existNodes([v0, v1, v2, v3, v4]);
expect(nodes.length).toEqual(5);
existEdge(v0, v1);
existEdge(v0, v2);
existEdge(v1, v3);
existEdge(v1, v4);
existEdge(v2, v3);
existEdge(v2, v4);
expect(edges.length).toEqual(6);
});
});
it('set inbound and outboundcounter correctly', function() {
var commNode, called, counterCallback,
v0, v1, v2, v3, v4,
e0_1, e0_2, e1_3, e1_4, e2_3, e2_4;
runs(function() {
var v = "vertices",
e = "edges";
nodes.length = 0;
edges.length = 0;
v0 = insertNode(v, 0);
v1 = insertNode(v, 1);
v2 = insertNode(v, 2);
v3 = insertNode(v, 3);
v4 = insertNode(v, 4);
e0_1 = insertEdge(e, v0, v1);
e0_2 = insertEdge(e, v0, v2);
e1_3 = insertEdge(e, v1, v3);
e1_4 = insertEdge(e, v1, v4);
e2_3 = insertEdge(e, v2, v3);
e2_4 = insertEdge(e, v2, v4);
called = 0;
counterCallback = function() {
called++;
};
spyOn(this, "fakeReducerRequest").andCallFake(function() {
return [v1, v3, v4];
});
adapter.setNodeLimit(3);
adapter.changeTo(v, e);
adapter.loadNode(v0, counterCallback);
adapter.loadNode(v1, counterCallback);
});
waitsFor(function() {
return called === 2;
});
runs(function() {
adapter.loadNode(v2, counterCallback);
commNode = getCommunityNodes()[0];
});
waitsFor(function() {
return called === 3;
});
runs(function() {
adapter.setNodeLimit(20);
adapter.expandCommunity(commNode, counterCallback);
});
waitsFor(function() {
return called === 4;
});
runs(function() {
var checkNodeWithInAndOut = function(id, inbound, outbound) {
var n = nodeWithID(id);
expect(n._outboundCounter).toEqual(outbound);
expect(n._inboundCounter).toEqual(inbound);
};
checkNodeWithInAndOut(v0, 0, 2);
checkNodeWithInAndOut(v1, 1, 2);
checkNodeWithInAndOut(v2, 1, 2);
checkNodeWithInAndOut(v3, 2, 0);
checkNodeWithInAndOut(v4, 2, 0);
});
});
});
describe('that displays a community node already', function() {
var firstCommId,
@ -996,7 +1381,7 @@
});
});
it('should expand a community if enough space is available', function() {
it('should expand a community if enough space is available', function() {
runs(function() {
adapter.setNodeLimit(10);
callbackCheck = false;
@ -1019,7 +1404,7 @@
});
it('should expand a community and join another '
+ 'one if not enough space is available', function() {
+ 'one if not enough space is available', function() {
runs(function() {
fakeResult = [c1, c7];
callbackCheck = false;
@ -1079,6 +1464,26 @@
});
});
it('should connect edges to internal nodes', function() {
runs(function() {
insertEdge(edgesCollection, c3, c0);
adapter.setNodeLimit(20);
callbackCheck = false;
adapter.loadNode(c3, checkCallbackFunction);
});
waitsFor(function() {
return callbackCheck;
});
runs(function() {
existEdge(c3, firstCommId);
});
});
});
});

View File

@ -43,13 +43,17 @@
beforeEach(function () {
adapter = {
changeTo: function(){}
changeTo: function(){},
getCollections: function(cb) {
cb(["nodes", "newNodes"], ["edges", "newEdges"]);
}
};
list = document.createElement("ul");
document.body.appendChild(list);
list.id = "control_list";
list.id = "control_adapter_list";
adapterUI = new ArangoAdapterControls(list, adapter);
spyOn(adapter, 'changeTo');
spyOn(adapter, "getCollections").andCallThrough();
this.addMatchers({
toBeTag: function(name) {
var el = this.actual;
@ -88,34 +92,119 @@
runs(function() {
adapterUI.addControlChangeCollections();
expect($("#control_list #control_collections").length).toEqual(1);
expect($("#control_list #control_collections")[0]).toConformToListCSS();
expect($("#control_adapter_list #control_adapter_collections").length).toEqual(1);
expect($("#control_adapter_list #control_adapter_collections")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_collections");
helper.simulateMouseEvent("click", "control_adapter_collections");
expect($("#control_collections_modal").length).toEqual(1);
expect($("#control_adapter_collections_modal").length).toEqual(1);
$("#control_collections_nodecollection").attr("value", "newNodes");
$("#control_collections_edgecollection").attr("value", "newEdges");
$("#control_adapter_collections_nodecollection").attr("value", "newNodes");
$("#control_adapter_collections_edgecollection").attr("value", "newEdges");
helper.simulateMouseEvent("click", "control_collections_submit");
helper.simulateMouseEvent("click", "control_adapter_collections_submit");
expect(adapter.changeTo).toHaveBeenCalledWith(
"newNodes",
"newEdges"
"newEdges",
false
);
});
waitsFor(function() {
return $("#control_collections_modal").length === 0;
return $("#control_adapter_collections_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
it('should change collections and traversal direction to directed', function() {
runs(function() {
adapterUI.addControlChangeCollections();
helper.simulateMouseEvent("click", "control_adapter_collections");
$("#control_adapter_collections_nodecollection").attr("value", "newNodes");
$("#control_adapter_collections_edgecollection").attr("value", "newEdges");
$("#control_adapter_collections_undirected").attr("checked", false);
helper.simulateMouseEvent("click", "control_adapter_collections_submit");
expect(adapter.changeTo).toHaveBeenCalledWith(
"newNodes",
"newEdges",
false
);
});
waitsFor(function() {
return $("#control_adapter_collections_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
it('should change collections and traversal direction to undirected', function() {
runs(function() {
adapterUI.addControlChangeCollections();
helper.simulateMouseEvent("click", "control_adapter_collections");
$("#control_adapter_collections_nodecollection").attr("value", "newNodes");
$("#control_adapter_collections_edgecollection").attr("value", "newEdges");
$("#control_adapter_collections_undirected").attr("checked", true);
helper.simulateMouseEvent("click", "control_adapter_collections_submit");
expect(adapter.changeTo).toHaveBeenCalledWith(
"newNodes",
"newEdges",
true
);
});
waitsFor(function() {
return $("#control_adapter_collections_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
it('should offer the available collections as lists', function() {
runs(function() {
adapterUI.addControlChangeCollections();
helper.simulateMouseEvent("click", "control_adapter_collections");
var docList = document.getElementById("control_adapter_collections_nodecollection"),
edgeList = document.getElementById("control_adapter_collections_edgecollection"),
docCollectionOptions = docList.children,
edgeCollectionOptions = edgeList.children;
expect(adapter.getCollections).toHaveBeenCalled();
expect(docList).toBeTag("select");
expect(docCollectionOptions.length).toEqual(2);
expect(docCollectionOptions[0]).toBeTag("option");
expect(docCollectionOptions[1]).toBeTag("option");
expect(docCollectionOptions[0].value).toEqual("nodes");
expect(docCollectionOptions[1].value).toEqual("newNodes");
expect(edgeList).toBeTag("select");
expect(edgeCollectionOptions.length).toEqual(2);
expect(edgeCollectionOptions[0]).toBeTag("option");
expect(edgeCollectionOptions[1]).toBeTag("option");
expect(edgeCollectionOptions[0].value).toEqual("edges");
expect(edgeCollectionOptions[1].value).toEqual("newEdges");
helper.simulateMouseEvent("click", "control_adapter_collections_submit");
});
waitsFor(function() {
return $("#control_adapter_collections_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
it('should be able to add all controls to the list', function() {
adapterUI.addAll();
expect($("#control_list #control_collections").length).toEqual(1);
expect($("#control_adapter_list #control_adapter_collections").length).toEqual(1);
});
});
}());

View File

@ -67,7 +67,9 @@ var describeInterface = function (testee) {
expect(testee).toHaveFunction("deleteNode", 2);
expect(testee).toHaveFunction("patchNode", 3);
expect(testee).toHaveFunction("setNodeLimit", 2);
expect(testee).toHaveFunction("setChildLimit", 1);
expect(testee).toHaveFunction("expandCommunity", 2);
});
};

View File

@ -42,6 +42,7 @@
beforeEach(function () {
svg = document.createElement("svg");
svg.id = "svg";
document.body.appendChild(svg);
});
@ -274,6 +275,55 @@
expect($("#1-5 line").attr("x2")).toEqual("28.284271247461902");
});
it('should be able to draw an edge that follows the cursor', function() {
var line,
jqLine,
cursorX,
cursorY,
nodeX = 15,
nodeY = 20,
shaper = new EdgeShaper(d3.select("svg")),
moveCB = shaper.addAnEdgeFollowingTheCursor(nodeX, nodeY);
cursorX = 20;
cursorY = 30;
moveCB(cursorX, cursorY);
expect($("#connectionLine").length).toEqual(1);
jqLine = $("#connectionLine");
line = document.getElementById("connectionLine");
expect(line.tagName.toLowerCase()).toEqual("line");
expect(jqLine.attr("x1")).toEqual(String(nodeX));
expect(jqLine.attr("y1")).toEqual(String(nodeY));
expect(jqLine.attr("x2")).toEqual(String(cursorX));
expect(jqLine.attr("y2")).toEqual(String(cursorY));
cursorX = 45;
cursorY = 12;
moveCB(cursorX, cursorY);
expect(jqLine.attr("x2")).toEqual(String(cursorX));
expect(jqLine.attr("y2")).toEqual(String(cursorY));
});
it('should be able to remove the cursor-following edge on demand', function() {
var line,
cursorX,
cursorY,
nodeX = 15,
nodeY = 20,
shaper = new EdgeShaper(d3.select("svg")),
moveCB;
moveCB = shaper.addAnEdgeFollowingTheCursor(nodeX, nodeY);
cursorX = 20;
cursorY = 30;
moveCB(cursorX, cursorY);
shaper.removeCursorFollowingEdge();
expect($("#connectionLine").length).toEqual(0);
});
describe('testing for colours', function() {
it('should have a default colouring of no colour flag is given', function() {

View File

@ -47,7 +47,7 @@
shaper = new EdgeShaper(d3.select("svg"));
list = document.createElement("ul");
document.body.appendChild(list);
list.id = "control_list";
list.id = "control_edge_list";
shaperUI = new EdgeShaperControls(list, shaper);
spyOn(shaper, 'changeTo');
this.addMatchers({
@ -94,10 +94,10 @@
runs(function() {
shaperUI.addControlOpticShapeNone();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_none")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_none").length).toEqual(1);
expect($("#control_edge_list #control_edge_none")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_none");
helper.simulateMouseEvent("click", "control_edge_none");
expect(shaper.changeTo).toHaveBeenCalledWith({
shape: {
@ -111,10 +111,10 @@
runs(function() {
shaperUI.addControlOpticShapeArrow();
expect($("#control_list #control_arrow").length).toEqual(1);
expect($("#control_list #control_arrow")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_arrow").length).toEqual(1);
expect($("#control_edge_list #control_edge_arrow")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_arrow");
helper.simulateMouseEvent("click", "control_edge_arrow");
expect(shaper.changeTo).toHaveBeenCalledWith({
shape: {
@ -129,12 +129,12 @@
runs(function() {
shaperUI.addControlOpticLabel();
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_label")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_label").length).toEqual(1);
expect($("#control_edge_list #control_edge_label")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_label");
$("#control_label_key").attr("value", "theAnswer");
helper.simulateMouseEvent("click", "control_label_submit");
helper.simulateMouseEvent("click", "control_edge_label");
$("#control_edge_label_key").attr("value", "theAnswer");
helper.simulateMouseEvent("click", "control_edge_label_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
label: "theAnswer"
@ -142,7 +142,7 @@
});
waitsFor(function() {
return $("#control_label_modal").length === 0;
return $("#control_edge_label_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -151,12 +151,12 @@
runs(function() {
shaperUI.addControlOpticSingleColour();
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_singlecolour")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_singlecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_singlecolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_singlecolour");
$("#control_singlecolour_stroke").attr("value", "#123456");
helper.simulateMouseEvent("click", "control_singlecolour_submit");
helper.simulateMouseEvent("click", "control_edge_singlecolour");
$("#control_edge_singlecolour_stroke").attr("value", "#123456");
helper.simulateMouseEvent("click", "control_edge_singlecolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -167,7 +167,7 @@
});
waitsFor(function() {
return $("#control_singlecolour_modal").length === 0;
return $("#control_edge_singlecolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -176,12 +176,12 @@
runs(function() {
shaperUI.addControlOpticAttributeColour();
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_attributecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_attributecolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_attributecolour");
$("#control_attributecolour_key").attr("value", "label");
helper.simulateMouseEvent("click", "control_attributecolour_submit");
helper.simulateMouseEvent("click", "control_edge_attributecolour");
$("#control_edge_attributecolour_key").attr("value", "label");
helper.simulateMouseEvent("click", "control_edge_attributecolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -192,7 +192,7 @@
});
waitsFor(function() {
return $("#control_attributecolour_modal").length === 0;
return $("#control_edge_attributecolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -201,13 +201,13 @@
runs(function() {
shaperUI.addControlOpticGradientColour();
expect($("#control_list #control_gradientcolour").length).toEqual(1);
expect($("#control_list #control_gradientcolour")[0]).toConformToListCSS();
expect($("#control_edge_list #control_edge_gradientcolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_gradientcolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_gradientcolour");
$("#control_gradientcolour_source").attr("value", "#123456");
$("#control_gradientcolour_target").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_gradientcolour_submit");
helper.simulateMouseEvent("click", "control_edge_gradientcolour");
$("#control_edge_gradientcolour_source").attr("value", "#123456");
$("#control_edge_gradientcolour_target").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_edge_gradientcolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -219,7 +219,7 @@
});
waitsFor(function() {
return $("#control_gradientcolour_modal").length === 0;
return $("#control_edge_gradientcolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -227,12 +227,12 @@
it('should be able to add all optic controls to the list', function () {
shaperUI.addAllOptics();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_arrow").length).toEqual(1);
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_gradientcolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_none").length).toEqual(1);
expect($("#control_edge_list #control_edge_arrow").length).toEqual(1);
expect($("#control_edge_list #control_edge_label").length).toEqual(1);
expect($("#control_edge_list #control_edge_singlecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_attributecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_gradientcolour").length).toEqual(1);
});
@ -244,12 +244,12 @@
it('should be able to add all controls to the list', function () {
shaperUI.addAll();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_arrow").length).toEqual(1);
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_gradientcolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_none").length).toEqual(1);
expect($("#control_edge_list #control_edge_arrow").length).toEqual(1);
expect($("#control_edge_list #control_edge_label").length).toEqual(1);
expect($("#control_edge_list #control_edge_singlecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_attributecolour").length).toEqual(1);
expect($("#control_edge_list #control_edge_gradientcolour").length).toEqual(1);
});
});

View File

@ -759,6 +759,147 @@
});
});
});
describe('checking binding to SVG', function() {
it('should be able to permanently bind many functions to events', function() {
var functions = {
a: function() {},
b: function() {},
c: function() {},
d: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
spyOn(functions, "c");
spyOn(functions, "d");
dispatcher.fixSVG("click", functions.a);
dispatcher.fixSVG("click", functions.b);
dispatcher.fixSVG("click", functions.c);
dispatcher.fixSVG("click", functions.d);
helper.simulateMouseEvent("click", "svg");
expect(functions.a).wasCalled();
expect(functions.b).wasCalled();
expect(functions.c).wasCalled();
expect(functions.d).wasCalled();
});
it('should be able to bind temporary functions to events', function() {
var functions = {
a: function() {}
};
spyOn(functions, "a");
dispatcher.bind("svg", "click", functions.a);
helper.simulateMouseEvent("click", "svg");
expect(functions.a).wasCalled();
});
it('should be able to overwrite temporary functions on events', function() {
var functions = {
a: function() {},
b: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
dispatcher.bind("svg", "click", functions.a);
dispatcher.bind("svg", "click", functions.b);
helper.simulateMouseEvent("click", "svg");
expect(functions.b).wasCalled();
expect(functions.a).wasNotCalled();
});
it('should not overwrite permanent functions', function() {
var functions = {
a: function() {},
b: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
dispatcher.fixSVG("click", functions.a);
dispatcher.bind("svg", "click", functions.b);
helper.simulateMouseEvent("click", "svg");
expect(functions.b).wasCalled();
expect(functions.a).wasCalled();
});
it('binding a permanent function should not effect temporary function', function() {
var functions = {
a: function() {},
b: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
dispatcher.bind("svg", "click", functions.b);
dispatcher.fixSVG("click", functions.a);
helper.simulateMouseEvent("click", "svg");
expect(functions.b).wasCalled();
expect(functions.a).wasCalled();
});
it('should be able to bind only the given events and'
+ ' unbind other temporary events', function() {
var functions = {
a: function() {},
b: function() {},
c: function() {},
d: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
spyOn(functions, "c");
spyOn(functions, "d");
dispatcher.bind("svg", "mouseup", functions.a);
dispatcher.bind("svg", "mousedown", functions.b);
dispatcher.bind("svg", "click", functions.c);
dispatcher.rebind("svg", {click: functions.d});
helper.simulateMouseEvent("click", "svg");
helper.simulateMouseEvent("mouseup", "svg");
helper.simulateMouseEvent("mousedown", "svg");
expect(functions.a).wasNotCalled();
expect(functions.b).wasNotCalled();
expect(functions.c).wasNotCalled();
expect(functions.d).wasCalled();
});
it('should not remove permanent events on rebind', function() {
var functions = {
a: function() {},
b: function() {}
};
spyOn(functions, "a");
spyOn(functions, "b");
dispatcher.fixSVG("mousemove", functions.a);
dispatcher.rebind("svg", {click: functions.b});
helper.simulateMouseEvent("mousemove", "svg");
helper.simulateMouseEvent("click", "svg");
expect(functions.a).wasCalled();
expect(functions.b).wasCalled();
});
});
describe('checking rebinding of events', function() {
@ -843,6 +984,8 @@
});
});
});
});

View File

@ -42,6 +42,7 @@
var svg, dispatcher, dispatcherUI, list,
nodeShaper, edgeShaper, layouter,
nodes, edges, adapter,
mousePointerbox,
addSpies = function() {
spyOn(layouter, "drag");
@ -60,17 +61,21 @@
beforeEach(function () {
nodes = [{
_id: 1,
_rev: 1,
_key: 1,
x: 3,
y: 4,
_data: {
_id: 1,
_rev: 1,
_key: 1,
name: "Alice"
}
},{
_id: 2,
_rev: 2,
_key: 2,
x: 1,
y: 2,
_data: {
_rev: 2,
_key: 2,
_id: 2
}
}];
@ -121,16 +126,26 @@
};
svg = document.createElement("svg");
svg.id = "svg";
document.body.appendChild(svg);
nodeShaper = new NodeShaper(d3.select("svg"));
edgeShaper = new EdgeShaper(d3.select("svg"));
list = document.createElement("ul");
document.body.appendChild(list);
list.id = "control_list";
list.id = "control_event_list";
mousePointerbox = document.createElement("svg");
mousePointerbox.id = "mousepointer";
mousePointerbox.className = "mousepointer";
document.body.appendChild(mousePointerbox);
nodeShaper.drawNodes(nodes);
edgeShaper.drawEdges(edges);
dispatcherUI = new EventDispatcherControls(list, nodeShaper, edgeShaper, completeConfig);
dispatcherUI = new EventDispatcherControls(
list, mousePointerbox, nodeShaper, edgeShaper, completeConfig
);
spyOn(nodeShaper, "changeTo").andCallThrough();
spyOn(edgeShaper, "changeTo").andCallThrough();
@ -174,6 +189,7 @@
expect(list).toConformToToolbox();
document.body.removeChild(list);
document.body.removeChild(svg);
document.body.removeChild(mousePointerbox);
});
it('should throw errors if not setup correctly', function() {
@ -182,9 +198,12 @@
}).toThrow("A list element has to be given.");
expect(function() {
var e = new EventDispatcherControls(list);
}).toThrow("The cursor decoration box has to be given.");
expect(function() {
var e = new EventDispatcherControls(list, mousePointerbox);
}).toThrow("The NodeShaper has to be given.");
expect(function() {
var e = new EventDispatcherControls(list, nodeShaper);
var e = new EventDispatcherControls(list, mousePointerbox, nodeShaper);
}).toThrow("The EdgeShaper has to be given.");
});
@ -192,9 +211,9 @@
runs(function() {
dispatcherUI.addControlDrag();
expect($("#control_list #control_drag").length).toEqual(1);
expect($("#control_event_list #control_event_drag").length).toEqual(1);
helper.simulateMouseEvent("click", "control_drag");
helper.simulateMouseEvent("click", "control_event_drag");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
@ -209,6 +228,8 @@
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-move");
helper.simulateDragEvent("1");
expect(layouter.drag).toHaveBeenCalled();
@ -220,9 +241,9 @@
runs(function() {
dispatcherUI.addControlEdit();
expect($("#control_list #control_edit").length).toEqual(1);
expect($("#control_event_list #control_event_edit").length).toEqual(1);
helper.simulateMouseEvent("click", "control_edit");
helper.simulateMouseEvent("click", "control_event_edit");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
@ -238,39 +259,38 @@
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-pencil");
helper.simulateMouseEvent("click", "1");
expect($("#control_node_edit_modal").length).toEqual(1);
expect($("#control_event_node_edit_modal").length).toEqual(1);
$("#control_node_edit_name_value").val("Bob");
$("#control_event_node_edit_name_value").val("Bob");
helper.simulateMouseEvent("click", "control_node_edit_submit");
helper.simulateMouseEvent("click", "control_event_node_edit_submit");
expect(adapter.patchNode).toHaveBeenCalledWith(
nodes[0],
{ _id: "1",
{
name: "Bob"
},
jasmine.any(Function));
});
waitsFor(function() {
return $("#control_node_edit_modal").length === 0;
return $("#control_event_node_edit_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
runs(function() {
helper.simulateMouseEvent("click", "1-2");
expect($("#control_edge_edit_modal").length).toEqual(1);
expect($("#control_event_edge_edit_modal").length).toEqual(1);
$("#control_edge_edit_label_value").val("newLabel");
helper.simulateMouseEvent("click", "control_edge_edit_submit");
$("#control_event_edge_edit_label_value").val("newLabel");
helper.simulateMouseEvent("click", "control_event_edge_edit_submit");
expect(adapter.patchEdge).toHaveBeenCalledWith(
edges[0],
{
_id: "12",
_rev: "12",
_key: "12",
_from: "1",
_to: "2",
label: "newLabel"
@ -279,7 +299,7 @@
});
waitsFor(function() {
return $("#control_edge_edit_modal").length === 0;
return $("#control_event_edge_edit_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -288,9 +308,9 @@
runs(function() {
dispatcherUI.addControlExpand();
expect($("#control_list #control_expand").length).toEqual(1);
expect($("#control_event_list #control_event_expand").length).toEqual(1);
helper.simulateMouseEvent("click", "control_expand");
helper.simulateMouseEvent("click", "control_event_expand");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
@ -305,6 +325,8 @@
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-plus");
helper.simulateMouseEvent("click", "1");
expect(adapter.loadNode).toHaveBeenCalledWith(nodes[0]._id, jasmine.any(Function));
@ -316,9 +338,9 @@
runs(function() {
dispatcherUI.addControlDelete();
expect($("#control_list #control_delete").length).toEqual(1);
expect($("#control_event_list #control_event_delete").length).toEqual(1);
helper.simulateMouseEvent("click", "control_delete");
helper.simulateMouseEvent("click", "control_event_delete");
expect(edgeShaper.changeTo).toHaveBeenCalledWith({
actions: {
@ -334,6 +356,8 @@
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-trash");
helper.simulateMouseEvent("click", "1");
expect(adapter.deleteNode).toHaveBeenCalledWith(
@ -351,48 +375,104 @@
});
});
it('should be able to add a connect control to the list', function() {
runs(function() {
describe('the connect control', function() {
it('should be added to the list', function() {
runs(function() {
dispatcherUI.addControlConnect();
expect($("#control_event_list #control_event_connect").length).toEqual(1);
helper.simulateMouseEvent("click", "control_event_connect");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true,
mousedown: jasmine.any(Function),
mouseup: jasmine.any(Function)
}
});
expect(edgeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true
}
});
expect(mousePointerbox.className).toEqual("mousepointer icon-resize-horizontal");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(adapter.createEdge).toHaveBeenCalledWith(
{source: nodes[1], target: nodes[0]},
jasmine.any(Function)
);
});
});
it('should draw a line from startNode following the cursor', function() {
var line,
cursorX,
cursorY;
spyOn(edgeShaper, "addAnEdgeFollowingTheCursor");
dispatcherUI.addControlConnect();
expect($("#control_list #control_connect").length).toEqual(1);
helper.simulateMouseEvent("click", "control_connect");
expect(nodeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true,
mousedown: jasmine.any(Function),
mouseup: jasmine.any(Function)
}
});
expect(edgeShaper.changeTo).toHaveBeenCalledWith({
actions: {
reset: true
}
});
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(adapter.createEdge).toHaveBeenCalledWith(
{source: nodes[1], target: nodes[0]},
jasmine.any(Function)
expect(edgeShaper.addAnEdgeFollowingTheCursor).toHaveBeenCalledWith(
0, 0
);
});
it('the cursor-line should follow the cursor on mousemove over svg', function() {
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
});
helper.simulateMouseMoveEvent("svg", 40, 50);
var line = $("#connectionLine");
expect(line.attr("x1")).toEqual(String(nodes[1].x));
expect(line.attr("y1")).toEqual(String(nodes[1].y));
expect(line.attr("x2")).toEqual("40");
expect(line.attr("y2")).toEqual("50");
});
it('the cursor-line should disappear on mouseup on svg', function() {
spyOn(edgeShaper, "removeCursorFollowingEdge");
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1-2");
expect(edgeShaper.removeCursorFollowingEdge).toHaveBeenCalled();
});
it('the cursor-line should disappear on mouseup on svg', function() {
spyOn(edgeShaper, "removeCursorFollowingEdge");
dispatcherUI.addControlConnect();
helper.simulateMouseEvent("click", "control_event_connect");
helper.simulateMouseEvent("mousedown", "2");
helper.simulateMouseEvent("mouseup", "1");
expect(edgeShaper.removeCursorFollowingEdge).toHaveBeenCalled();
});
});
it('should be able to add all controls to the list', function () {
dispatcherUI.addAll();
expect($("#control_list #control_drag").length).toEqual(1);
expect($("#control_list #control_edit").length).toEqual(1);
expect($("#control_list #control_expand").length).toEqual(1);
expect($("#control_list #control_delete").length).toEqual(1);
expect($("#control_list #control_connect").length).toEqual(1);
expect($("#control_event_list #control_event_drag").length).toEqual(1);
expect($("#control_event_list #control_event_edit").length).toEqual(1);
expect($("#control_event_list #control_event_expand").length).toEqual(1);
expect($("#control_event_list #control_event_delete").length).toEqual(1);
expect($("#control_event_list #control_event_connect").length).toEqual(1);
});
});

View File

@ -209,21 +209,127 @@
expect(c2._outboundCounter).toEqual(1);
});
it('should expand a community node properly', function() {
var comm = {
_id: "*community_1"
};
nodes.push(comm);
describe('with community nodes', function() {
spyOn(adapterDummy, "expandCommunity");
it('should expand a community node properly', function() {
var comm = {
_id: "*community_1"
};
nodes.push(comm);
testee = eventLib.Expand(config);
testee(comm);
spyOn(adapterDummy, "expandCommunity");
testee = eventLib.Expand(config);
testee(comm);
expect(adapterDummy.expandCommunity).toHaveBeenCalledWith(comm, jasmine.any(Function));
});
it('should remove a community if last pointer to it is collapsed', function() {
runs(function() {
var c0 = {
_id: 0,
_outboundCounter: 1,
_inboundCounter: 0
},
c1 = {
_id: 1,
_expanded: true,
_outboundCounter: 1,
_inboundCounter: 1
},
comm = {
_id: "*community_1",
_outboundCounter: 1,
_inboundCounter: 1
},
c2 = {
_id: 1,
_outboundCounter: 0,
_inboundCounter: 1
},
e0 = {
source: c0,
target: c1
},
e1 = {
source: c1,
target: comm
},
e2 = {
source: comm,
target: c2
};
nodes.push(c0);
nodes.push(c1);
nodes.push(comm);
nodes.push(c2);
edges.push(e0);
edges.push(e1);
edges.push(e2);
testee = eventLib.Expand(config);
testee(c1);
expect(nodes).toEqual([c0, c1]);
expect(edges).toEqual([e0]);
});
});
it('should not remove a community if a pointer to it still exists', function() {
runs(function() {
var c0 = {
_id: 0,
_outboundCounter: 2,
_inboundCounter: 0
},
c1 = {
_id: 1,
_expanded: true,
_outboundCounter: 1,
_inboundCounter: 1
},
comm = {
_id: "*community_1",
_outboundCounter: 0,
_inboundCounter: 2
},
e0 = {
source: c0,
target: c1
},
e1 = {
source: c0,
target: comm
},
e2 = {
source: c1,
target: comm
};
nodes.push(c0);
nodes.push(c1);
nodes.push(comm);
edges.push(e0);
edges.push(e1);
edges.push(e2);
testee = eventLib.Expand(config);
testee(c1);
expect(nodes).toEqual([c0, c1, comm]);
expect(edges).toEqual([e0, e1]);
});
});
expect(adapterDummy.expandCommunity).toHaveBeenCalledWith(comm, jasmine.any(Function));
});
describe('setup process', function() {
var testConfig = {};

View File

@ -154,7 +154,7 @@
+ " should be close to Node " + n2.id
+ " but distance is " + distance;
};
threshold = threshold || 100;
threshold = threshold || 150;
return Math.abs(distance) < threshold;
},
@ -241,7 +241,7 @@
});
it('should position not linked nodes close to each other', function() {
runs(function() {
runs(function() {
nodes = createNodeList(4);
standardConfig.nodes = nodes;
edgeShaper = {"updateEdges": function(){}};
@ -391,10 +391,16 @@
var tmp = new ForceLayouter(config);
/*
expect(mock.size).wasCalledWith([940, 640]);
expect(mock.linkDistance).wasCalledWith(80);
expect(mock.linkDistance).wasCalledWith(240);
expect(mock.gravity).wasCalledWith(0.08);
expect(mock.charge).wasCalledWith(-240);
*/
expect(mock.size).wasCalledWith([940, 640]);
expect(mock.linkDistance).wasCalledWith(240);
expect(mock.gravity).wasCalledWith(0.01);
expect(mock.charge).wasCalledWith(-1000);
});
it('should be able to switch the distance', function() {

View File

@ -49,7 +49,7 @@
layouter = new ForceLayouter(config);
list = document.createElement("ul");
document.body.appendChild(list);
list.id = "control_list";
list.id = "control_layout_list";
layouterUI = new LayouterControls(list, layouter);
spyOn(layouter, 'changeTo');
this.addMatchers({
@ -90,15 +90,15 @@
runs(function() {
layouterUI.addControlGravity();
expect($("#control_list #control_gravity").length).toEqual(1);
expect($("#control_list #control_gravity")[0]).toConformToListCSS();
expect($("#control_layout_list #control_layout_gravity").length).toEqual(1);
expect($("#control_layout_list #control_layout_gravity")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_gravity");
helper.simulateMouseEvent("click", "control_layout_gravity");
expect($("#control_gravity_modal").length).toEqual(1);
expect($("#control_layout_gravity_modal").length).toEqual(1);
$("#control_gravity_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_gravity_submit");
$("#control_layout_gravity_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_layout_gravity_submit");
expect(layouter.changeTo).toHaveBeenCalledWith({
gravity: "42"
@ -107,7 +107,7 @@
});
waitsFor(function() {
return $("#control_gravity_modal").length === 0;
return $("#control_layout_gravity_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -115,15 +115,15 @@
runs(function() {
layouterUI.addControlDistance();
expect($("#control_list #control_distance").length).toEqual(1);
expect($("#control_list #control_distance")[0]).toConformToListCSS();
expect($("#control_layout_list #control_layout_distance").length).toEqual(1);
expect($("#control_layout_list #control_layout_distance")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_distance");
helper.simulateMouseEvent("click", "control_layout_distance");
expect($("#control_distance_modal").length).toEqual(1);
expect($("#control_layout_distance_modal").length).toEqual(1);
$("#control_distance_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_distance_submit");
$("#control_layout_distance_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_layout_distance_submit");
expect(layouter.changeTo).toHaveBeenCalledWith({
distance: "42"
@ -132,7 +132,7 @@
});
waitsFor(function() {
return $("#control_distance_modal").length === 0;
return $("#control_layout_distance_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -140,15 +140,15 @@
runs(function() {
layouterUI.addControlCharge();
expect($("#control_list #control_charge").length).toEqual(1);
expect($("#control_list #control_charge")[0]).toConformToListCSS();
expect($("#control_layout_list #control_layout_charge").length).toEqual(1);
expect($("#control_layout_list #control_layout_charge")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_charge");
helper.simulateMouseEvent("click", "control_layout_charge");
expect($("#control_charge_modal").length).toEqual(1);
expect($("#control_layout_charge_modal").length).toEqual(1);
$("#control_charge_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_charge_submit");
$("#control_layout_charge_value").attr("value", 42);
helper.simulateMouseEvent("click", "control_layout_charge_submit");
expect(layouter.changeTo).toHaveBeenCalledWith({
charge: "42"
@ -157,16 +157,16 @@
});
waitsFor(function() {
return $("#control_charge_modal").length === 0;
return $("#control_layout_charge_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
it('should be able to add all controls to the list', function () {
layouterUI.addAll();
expect($("#control_list #control_gravity").length).toEqual(1);
expect($("#control_list #control_distance").length).toEqual(1);
expect($("#control_list #control_charge").length).toEqual(1);
expect($("#control_layout_list #control_layout_gravity").length).toEqual(1);
expect($("#control_layout_list #control_layout_distance").length).toEqual(1);
expect($("#control_layout_list #control_layout_charge").length).toEqual(1);
});
});

View File

@ -57,6 +57,9 @@
value: value
};
};
r.getCollections = function(callback) {
callback(["nodes"], ["edges"]);
};
return r;
};
//Mock for ZoomManager
@ -190,17 +193,41 @@
});
it('should contain the objects from eventDispatcher', function() {
expect($(toolboxSelector + " #control_drag").length).toEqual(1);
expect($(toolboxSelector + " #control_edit").length).toEqual(1);
expect($(toolboxSelector + " #control_expand").length).toEqual(1);
expect($(toolboxSelector + " #control_delete").length).toEqual(1);
expect($(toolboxSelector + " #control_connect").length).toEqual(1);
expect($(toolboxSelector + " #control_event_drag").length).toEqual(1);
expect($(toolboxSelector + " #control_event_edit").length).toEqual(1);
expect($(toolboxSelector + " #control_event_expand").length).toEqual(1);
expect($(toolboxSelector + " #control_event_delete").length).toEqual(1);
expect($(toolboxSelector + " #control_event_connect").length).toEqual(1);
});
it('should have the correct layout', function() {
expect($(toolboxSelector)[0]).toConformToToolboxLayout();
});
it('should create the additional mouse-icon box', function() {
var pointerBox = $("#contentDiv #mousepointer");
expect(pointerBox.length).toEqual(1);
expect(pointerBox[0]).toBeTag("div");
expect(pointerBox[0]).toBeOfClass("mousepointer");
});
it('should position the mouse-icon box next to the mouse pointer', function() {
var x = 40,
y = 50,
pointerBox = $("#contentDiv #mousepointer");
helper.simulateMouseMoveEvent("graphViewerSVG", x, y);
expect(pointerBox.offset().left).toEqual(x + 7);
expect(pointerBox.offset().top).toEqual(y + 12);
x = 66;
y = 33;
helper.simulateMouseMoveEvent("graphViewerSVG", x, y);
expect(pointerBox.offset().left).toEqual(x + 7);
expect(pointerBox.offset().top).toEqual(y + 12);
});
});
describe('checking the menubar', function() {
@ -263,12 +290,14 @@
expect($(menuSelector + " #control_gradientcolour").length).toEqual(1);
});
*/
/*
it('should contain a menu for the adapter', function() {
var menuSelector = "#contentDiv #menubar #adaptermenu";
expect($(menuSelector).length).toEqual(1);
expect($(menuSelector)[0]).toBeADropdownMenu();
expect($(menuSelector + " #control_collections").length).toEqual(1);
});
*/
/*
it('should contain a menu for the layouter', function() {
var menuSelector = "#contentDiv #menubar #layoutermenu";
@ -280,6 +309,15 @@
});
*/
it('should contain a general configure menu', function() {
var menuSelector = "#contentDiv #menubar #configuremenu";
expect($(menuSelector).length).toEqual(1);
expect($(menuSelector)[0]).toBeADropdownMenu();
expect($("> button", menuSelector).text()).toEqual("Configure ");
expect($(menuSelector + " #control_adapter_collections").length).toEqual(1);
expect($(menuSelector + " #control_node_label").length).toEqual(1);
});
it('should have the same layout as the web interface', function() {
var header = div.children[0],
transHeader = header.firstChild,
@ -296,8 +334,10 @@
expect(searchField.id).toEqual("transparentPlaceholder");
expect(searchField.className).toEqual("pull-left");
expect(searchField.children[0].id).toEqual("attribute");
expect(searchField.children[1].id).toEqual("value");
expect(searchField.children[2].id).toEqual("loadnode");
expect(searchField.children[1]).toBeTag("span");
expect(searchField.children[1].textContent).toEqual("==");
expect(searchField.children[2].id).toEqual("value");
expect(searchField.children[3].id).toEqual("loadnode");
});
});
@ -444,7 +484,7 @@
runs (function() {
$("#contentDiv #menubar #value").attr("value", "0");
helper.simulateMouseEvent("click", "loadnode");
helper.simulateMouseEvent("click", "control_expand");
helper.simulateMouseEvent("click", "control_event_expand");
});
waits(waittime);

View File

@ -98,6 +98,12 @@
expect(reducer.getCommunity.length).toEqual(2);
});
it('should offer a function for bucket sort of nodes', function() {
expect(reducer.bucketNodes).toBeDefined();
expect(reducer.bucketNodes).toEqual(jasmine.any(Function));
expect(reducer.bucketNodes.length).toEqual(2);
});
});
describe('checking community identification', function() {
@ -154,6 +160,146 @@
});
describe('checking bucket sort of nodes', function() {
var allNodes, buckets;
beforeEach(function() {
allNodes = [];
this.addMatchers({
toContainAll: function(objs) {
var bucket = this.actual,
passed = true;
_.each(bucket, function(n) {
var i;
for (i = 0; i < objs.length; i++) {
if (objs[i] === n) {
return;
}
}
passed = false;
});
this.message = function() {
return JSON.stringify(bucket)
+ " should contain all of "
+ JSON.stringify(objs);
};
return passed;
}
});
});
it('should not bucket anything if #nodes <= #buckets', function() {
buckets = 5;
allNodes.push({a: 1});
allNodes.push({a: 1});
allNodes.push({a: 1});
allNodes.push({a: 1});
allNodes.push({a: 1});
var res = reducer.bucketNodes(allNodes, buckets);
expect(res.length).toEqual(5);
expect(res[0].length).toEqual(1);
expect(res[1].length).toEqual(1);
expect(res[2].length).toEqual(1);
expect(res[3].length).toEqual(1);
expect(res[4].length).toEqual(1);
});
it('should create at most the given amount of buckets', function() {
buckets = 3;
allNodes.push({a: 1});
allNodes.push({b: 2});
allNodes.push({c: 3});
allNodes.push({d: 4});
allNodes.push({e: 5});
allNodes.push({f: 6});
var res = reducer.bucketNodes(allNodes, buckets);
expect(res.length).toEqual(3);
});
it('should uniformly distribute dissimilar nodes', function() {
buckets = 3;
allNodes.push({a: 1});
allNodes.push({b: 2});
allNodes.push({c: 3});
allNodes.push({d: 4});
allNodes.push({e: 5});
allNodes.push({f: 6});
allNodes.push({g: 7});
allNodes.push({h: 8});
allNodes.push({i: 9});
var res = reducer.bucketNodes(allNodes, buckets);
expect(res[0].length).toEqual(3);
expect(res[1].length).toEqual(3);
expect(res[2].length).toEqual(3);
});
it('should bucket clearly similar nodes together', function() {
buckets = 3;
var a1, a2 ,a3,
b1, b2, b3,
c1, c2, c3,
resArray,
res1,
res2,
res3;
a1 = {a: 1};
a2 = {a: 1};
a3 = {a: 1};
b1 = {b: 2};
b2 = {b: 2};
b3 = {b: 2};
c1 = {c: 3};
c2 = {c: 3};
c3 = {c: 3};
allNodes.push(a1);
allNodes.push(a2);
allNodes.push(a3);
allNodes.push(b1);
allNodes.push(b2);
allNodes.push(b3);
allNodes.push(c1);
allNodes.push(c2);
allNodes.push(c3);
resArray = reducer.bucketNodes(allNodes, buckets);
res1 = resArray[0];
res2 = resArray[1];
res3 = resArray[2];
if (res1[0].a !== undefined) {
expect(res1).toContainAll([a1, a2, a3]);
} else if (res2[0].a !== undefined) {
expect(res2).toContainAll([a1, a2, a3]);
} else {
expect(res3).toContainAll([a1, a2, a3]);
}
if (res1[0].b !== undefined) {
expect(res1).toContainAll([b1, b2, b3]);
} else if (res2[0].b !== undefined) {
expect(res2).toContainAll([b1, b2, b3]);
} else {
expect(res3).toContainAll([b1, b2, b3]);
}
if (res1[0].c !== undefined) {
expect(res1).toContainAll([c1, c2, c3]);
} else if (res2[0].c !== undefined) {
expect(res2).toContainAll([c1, c2, c3]);
} else {
expect(res3).toContainAll([c1, c2, c3]);
}
});
});
});
});
}());

View File

@ -47,7 +47,7 @@
shaper = new NodeShaper(d3.select("svg"));
list = document.createElement("ul");
document.body.appendChild(list);
list.id = "control_list";
list.id = "control_node_list";
shaperUI = new NodeShaperControls(list, shaper);
spyOn(shaper, 'changeTo');
this.addMatchers({
@ -94,10 +94,10 @@
runs(function() {
shaperUI.addControlOpticShapeNone();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_none")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_none").length).toEqual(1);
expect($("#control_node_list #control_node_none")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_none");
helper.simulateMouseEvent("click", "control_node_none");
expect(shaper.changeTo).toHaveBeenCalledWith({
shape: {
@ -111,14 +111,14 @@
runs(function() {
shaperUI.addControlOpticShapeCircle();
expect($("#control_list #control_circle").length).toEqual(1);
expect($("#control_list #control_circle")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_circle").length).toEqual(1);
expect($("#control_node_list #control_node_circle")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_circle");
expect($("#control_circle_modal").length).toEqual(1);
helper.simulateMouseEvent("click", "control_node_circle");
expect($("#control_node_circle_modal").length).toEqual(1);
$("#control_circle_radius").attr("value", 42);
helper.simulateMouseEvent("click", "control_circle_submit");
$("#control_node_circle_radius").attr("value", 42);
helper.simulateMouseEvent("click", "control_node_circle_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
shape: {
@ -129,7 +129,7 @@
});
waitsFor(function() {
return $("#control_circle_modal").length === 0;
return $("#control_node_circle_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -138,13 +138,13 @@
runs(function() {
shaperUI.addControlOpticShapeRect();
expect($("#control_list #control_rect").length).toEqual(1);
expect($("#control_list #control_rect")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_rect").length).toEqual(1);
expect($("#control_node_list #control_node_rect")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_rect");
$("#control_rect_width").attr("value", 42);
$("#control_rect_height").attr("value", 12);
helper.simulateMouseEvent("click", "control_rect_submit");
helper.simulateMouseEvent("click", "control_node_rect");
$("#control_node_rect_width").attr("value", 42);
$("#control_node_rect_height").attr("value", 12);
helper.simulateMouseEvent("click", "control_node_rect_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
shape: {
@ -156,7 +156,7 @@
});
waitsFor(function() {
return $("#control_rect_modal").length === 0;
return $("#control_node_rect_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -165,12 +165,12 @@
runs(function() {
shaperUI.addControlOpticLabel();
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_label")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_label").length).toEqual(1);
expect($("#control_node_list #control_node_label")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_label");
$("#control_label_key").attr("value", "theAnswer");
helper.simulateMouseEvent("click", "control_label_submit");
helper.simulateMouseEvent("click", "control_node_label");
$("#control_node_label_key").attr("value", "theAnswer");
helper.simulateMouseEvent("click", "control_node_label_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
label: "theAnswer"
@ -178,7 +178,7 @@
});
waitsFor(function() {
return $("#control_label_modal").length === 0;
return $("#control_node_label_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -187,13 +187,13 @@
runs(function() {
shaperUI.addControlOpticSingleColour();
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_singlecolour")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_singlecolour").length).toEqual(1);
expect($("#control_node_list #control_node_singlecolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_singlecolour");
$("#control_singlecolour_fill").attr("value", "#123456");
$("#control_singlecolour_stroke").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_singlecolour_submit");
helper.simulateMouseEvent("click", "control_node_singlecolour");
$("#control_node_singlecolour_fill").attr("value", "#123456");
$("#control_node_singlecolour_stroke").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_node_singlecolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -205,7 +205,7 @@
});
waitsFor(function() {
return $("#control_singlecolour_modal").length === 0;
return $("#control_node_singlecolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -214,12 +214,12 @@
runs(function() {
shaperUI.addControlOpticAttributeColour();
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_attributecolour").length).toEqual(1);
expect($("#control_node_list #control_node_attributecolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_attributecolour");
$("#control_attributecolour_key").attr("value", "label");
helper.simulateMouseEvent("click", "control_attributecolour_submit");
helper.simulateMouseEvent("click", "control_node_attributecolour");
$("#control_node_attributecolour_key").attr("value", "label");
helper.simulateMouseEvent("click", "control_node_attributecolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -230,7 +230,7 @@
});
waitsFor(function() {
return $("#control_attributecolour_modal").length === 0;
return $("#control_node_attributecolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -239,13 +239,13 @@
runs(function() {
shaperUI.addControlOpticExpandColour();
expect($("#control_list #control_expandcolour").length).toEqual(1);
expect($("#control_list #control_expandcolour")[0]).toConformToListCSS();
expect($("#control_node_list #control_node_expandcolour").length).toEqual(1);
expect($("#control_node_list #control_node_expandcolour")[0]).toConformToListCSS();
helper.simulateMouseEvent("click", "control_expandcolour");
$("#control_expandcolour_expanded").attr("value", "#123456");
$("#control_expandcolour_collapsed").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_expandcolour_submit");
helper.simulateMouseEvent("click", "control_node_expandcolour");
$("#control_node_expandcolour_expanded").attr("value", "#123456");
$("#control_node_expandcolour_collapsed").attr("value", "#654321");
helper.simulateMouseEvent("click", "control_node_expandcolour_submit");
expect(shaper.changeTo).toHaveBeenCalledWith({
color: {
@ -257,7 +257,7 @@
});
waitsFor(function() {
return $("#control_expandcolour_modal").length === 0;
return $("#control_node_expandcolour_modal").length === 0;
}, 2000, "The modal dialog should disappear.");
});
@ -266,13 +266,13 @@
it('should be able to add all optic controls to the list', function () {
shaperUI.addAllOptics();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_circle").length).toEqual(1);
expect($("#control_list #control_rect").length).toEqual(1);
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_expandcolour").length).toEqual(1);
expect($("#control_node_list #control_node_none").length).toEqual(1);
expect($("#control_node_list #control_node_circle").length).toEqual(1);
expect($("#control_node_list #control_node_rect").length).toEqual(1);
expect($("#control_node_list #control_node_label").length).toEqual(1);
expect($("#control_node_list #control_node_singlecolour").length).toEqual(1);
expect($("#control_node_list #control_node_attributecolour").length).toEqual(1);
expect($("#control_node_list #control_node_expandcolour").length).toEqual(1);
});
it('should be able to add all action controls to the list', function () {
@ -283,13 +283,13 @@
it('should be able to add all controls to the list', function () {
shaperUI.addAll();
expect($("#control_list #control_none").length).toEqual(1);
expect($("#control_list #control_circle").length).toEqual(1);
expect($("#control_list #control_rect").length).toEqual(1);
expect($("#control_list #control_label").length).toEqual(1);
expect($("#control_list #control_singlecolour").length).toEqual(1);
expect($("#control_list #control_attributecolour").length).toEqual(1);
expect($("#control_list #control_expandcolour").length).toEqual(1);
expect($("#control_node_list #control_node_none").length).toEqual(1);
expect($("#control_node_list #control_node_circle").length).toEqual(1);
expect($("#control_node_list #control_node_rect").length).toEqual(1);
expect($("#control_node_list #control_node_label").length).toEqual(1);
expect($("#control_node_list #control_node_singlecolour").length).toEqual(1);
expect($("#control_node_list #control_node_attributecolour").length).toEqual(1);
expect($("#control_node_list #control_node_expandcolour").length).toEqual(1);
});
});

View File

@ -214,7 +214,7 @@
fontMax = 16;
fontMin = 6;
radMax = 25;
radMin = 1;
radMin = 4;
distRBase = 100;
minScale = radMin / radMax;
toggleScale = fontMin / fontMax;

View File

@ -41,23 +41,32 @@ function ArangoAdapterControls(list, adapter) {
baseClass = "adapter";
this.addControlChangeCollections = function() {
var prefix = "control_collections",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Collections", prefix, function() {
modalDialogHelper.createModalDialog("Switch Collections",
idprefix, [{
type: "text",
id: "nodecollection"
},{
type: "text",
id: "edgecollection"
}], function () {
var nodes = $("#" + idprefix + "nodecollection").attr("value"),
edges = $("#" + idprefix + "edgecollection").attr("value");
adapter.changeTo(nodes, edges);
}
);
var prefix = "control_adapter_collections",
idprefix = prefix + "_";
adapter.getCollections(function(nodeCols, edgeCols) {
uiComponentsHelper.createButton(baseClass, list, "Collections", prefix, function() {
modalDialogHelper.createModalDialog("Switch Collections",
idprefix, [{
type: "list",
id: "nodecollection",
objects: nodeCols
},{
type: "list",
id: "edgecollection",
objects: edgeCols
},{
type: "checkbox",
id: "undirected"
}], function () {
var nodes = $("#" + idprefix + "nodecollection").attr("value"),
edges = $("#" + idprefix + "edgecollection").attr("value"),
undirected = !!$("#" + idprefix + "undirected").attr("checked");
adapter.changeTo(nodes, edges, undirected);
}
);
});
});
};
this.addAll = function() {

View File

@ -41,7 +41,7 @@ function EdgeShaperControls(list, shaper) {
baseClass = "graph";
this.addControlOpticShapeNone = function() {
var prefix = "control_none",
var prefix = "control_edge_none",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "None", prefix, function() {
shaper.changeTo({
@ -53,7 +53,7 @@ function EdgeShaperControls(list, shaper) {
};
this.addControlOpticShapeArrow = function() {
var prefix = "control_arrow",
var prefix = "control_edge_arrow",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Arrow", prefix, function() {
shaper.changeTo({
@ -67,7 +67,7 @@ function EdgeShaperControls(list, shaper) {
this.addControlOpticLabel = function() {
var prefix = "control_label",
var prefix = "control_edge_label",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Label", prefix, function() {
modalDialogHelper.createModalDialog("Switch Label Attribute",
@ -88,7 +88,7 @@ function EdgeShaperControls(list, shaper) {
this.addControlOpticSingleColour = function() {
var prefix = "control_singlecolour",
var prefix = "control_edge_singlecolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Single Colour", prefix, function() {
modalDialogHelper.createModalDialog("Switch to Colour",
@ -109,7 +109,7 @@ function EdgeShaperControls(list, shaper) {
};
this.addControlOpticAttributeColour = function() {
var prefix = "control_attributecolour",
var prefix = "control_edge_attributecolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Colour by Attribute", prefix, function() {
modalDialogHelper.createModalDialog("Display colour by attribute",
@ -130,7 +130,7 @@ function EdgeShaperControls(list, shaper) {
};
this.addControlOpticGradientColour = function() {
var prefix = "control_gradientcolour",
var prefix = "control_edge_gradientcolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Gradient Colour", prefix, function() {
modalDialogHelper.createModalDialog("Change colours for gradient",

View File

@ -1,6 +1,6 @@
/*jslint indent: 2, nomen: true, maxlen: 100, white: true plusplus: true */
/*global $, _, d3*/
/*global document*/
/*global document, window*/
/*global modalDialogHelper, uiComponentsHelper */
/*global EventDispatcher, EventLibrary*/
////////////////////////////////////////////////////////////////////////////////
@ -29,12 +29,15 @@
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig) {
function EventDispatcherControls(list, cursorIconBox, nodeShaper, edgeShaper, dispatcherConfig) {
"use strict";
if (list === undefined) {
throw "A list element has to be given.";
}
if (cursorIconBox === undefined) {
throw "The cursor decoration box has to be given.";
}
if (nodeShaper === undefined) {
throw "The NodeShaper has to be given.";
}
@ -53,6 +56,10 @@ function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig)
eventlib = new EventLibrary(),
dispatcher = new EventDispatcher(nodeShaper, edgeShaper, dispatcherConfig),
setCursorIcon = function(icon) {
cursorIconBox.className = "mousepointer icon-" + icon;
},
appendToList = function(button) {
if (firstButton) {
currentListGroup = document.createElement("div");
@ -72,14 +79,14 @@ function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig)
baseClass,
list,
title,
"control_" + title,
"control_event_" + title,
callback
);
},
createIcon = function(icon, title, callback) {
var btn = uiComponentsHelper.createIconButton(
icon,
"control_" + title,
"control_event_" + title,
callback
);
appendToList(btn);
@ -89,33 +96,72 @@ function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig)
},
rebindEdges = function(actions) {
dispatcher.rebind("edges", actions);
},
rebindSVG = function(actions) {
dispatcher.rebind("svg", actions);
},
getCursorPosition = function (ev) {
var e = ev || window.event,
res = {};
res.x = e.clientX;
res.y = e.clientY;
res.x += document.body.scrollLeft;
res.y += document.body.scrollTop;
return res;
},
getCursorPositionInSVG = function (ev) {
var pos = getCursorPosition(ev);
pos.x -= $('svg').offset().left;
pos.y -= $('svg').offset().top;
return pos;
},
moveCursorBox = function(ev) {
var pos = getCursorPosition(ev);
pos.x += 7;
pos.y += 12;
cursorIconBox.style.position = "absolute";
cursorIconBox.style.left = pos.x + 'px';
cursorIconBox.style.top = pos.y + 'px';
};
dispatcher.fixSVG("mousemove", moveCursorBox);
dispatcher.fixSVG("mouseout", function() {
cursorIconBox.style.display = "none";
});
dispatcher.fixSVG("mouseover", function() {
cursorIconBox.style.display = "block";
});
this.addControlDrag = function() {
var prefix = "control_drag",
var prefix = "control_event_drag",
idprefix = prefix + "_",
icon = "move",
callback = function() {
setCursorIcon(icon);
rebindNodes( {
drag: dispatcher.events.DRAG
});
rebindEdges();
rebindSVG();
};
createIcon("move", "drag", callback);
createIcon(icon, "drag", callback);
};
this.addControlEdit = function() {
var prefix = "control_edit",
var prefix = "control_event_edit",
idprefix = prefix + "_",
icon = "pencil",
nodeCallback = function(n) {
modalDialogHelper.createModalEditDialog(
"Edit Node " + n._id,
"control_node_edit_",
"control_event_node_edit_",
n._data,
function(newData) {
dispatcher.events.PATCHNODE(n, newData, function() {
$("#control_node_edit_modal").modal('hide');
$("#control_event_node_edit_modal").modal('hide');
})();
}
);
@ -123,59 +169,83 @@ function EventDispatcherControls(list, nodeShaper, edgeShaper, dispatcherConfig)
edgeCallback = function(e) {
modalDialogHelper.createModalEditDialog(
"Edit Edge " + e._data._from + "->" + e._data._to,
"control_edge_edit_",
"control_event_edge_edit_",
e._data,
function(newData) {
dispatcher.events.PATCHEDGE(e, newData, function() {
$("#control_edge_edit_modal").modal('hide');
$("#control_event_edge_edit_modal").modal('hide');
})();
}
);
},
callback = function() {
setCursorIcon(icon);
rebindNodes({click: nodeCallback});
rebindEdges({click: edgeCallback});
rebindSVG();
};
createIcon("pencil", "edit", callback);
createIcon(icon, "edit", callback);
};
this.addControlExpand = function() {
var prefix = "control_expand",
var prefix = "control_event_expand",
idprefix = prefix + "_",
icon = "plus",
callback = function() {
setCursorIcon(icon);
rebindNodes({click: dispatcher.events.EXPAND});
rebindEdges();
rebindSVG();
};
createIcon("plus", "expand", callback);
createIcon(icon, "expand", callback);
};
this.addControlDelete = function() {
var prefix = "control_delete",
var prefix = "control_event_delete",
idprefix = prefix + "_",
icon = "trash",
callback = function() {
setCursorIcon(icon);
rebindNodes({click: dispatcher.events.DELETENODE(function() {
})});
rebindEdges({click: dispatcher.events.DELETEEDGE(function() {
})});
rebindSVG();
};
createIcon("trash", "delete", callback);
createIcon(icon, "delete", callback);
};
this.addControlConnect = function() {
var prefix = "control_connect",
var prefix = "control_event_connect",
idprefix = prefix + "_",
icon = "resize-horizontal",
callback = function() {
setCursorIcon(icon);
rebindNodes({
mousedown: dispatcher.events.STARTCREATEEDGE(),
mousedown: dispatcher.events.STARTCREATEEDGE(function(startNode, ev) {
var pos = getCursorPositionInSVG(ev);
var moveCB = edgeShaper.addAnEdgeFollowingTheCursor(pos.x, pos.y);
dispatcher.bind("svg", "mousemove", function(ev) {
var pos = getCursorPositionInSVG(ev);
moveCB(pos.x, pos.y);
});
}),
mouseup: dispatcher.events.FINISHCREATEEDGE(function(edge){
edgeShaper.removeCursorFollowingEdge();
dispatcher.bind("svg", "mousemove", function(){});
})
});
rebindEdges();
rebindSVG({
mouseup: function() {
dispatcher.events.CANCELCREATEEDGE();
edgeShaper.removeCursorFollowingEdge();
}
});
};
createIcon("resize-horizontal", "connect", callback);
createIcon(icon, "connect", callback);
};

View File

@ -2,7 +2,7 @@
/*global document, $, _ */
/*global EventDispatcherControls, NodeShaperControls, EdgeShaperControls */
/*global LayouterControls, ArangoAdapterControls*/
/*global GraphViewer, d3*/
/*global GraphViewer, d3, window*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
@ -30,7 +30,7 @@
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
function GraphViewerUI(container, adapterConfig, optWidth, optHeight, viewerConfig) {
"use strict";
if (container === undefined) {
@ -48,7 +48,9 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
height = optHeight || container.offsetHeight,
menubar = document.createElement("ul"),
background = document.createElement("div"),
svg,
mousePointerBox = document.createElement("div"),
svg,
makeBootstrapDropdown = function (div, id, title) {
var btn, caret, list;
div.className = "btn-group";
@ -69,6 +71,7 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
createSVG = function () {
return d3.select("#" + container.id + " #background")
.append("svg")
.attr("id", "graphViewerSVG")
.attr("width",width)
.attr("height",height)
.attr("class", "pull-right graphViewer")
@ -78,13 +81,17 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
var toolbox = document.createElement("div"),
dispatcherUI = new EventDispatcherControls(
toolbox,
mousePointerBox,
graphViewer.nodeShaper,
graphViewer.edgeShaper,
graphViewer.dispatcherConfig
);
toolbox.id = "toolbox";
toolbox.className = "btn-group btn-group-vertical pull-left toolbox";
mousePointerBox.id = "mousepointer";
mousePointerBox.className = "mousepointer";
background.appendChild(toolbox);
background.appendChild(mousePointerBox);
dispatcherUI.addAll();
},
createMenu = function() {
@ -94,6 +101,14 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
searchValueField = document.createElement("input"),
searchStart = document.createElement("img"),
buttons = document.createElement("div"),
equalsField = document.createElement("span"),
configureDropDown = document.createElement("div"),
configureList = makeBootstrapDropdown(
configureDropDown,
"configuredropdown",
"Configure"
),
/*
nodeShaperDropDown = document.createElement("div"),
nodeShaperList = makeBootstrapDropdown(
@ -107,14 +122,12 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
"edgeshaperdropdown",
"Edges"
),
*/
adapterDropDown = document.createElement("div"),
adapterList = makeBootstrapDropdown(
adapterDropDown,
"adapterdropdown",
"Connection"
),
/*
layouterDropDown = document.createElement("div"),
layouterList = makeBootstrapDropdown(
layouterDropDown,
@ -133,11 +146,21 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
layouterList,
graphViewer.layouter
),
*/
adapterUI = new ArangoAdapterControls(
adapterList,
graphViewer.adapter
),
*/
nodeShaperUI = new NodeShaperControls(
configureList,
graphViewer.nodeShaper
),
adapterUI = new ArangoAdapterControls(
configureList,
graphViewer.adapter
),
searchFunction = function() {
if (searchAttrField.value === ""
|| searchAttrField.value === undefined) {
@ -175,13 +198,18 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
searchStart.height = 16;
searchStart.src = "img/enter_icon.png";
equalsField.className = "searchEqualsLabel";
equalsField.appendChild(document.createTextNode("=="));
/*
nodeShaperDropDown.id = "nodeshapermenu";
edgeShaperDropDown.id = "edgeshapermenu";
layouterDropDown.id = "layoutermenu";
*/
adapterDropDown.id = "adaptermenu";
*/
configureDropDown.id = "configuremenu";
searchStart.onclick = searchFunction;
$(searchValueField).keypress(function(e) {
@ -195,34 +223,36 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight) {
menubar.appendChild(transparentHeader);
transparentHeader.appendChild(searchDiv);
searchDiv.appendChild(searchAttrField);
searchDiv.appendChild(equalsField);
searchDiv.appendChild(searchValueField);
searchDiv.appendChild(searchStart);
transparentHeader.appendChild(buttons);
buttons.appendChild(configureDropDown);
adapterUI.addControlChangeCollections();
nodeShaperUI.addControlOpticLabel();
/*
buttons.appendChild(nodeShaperDropDown);
buttons.appendChild(edgeShaperDropDown);
buttons.appendChild(layouterDropDown);
*/
buttons.appendChild(adapterDropDown);
/*
transparentHeader.appendChild(nodeShaperDropDown);
transparentHeader.appendChild(edgeShaperDropDown);
transparentHeader.appendChild(adapterDropDown);
transparentHeader.appendChild(layouterDropDown);
*/
/*
nodeShaperUI.addAll();
edgeShaperUI.addAll();
layouterUI.addAll();
*/
adapterUI.addAll();
*/
};
container.appendChild(menubar);
container.appendChild(background);
background.className = "thumbnails";
background.id = "background";
svg = createSVG();
graphViewer = new GraphViewer(svg, width, height, adapterConfig, {zoom: true});
viewerConfig = viewerConfig || {};
viewerConfig.zoom = true;
graphViewer = new GraphViewer(svg, width, height, adapterConfig, viewerConfig);
createToolbox();
createMenu();

View File

@ -41,7 +41,7 @@ function LayouterControls(list, layouter) {
baseClass = "layout";
this.addControlGravity = function() {
var prefix = "control_gravity",
var prefix = "control_layout_gravity",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Gravity", prefix, function() {
modalDialogHelper.createModalDialog("Switch Gravity Strength",
@ -59,7 +59,7 @@ function LayouterControls(list, layouter) {
};
this.addControlCharge = function() {
var prefix = "control_charge",
var prefix = "control_layout_charge",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Charge", prefix, function() {
modalDialogHelper.createModalDialog("Switch Charge Strength",
@ -77,7 +77,7 @@ function LayouterControls(list, layouter) {
};
this.addControlDistance = function() {
var prefix = "control_distance",
var prefix = "control_layout_distance",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Distance", prefix, function() {
modalDialogHelper.createModalDialog("Switch Distance Strength",

View File

@ -57,7 +57,7 @@ var modalDialogHelper = modalDialogHelper || {};
document.body.removeChild(div);
};
headerDiv.className = "modal_header";
headerDiv.className = "modal-header";
buttonDismiss.className = "close";
buttonDismiss.dataDismiss = "modal";
@ -66,11 +66,11 @@ var modalDialogHelper = modalDialogHelper || {};
header.appendChild(document.createTextNode(title));
bodyDiv.className = "modal_body";
bodyDiv.className = "modal-body";
bodyTable.id = idprefix + "table";
footerDiv.className = "modal_footer";
footerDiv.className = "modal-footer";
buttonCancel.id = idprefix + "cancel";
buttonCancel.className = "btn btn-danger pull-left";
@ -132,6 +132,25 @@ var modalDialogHelper = modalDialogHelper || {};
input.id = idprefix + o.id;
contentTh.appendChild(input);
break;
case "checkbox":
input = document.createElement("input");
input.type = "checkbox";
input.id = idprefix + o.id;
contentTh.appendChild(input);
break;
case "list":
input = document.createElement("select");
input.id = idprefix + o.id;
contentTh.appendChild(input);
_.each(o.objects, function(entry) {
var option = document.createElement("option");
option.value = entry;
option.appendChild(
document.createTextNode(entry)
);
input.appendChild(option);
});
break;
default:
//Sorry unknown
table.removeChild(tr);

View File

@ -41,7 +41,7 @@ function NodeShaperControls(list, shaper) {
baseClass = "graph";
this.addControlOpticShapeNone = function() {
uiComponentsHelper.createButton(baseClass, list, "None", "control_none", function() {
uiComponentsHelper.createButton(baseClass, list, "None", "control_node_none", function() {
shaper.changeTo({
shape: {
type: NodeShaper.shapes.NONE
@ -51,7 +51,7 @@ function NodeShaperControls(list, shaper) {
};
this.addControlOpticShapeCircle = function() {
var prefix = "control_circle",
var prefix = "control_node_circle",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Circle", prefix, function() {
modalDialogHelper.createModalDialog("Switch to Circle",
@ -72,11 +72,11 @@ function NodeShaperControls(list, shaper) {
};
this.addControlOpticShapeRect = function() {
var prefix = "control_rect",
var prefix = "control_node_rect",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Rectangle", prefix, function() {
modalDialogHelper.createModalDialog("Switch to Rectangle",
"control_rect_", [{
"control_node_rect_", [{
type: "text",
id: "width"
},{
@ -98,7 +98,7 @@ function NodeShaperControls(list, shaper) {
};
this.addControlOpticLabel = function() {
var prefix = "control_label",
var prefix = "control_node_label",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Label", prefix, function() {
modalDialogHelper.createModalDialog("Switch Label Attribute",
@ -120,7 +120,7 @@ function NodeShaperControls(list, shaper) {
//////////////////////////////////////////////////////////////////
this.addControlOpticSingleColour = function() {
var prefix = "control_singlecolour",
var prefix = "control_node_singlecolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Single Colour", prefix, function() {
modalDialogHelper.createModalDialog("Switch to Colour",
@ -146,7 +146,7 @@ function NodeShaperControls(list, shaper) {
};
this.addControlOpticAttributeColour = function() {
var prefix = "control_attributecolour",
var prefix = "control_node_attributecolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Colour by Attribute", prefix, function() {
modalDialogHelper.createModalDialog("Display colour by attribute",
@ -167,7 +167,7 @@ function NodeShaperControls(list, shaper) {
};
this.addControlOpticExpandColour = function() {
var prefix = "control_expandcolour",
var prefix = "control_node_expandcolour",
idprefix = prefix + "_";
uiComponentsHelper.createButton(baseClass, list, "Expansion Colour", prefix, function() {
modalDialogHelper.createModalDialog("Display colours for expansion",

View File

@ -1,8 +1,9 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone*/
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.arangoCollection = Backbone.Model.extend({
initialize: function () {
'use strict';
},
urlRoot: "/_api/collection",

View File

@ -1,8 +1,9 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone*/
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.arangoDocument = Backbone.Model.extend({
initialize: function () {
'use strict';
},
urlRoot: "/_api/document",
defaults: {

View File

@ -1,8 +1,9 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone*/
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.arangoLog = Backbone.Model.extend({
initialize: function () {
'use strict';
},
urlRoot: "/_admin/log",
defaults: {

View File

@ -1,10 +1,12 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone*/
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.Statistics = Backbone.Model.extend({
defaults: {
},
url: function() {
'use strict';
return "../statistics";
}
});

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global window, Backbone*/
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.StatisticsDescription = Backbone.Model.extend({
defaults: {
@ -7,6 +7,8 @@ window.StatisticsDescription = Backbone.Model.extend({
"groups" : ""
},
url: function() {
'use strict';
return "../statistics-description";
}
});

View File

@ -1,3 +1,6 @@
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, continue: true, regexp: true */
/*global require, window, Backbone */
window.Foxx = Backbone.Model.extend({
defaults: {
"title": "",
@ -8,6 +11,8 @@ window.Foxx = Backbone.Model.extend({
},
url: function() {
'use strict';
if (this.get("_key")) {
return "../aardvark/foxxes/" + this.get("_key");
}
@ -15,6 +20,8 @@ window.Foxx = Backbone.Model.extend({
},
isNew: function() {
'use strict';
return false;
}

View File

@ -35,7 +35,7 @@
<p>Theres no way back…</p>
</div>
<div class="modal-footer">
<button id="confirmDeleteBtn" class="btn btn-danger" style="float:right">Delete</button>
<button id="confirmDeleteBtn" class="btn btn-danger" style="float:right" disabled="true">Delete</button>
</div>
</div>

View File

@ -1,22 +1,54 @@
<form action="javascript:void(0);" autocomplete="on" class="form-horizontal" id="creationDialog">
<fieldset>
<legend>Please give the collections</legend>
<div class="control-group">
<label for="nodeCollection" class="control-label">Node Collection</label>
<div class="controls">
<input id="nodeCollection" type="text" name="nodeCollection" placeholder="Node Collection" maxlength="75" class="input-xlarge" value="Classes">
<div class="thumbnails" id="background">
<form action="javascript:void(0);" autocomplete="on" class="form-horizontal" id="creationDialog">
<fieldset>
<legend>Configuration</legend>
<div class="control-group">
<label for="nodeCollection" class="control-label">Node Collection</label>
<div class="controls">
<input id="nodeCollection" type="text" name="nodeCollection" placeholder="Node Collection" maxlength="75" class="input-xlarge" value="Classes">
</div>
</div>
</div>
<div class="control-group">
<label for="edgeCollection" class="control-label">Edge Collection</label>
<div class="controls">
<input id="edgeCollection" type="text" name="edgeCollection" placeholder="Edge Collection" maxlength="75" class="input-xlarge" value="Connections">
<div class="control-group">
<label for="edgeCollection" class="control-label">Edge Collection</label>
<div class="controls">
<input id="edgeCollection" type="text" name="edgeCollection" placeholder="Edge Collection" maxlength="75" class="input-xlarge" value="Connections">
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary" id="createViewer" >Start</button>
<div class="accordion" id="advancedGraphOptions">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#advancedGraphOptions" href="#advancedOptions">
Advanced
</a>
</div>
<div id="advancedOptions" class="accordion-body collapse out">
<div class="accordion-inner">
<div class="control-group">
<label for="undirected" class="control-label">Undirected Graph</label>
<div class="controls">
<input id="undirected" type="checkbox" name="undirected" class="input-xlarge">
</div>
</div>
<div class="control-group">
<label for="nodeLabel" class="control-label">Node Label</label>
<div class="controls">
<input id="nodeLabel" type="text" name="nodeLabel" placeholder="Node Label" maxlength="75" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</form>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary" id="createViewer" >Start</button>
</div>
</div>
</fieldset>
</form>
</div>

View File

@ -29,7 +29,16 @@ var documentsView = Backbone.View.extend({
"click #documents_next" : "nextDocuments",
"click #confirmDeleteBtn" : "confirmDelete",
"keyup .modal-body" : "listenKey",
"click .key" : "nop"
"click .key" : "nop",
"keyup" : "returnPressedHandler"
},
returnPressedHandler: function(event) {
if (event.keyCode === 13) {
if (!!$("#confirmDeleteBtn").attr("disabled") === false) {
this.confirmDelete();
}
}
},
nop: function(event) {
@ -128,11 +137,12 @@ var documentsView = Backbone.View.extend({
var thiselement = a.currentTarget.parentElement;
this.idelement = $(thiselement).prev().prev();
this.alreadyClicked = true;
$("#confirmDeleteBtn").attr("disabled", false);
$('#docDeleteModal').modal('show');
},
confirmDelete: function () {
$("#confirmDeleteBtn").attr("disabled", true);
this.reallyDelete();
},
reallyDelete: function () {
@ -152,7 +162,7 @@ var documentsView = Backbone.View.extend({
deleted = true;
}
else if (result === false) {
arangoHelper.arangoError('Document error');
arangoHelper.arangoError('Could not delete document');
}
}
else if (this.type === 'edge') {

View File

@ -14,20 +14,35 @@ window.graphView = Backbone.View.extend({
createViewer: function() {
var ecol,
ncol,
aaconfig;
ncol,
aaconfig,
undirected,
label,
config;
ecol = $("#edgeCollection").val();
ncol = $("#nodeCollection").val();
undirected = !!$("#undirected").attr("checked");
label = $("#nodeLabel").val();
ecol = $("#edgeCollection")[0].value;
ncol = $("#nodeCollection")[0].value;
aaconfig = {
type: "arango",
nodeCollection: ncol,
edgeCollection: ecol
edgeCollection: ecol,
undirected: undirected
};
if (label !== undefined && label !== "") {
config = {
nodeShaper: {
label: label
}
}
}
$("#creationDialog").remove();
ui = new GraphViewerUI(document.getElementById("content"), aaconfig, 940, 680);
$("#background").remove();
ui = new GraphViewerUI(document.getElementById("content"), aaconfig, 940, 680, config);
},

View File

@ -48,6 +48,7 @@ JAVASCRIPT_JSLINT = \
`find @srcdir@/js/common/modules/org -name "*.js"` \
`find @srcdir@/js/client/modules -name "*.js"` \
`find @srcdir@/js/server/modules -name "*.js"` \
`find @srcdir@/html/admin/js/models -name "*.js"` \
\
@srcdir@/js/client/client.js \
@srcdir@/js/server/server.js \

View File

@ -241,7 +241,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -235,7 +235,7 @@ function post_api_collection (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -668,7 +668,7 @@ function put_api_collection_load (req, res, collection) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -720,7 +720,7 @@ function put_api_collection_unload (req, res, collection) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -750,7 +750,7 @@ function put_api_collection_truncate (req, res, collection) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -812,7 +812,7 @@ function put_api_collection_properties (req, res, collection) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -870,7 +870,7 @@ function put_api_collection_rename (req, res, collection) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
@ -979,7 +979,7 @@ function delete_api_collection (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
}
@ -1012,7 +1012,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -137,7 +137,7 @@ var QUERY = internal.AQL_QUERY;
///
/// Executes a query and extract the result in a single go:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCreateCursorForLimitReturnSingle}
/// @EXAMPLE_ARANGOSH_RUN{RestCursorCreateCursorForLimitReturnSingle}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -157,7 +157,7 @@ var QUERY = internal.AQL_QUERY;
///
/// Executes a query and extract part of the result:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCreateCursorForLimitReturn}
/// @EXAMPLE_ARANGOSH_RUN{RestCursorCreateCursorForLimitReturn}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn);
@ -182,7 +182,7 @@ var QUERY = internal.AQL_QUERY;
///
/// Missing body:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCreateCursorMissingBody}
/// @EXAMPLE_ARANGOSH_RUN{RestCursorCreateCursorMissingBody}
/// var url = "/_api/cursor";
///
/// var response = logCurlRequest('POST', url, '');
@ -194,7 +194,7 @@ var QUERY = internal.AQL_QUERY;
///
/// Unknown collection:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCreateCursorUnknownCollection}
/// @EXAMPLE_ARANGOSH_RUN{RestCursorCreateCursorUnknownCollection}
/// var url = "/_api/cursor";
/// var body = '{ "query" : "FOR u IN unknowncoll LIMIT 2 RETURN u", "count" : true, "batchSize" : 2 }';
///
@ -235,7 +235,7 @@ function POST_api_cursor(req, res) {
// error occurred
if (cursor instanceof Error) {
actions.resultException(req, res, cursor);
actions.resultException(req, res, cursor, undefined, false);
return;
}
@ -285,11 +285,27 @@ function POST_api_cursor(req, res) {
///
/// Missing identifier
///
/// @verbinclude api-cursor-missing-cursor-identifier
/// @EXAMPLE_ARANGOSH_RUN{RestCursorMissingCursorIdentifier}
/// var url = "/_api/cursor";
///
/// var response = logCurlRequest('PUT', url, '');
///
/// assert(response.code === 400);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Unknown identifier
///
/// @verbinclude api-cursor-invalid-cursor-identifier
/// @EXAMPLE_ARANGOSH_RUN{RestCursorInvalidCursorIdentifier}
/// var url = "/_api/cursor/123123";
///
/// var response = logCurlRequest('PUT', url, '');
///
/// assert(response.code === 400);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
////////////////////////////////////////////////////////////////////////////////
function PUT_api_cursor (req, res) {
@ -404,7 +420,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -131,7 +131,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -137,7 +137,7 @@ function POST_api_explain (req, res) {
var result = EXPLAIN(json.query, json.bindVars);
if (result instanceof Error) {
actions.resultException(req, res, result);
actions.resultException(req, res, result, undefined, false);
return;
}
@ -169,7 +169,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -1770,7 +1770,7 @@ function post_graph_vertex_edges (req, res, g) {
// error occurred
if (cursor instanceof Error) {
actions.resultException(req, res, cursor);
actions.resultException(req, res, cursor, undefined, false);
return;
}
@ -2039,7 +2039,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -890,7 +890,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -126,7 +126,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -115,7 +115,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -193,7 +193,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -312,7 +312,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -430,7 +430,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -522,7 +522,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -611,7 +611,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -688,7 +688,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -734,7 +734,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -828,7 +828,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -904,7 +904,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -990,7 +990,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -1083,7 +1083,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -141,7 +141,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -335,7 +335,7 @@ actions.defineHttp({
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{AdminStatistics1}
/// @EXAMPLE_ARANGOSH_RUN{RestAdminStatistics1}
/// var url = "/_admin/statistics";
/// var response = logCurlRequest('GET', url);
///
@ -362,7 +362,7 @@ actions.defineHttp({
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -402,7 +402,7 @@ actions.defineHttp({
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{AdminStatisticsDescription1}
/// @EXAMPLE_ARANGOSH_RUN{RestAdminStatisticsDescription1}
/// var url = "/_admin/statistics-description";
/// var response = logCurlRequest('GET', url);
///
@ -611,7 +611,7 @@ actions.defineHttp({
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -456,7 +456,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -341,7 +341,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});
@ -428,7 +428,7 @@ actions.defineHttp({
}
}
catch (err) {
actions.resultException(req, res, err);
actions.resultException(req, res, err, undefined, false);
}
}
});

View File

@ -1198,7 +1198,7 @@ function resultError (req, res, httpReturnCode, errorNum, errorMessage, headers,
res.body = JSON.stringify(result);
if (headers !== undefined) {
if (headers !== undefined && headers !== null) {
res.headers = headers;
}
}
@ -1806,36 +1806,42 @@ function indexNotFound (req, res, collection, index, headers) {
////////////////////////////////////////////////////////////////////////////////
/// @brief generates an error for an exception
///
/// @FUN{actions.resultException(@FA{req}, @FA{res}, @FA{err}, @FA{headers})}
/// @FUN{actions.resultException(@FA{req}, @FA{res}, @FA{err}, @FA{headers}, @FA{verbose})}
///
/// The function generates an error response.
/// The function generates an error response. If @FA{verbose} is set to
/// @LIT{true} or not specified (the default), then the error stack trace will
/// be included in the error message if available.
////////////////////////////////////////////////////////////////////////////////
function resultException (req, res, err, headers) {
function resultException (req, res, err, headers, verbose) {
'use strict';
var code;
var msg;
var num;
if (verbose || verbose === undefined) {
msg = String(err.stack || err);
}
else {
msg = String(err);
}
if (err instanceof internal.ArangoError) {
num = err.errorNum;
msg = err.errorMessage;
code = exports.HTTP_BAD;
if (num === 0) {
num = arangodb.ERROR_INTERNAL;
}
if (msg === "") {
msg = String(err.stack || err);
if (err.errorMessage !== "" && ! verbose) {
msg = err.errorMessage;
}
else {
msg += ": " + String(err.stack || err);
}
switch (num) {
case arangodb.ERROR_INTERNAL:
case arangodb.ERROR_OUT_OF_MEMORY:
code = exports.HTTP_SERVER_ERROR;
break;
@ -1844,23 +1850,17 @@ function resultException (req, res, err, headers) {
code = exports.HTTP_CONFLICT;
break;
}
resultError(req, res, code, num, msg, headers);
}
else if (err instanceof TypeError) {
num = arangodb.ERROR_TYPE_ERROR;
code = exports.HTTP_BAD;
msg = String(err.stack || err);
resultError(req, res, code, num, msg, headers);
}
else {
resultError(req, res,
exports.HTTP_SERVER_ERROR, arangodb.ERROR_HTTP_SERVER_ERROR,
String(err.stack || err),
headers);
num = arangodb.ERROR_HTTP_SERVER_ERROR;
code = exports.HTTP_SERVER_ERROR;
}
resultError(req, res, code, num, msg, headers);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -761,6 +761,11 @@ exports.developmentRoutes = function () {
var prefix = doc.collectionPrefix;
var app = module.createApp(appId);
if (app === null) {
throw new Error("cannot find application '" + appId + "'");
}
var r = routingAalApp(app, mount, prefix);
routes.push(r);

View File

@ -343,6 +343,63 @@ function ahuacatlQueryVariablesTestSuite () {
var actual = getQueryResults(query);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief collect and return (should omit any temporary variables)
////////////////////////////////////////////////////////////////////////////////
testTemporaryVariables1 : function () {
var data = [
{ name: "baz" },
{ name: "bar" }
];
var expected = [
{ "criteria" : "bar", "g" : [ { "y" : { "test" : "test", "name" : "bar" } } ] },
{ "criteria" : "baz", "g" : [ { "y" : { "test" : "test", "name" : "baz" } } ] }
];
var query = "FOR y IN (FOR x IN " + JSON.stringify(data) + " LET object = (FOR a IN [ '1', '2' ] RETURN a) RETURN { test: \"test\", name: x.name }) COLLECT criteria = y.name INTO g LIMIT 10 RETURN { criteria: criteria, g: g }";
var actual = getQueryResults("LET result = (" + query + ") LIMIT 10 RETURN result");
assertEqual([ expected ], actual);
actual = getQueryResults(query);
assertEqual(expected, actual);
// omit creating sub-objects
query = "FOR y IN (FOR x IN " + JSON.stringify(data) + " RETURN { test: \"test\", name: x.name }) COLLECT criteria = y.name INTO g LIMIT 10 RETURN { criteria: criteria, g: g }";
actual = getQueryResults("LET result = (" + query + ") LIMIT 10 RETURN result");
assertEqual([ expected ], actual);
actual = getQueryResults(query);
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief collect and return (should omit any temporary variables)
////////////////////////////////////////////////////////////////////////////////
testTemporaryVariables2 : function () {
var data = [
{ name: "baz", _id: "id1" },
{ name: "bar", _id: "id2" },
{ name: "foo", _id: "id3" }
];
var expected = [
{ "criteria" : "yid3", "g" : [ { "y" : { "x" : { "name" : "foo", "_id" : "id3" } } } ] },
{ "criteria" : "yid2", "g" : [ { "y" : { "x" : { "name" : "bar", "_id" : "id2" } } } ] },
{ "criteria" : "yid1", "g" : [ { "y" : { "x" : { "name" : "baz", "_id" : "id1" } } } ] }
];
var query = "FOR y IN (FOR x IN " + JSON.stringify(data) + " RETURN { x: x }) COLLECT criteria = CONCAT(\"y\", y.x._id) INTO g SORT MAX(g[*].y.x._id) DESC LIMIT 10 RETURN { criteria: criteria, g: g }";
var actual = getQueryResults("LET result = (" + query + ") LIMIT 10 RETURN result");
assertEqual([ expected ], actual);
actual = getQueryResults(query);
assertEqual(expected, actual);
}
};

View File

@ -24,7 +24,13 @@
#ifdef _Z_OF
#undef OF
#define OF _Z_OF
#else
#ifndef OF
#define _Z_OF(args) args
#define OF _Z_OF
#endif
#endif
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))