cody
Version:
471 lines (375 loc) • 15 kB
JavaScript
//
// Johan Coppieters - mar 2013 - cody
//
//
console.log("loading " + module.id);
var mysql = require("mysql2");
var fs = require("fs");
var cody = require('../index.js');
function TreeController(context) {
console.log("TreeController.constructor -> page(" + context.page.itemId + ") = " + context.page.title + ", request = " + context.request);
// init inherited controller
cody.Controller.call(this, context);
context.shownode = this.getRoot();
}
TreeController.prototype = Object.create( cody.Controller.prototype );
module.exports = TreeController;
TreeController.prototype.getFilePath = function() {
return this.context.dynamic + this.getFolder();
};
// Next 4 should be overridden
TreeController.prototype.getRoot = function() {
throw new Error("TreeController.getRoot should be overridden - return an id");
};
TreeController.prototype.getType = function(theNode) {
throw new Error("TreeController.getType should be overridden - return a string (image, folder, ...) to be used by the Atom tree to display the nodes");
};
TreeController.prototype.getObject = function(id) {
throw new Error("TreeController.getObject should be overridden - return an Atom with the specified id");
};
TreeController.prototype.getFolder = function() {
throw new Error("TreeController.getFolder should be overridden - return a string / subpath in which the documents can be found");
};
/* required protocol for nodes:
Node.prototype.getAllowedDomains = function() { return ""; }
Node.prototype.hasChildren = function() { return false; }
Node.prototype.isActive = function() { return true; }
Node.prototype.isVisible = function() { return true; }
Node.prototype.getChildren = function() { return []; }
Node.prototype.getSortOrder = function() {}
Node.prototype.setSortOrder = function(nr) {}
Node.prototype.setName = function(name) {}
Node.prototype.getName = function() {}
Node.prototype.getId = function() {}
Node.prototype.scrapeFrom = function(controller) {}
Node.prototype.doUpdate = function(controller, finish) {}
Node.prototype.doDelete = function(controller, finish) {}
*/
TreeController.toId = function(theNode) {
if ((typeof theNode === "undefined") || (theNode === "")) {
return 0;
} else if (theNode.indexOf("id_") === 0) {
return parseInt(theNode.substring(3), 10);
} else {
return parseInt(theNode, 10);
}
};
TreeController.prototype.doRequest = function( finish ) {
var self = this;
if (self.isRequest("insert")) {
// a new node was inserted in the tree
self.addObject( self.getParam("name"),
self.getParam("refnode"),
self.getParam("type"),
self.getParam("kind"), finish );
} else if (self.isRequest("move")) {
// a node was being moved around in the tree
this.moveObject( self.getParam("node"),
self.getParam("refnode"),
self.getParam("type"), finish);
} else if (self.isRequest("rename")) {
// a node has been renamed in the tree
this.renameObject( self.getParam("name"),
self.getParam("node"), finish);
} else if (self.isRequest("realdelete")) {
// request to really delete a node from the tree
this.realDeleteObject( self.getParam("node"), finish);
} else if (self.isRequest("delete")) {
// request to mark a node as "deleted" / "inactive" in the tree
this.deleteObject( self.getParam("node"), finish);
} else if (self.isRequest("select")) {
// generate a input/type=select
this.gen( this.getList() );
finish("");
} else if (self.isRequest("menu")) {
// generate a ul/li tree for menus
this.gen( this.getMenu(), { "Content-Type": "application/html" } );
finish("");
} else if (self.isRequest("getnode")) {
// get all info and data on this node
this.fetchNode( self.getParam("node"), function() {
finish( self.context.fn.replace(".ejs", "-ajax.ejs") );
});
} else if (self.isRequest("save")) {
// save all info on this node (done by a submit, so we need to redraw the screen, too bad)
this.saveInfo( self.getParam("node"), finish );
} else {
// no specific request, just draw the tree...
finish();
}
};
//display the complete tree to be used in a array with id / filename.
TreeController.prototype.getArray = function( theRoot ) {
var self = this;
var imagePath = self.getFilePath();
var aRoot = self.getObject((typeof theRoot === "undefined") ? this.getRoot() : theRoot);
function dashes(cnt) {
var s = "";
for (var i=0; i<cnt; i++) { s += "-"; }
return s;
}
function renderArray( theNode, level ) {
var aTree = "";
var aList = theNode.getChildren();
for (var x in aList) {
var p = aList[x];
if (p.isVisible()) {
if (aTree.length > 0) { aTree += ", "; }
aTree += "[\"" + dashes(level) + " " + p.getName() + "\",\"" + imagePath + "/" + p.getFileName() + "\"]";
var rest = renderArray(p, level+1);
if (rest.length > 0) { aTree += "," + rest; }
}
}
return aTree;
}
return "[" + renderArray( aRoot, 0 ) + "]";
};
//display the complete tree to be used in a select/menu.
TreeController.prototype.getMenu = function( theRoot ) {
var self = this;
var aRoot = (typeof theRoot === "object") ? theRoot : self.getObject((typeof theRoot === "undefined") ? self.getRoot() : theRoot);
function renderTree( theNode ) {
var aTree = "";
var aList = theNode.getChildren();
for (var x in aList) {
var p = aList[x];
if (p.isVisible()) {
aTree += "<li id=\"" + p.id + "\" rel=\"" + p.getFileName() + "\" title=\"" + p.name +"." + p.extention + "\"><a href=\"#\">" + p.getName() + "</a>" + renderTree(p) + "</li>";
}
}
return (aTree.length === 0) ? "" : "<ul>" + aTree + "</ul>";
}
return renderTree( aRoot );
};
//display the complete tree to be used in a select/menu.
TreeController.prototype.getList = function( theRoot ) {
var self = this;
var aRoot = (typeof theRoot === "object") ? theRoot : self.getObject((typeof theRoot === "undefined") ? self.getRoot() : theRoot);
function renderTree( theNode ) {
var aTree = "";
var aList = theNode.getChildren();
for (var x in aList) {
var p = aList[x];
if (p.isVisible()) {
aTree += "<li id=\"" + p.getId() + "\" rel=\"" + p.getFileName() + "\">" +
p.getName() + renderTree(p) + "</li>";
}
}
return (aTree.length === 0) ? "" : "<ul>" + aTree + "</ul>";
}
return renderTree( aRoot );
};
// The complete tree for the admin part of the essen
TreeController.prototype.getTree = function( theRoot ) {
var self = this;
var aRoot = (typeof theRoot === "number") ? self.app.getAtom(theRoot) :
(typeof theRoot === "object") ? theRoot :
self.getObject((typeof theRoot === "undefined") ? self.getRoot() : theRoot);
function renderTree( theNode, open, descend ) {
var aTree = "";
if (typeof theNode != "undefined") {
var aList = theNode.getChildren();
for (var x in aList) { var p = aList[x];
var name = (p.isActive()) ? p.getName() : "("+p.getName()+")";
var classes = (open ? "open " : "") +
(p.isVisible() ? "" : "invisible ") +
(p.isActive() ? "" : "deleted");
aTree += "<li id=\"id_" + p.getId() + "\" class=\"" + classes + "\"" +
" rel=\""+ self.getType(p) + "\"" +
"><a href=\"#\">" + name + "</a>";
if (descend > 0) {
aTree += renderTree(p, false, descend-1);
}
aTree += "</li>";
}
}
if (aTree.length === 0) {
return "";
} else {
return "<ul>" + aTree + "</ul>";
}
}
return renderTree( aRoot, false, 99 );
};
TreeController.prototype.saveInfo = function( nodeId, finish ) {
var self = this;
console.log("FormController.saveInfo: node = " + nodeId );
var anObject = this.getObject(TreeController.toId(nodeId));
if (typeof anObject !== "undefined") {
self.context.shownode = anObject.parentId;
anObject.scrapeFrom(this);
var F = self.context.req.files;
if ((typeof F !== "undefined") && (typeof F.fileToUpload !== "undefined")) {
F = F.fileToUpload;
if (F.size !== 0) {
// find the name of the file
var dot = F.name.lastIndexOf(".");
anObject.setExtention(F.name.substring(dot+1));
var oldNote = anObject.getNote() || "";
if (oldNote === "") { anObject.setNote(F.name.substring(0, dot)); }
var newPath = anObject.getPathName(self);
// move the tmp file to our own datastore
console.log("TreeController.saveInfo: moving file from " + F.path + " to " + newPath);
fs.rename(F.path, newPath, function(err) {
if (err) {
console.log(err);
this.feedBack(false, "unable to rename uploaded file to " + newPath);
} else {
anObject.doUpdate(self, finish);
}
});
} else {
// just delete the tmp file if it's empty
fs.unlink(F.path, function() {
anObject.doUpdate(self, finish);
});
}
} else {
console.log("TreeController.saveInfo: no file attached.");
anObject.doUpdate(self, finish);
}
} else {
this.feedBack(false, "failed to save the data");
finish();
}
};
TreeController.prototype.addObject = function( title, refNode, type, kind, finish ) {
var self = this;
console.log("Received TreeController - addObject, refnode = " + refNode + ", title = " + title + ", type = " + type + ", kind = " + kind);
var refNodeId = TreeController.toId(refNode);
var orderNr, aParent;
var ext = (kind === "folder") ? "xxx" : (kind === "form") ? "" : "---";
// fetch the parent and sortorder
if (type === "inside") {
orderNr = 5;
aParent = self.app.getAtom(refNodeId);
} else {
// after -> is always at the end -> we never get this !! (worked with previous version of jsTree)
var refItem = self.app.getAtom(refNodeId);
orderNr = refItem.sortorder + 10;
aParent = refItem.parent;
}
var basis = cody.Atom.addDefaults({name: title, sortorder: orderNr, extention: ext}, aParent);
var anAtom = new cody.Atom(basis);
anAtom.pickParent(self.app.atoms);
// console.log(anAtom);
anAtom.doUpdate(self, function() {
self.app.addAtom(anAtom);
finish( { status: "OK", node: "id_" + anAtom.id } );
});
};
TreeController.prototype.moveObject = function( nodeId, refNode, type, finish ) {
var self = this;
// type = "before" / "after" or "last" / "inside"
console.log("Received TreeController - moveObject, refnode = " + refNode +
", node = " + nodeId + ", type = " + type);
var orderNr;
var aParent;
// fetch the parent and insertion point
if ((type === "inside") || (type === "last")) {
aParent = self.app.getAtom(cody.TreeController.toId(refNode));
orderNr = 9999;
} else {
var refItem = self.app.getAtom(cody.TreeController.toId(refNode));
aParent = self.app.getAtom(refItem.parentId);
orderNr = refItem.sortorder + ((type === "before") ? -5 : +5);
}
// fetch the node to be moved
var anItem = self.app.getAtom(cody.TreeController.toId(nodeId));
var curParent = self.app.getAtom(anItem.parentId);
// position in the tree
anItem.parentId = aParent.id;
//console.log("TreeController.MovePage: old order = " + anItem.sortorder + " (of " + anItem.id + "), new order = " + orderNr + ", in parent = " + anItem.parentId);
anItem.sortorder = orderNr;
try {
self.respace(aParent, function whenDone() {
finish( { status: "OK" } );
});
} catch (e) {
console.log("TreeController.MoveItem: Failed to update the Item object.");
console.log(e);
finish( { status: "NOK", error: e.toString() } );
}
};
TreeController.prototype.renameObject = function( title, nodeId, finish ) {
var self = this;
console.log("Received TreeController - rename, node = " + nodeId + ", title = " + title);
var anObject = this.getObject(TreeController.toId(nodeId));
if (typeof anObject !== "undefined") {
try {
anObject.setName(title);
anObject.doUpdate(self, function() {
self.context.shownode = anObject.id;
finish( { status: "OK" } );
});
} catch (e) {
console.log("TreeController.RenameObject: Failed to update the object - " + e);
finish( { status: "NOK", error: e.toString() } );
}
} else {
finish( { status: "NOK"} );
}
};
TreeController.prototype.deleteObject = function( nodeId, finish ) {
var self = this;
var anObject = self.getObject(TreeController.toId(nodeId));
if (self.app.hasAtomChildren(anObject)) {
finish({ status: "NOE", error: "not empty"});
} else {
self.context.shownode = anObject.parentId;
anObject.doDelete(self, function(err) {
if (err) {
finish({status: "NOK", error: err.toString()});
} else {
finish({status: "OK"});
}
});
}
};
TreeController.prototype.realDeleteObject = function( nodeId, finish ) {
var self = this;
this.deleteObject( nodeId, function(msg) {
if (msg.status === "NOE") {
self.feedBack(false, "There are still elements below this item");
finish();
} else if (msg.status === "NOK") {
self.feedBack(false, "Error deleting this item: " + msg.error);
finish();
} else {
self.feedBack(true, "Item successfully deleted");
finish();
}
});
};
TreeController.prototype.makeSelect = function( type ) {
};
TreeController.prototype.fetchNode = function( nodeId, finish ) {
console.log("TreeController.FetchNode: nodeId = " + nodeId);
this.context.atom = this.getObject(TreeController.toId(nodeId));
if (! this.context.atom) {
this.gen("NOK,Could not find the requested atom with id = " + nodeId, { "Content-Type": "application/html" });
} else {
finish();
}
};
TreeController.prototype.respace = function( parent, finish ) {
var self = this;
var aList = parent.getChildren();
var nr = 0;
cody.Application.each(aList, function respaceOnePage(done) {
var aChild = this;
nr += 10;
//console.log("TreeController.Respace: checking '" + aChild.name + "' now = " + aChild.sortorder + " to " + nr);
if (aChild.getSortOrder() !== nr) {
aChild.setSortOrder(nr);
aChild.doUpdate(self, function() {
done();
});
} else {
done();
}
}, function whenDone(err) {
if (err) { console.log("TreeController - respace: error = " + err); }
if (typeof finish === "function") { finish(); }
});
};