blob: 77b3dfd87cebbb3e0ce970e1227dcb97176e180f [file] [log] [blame]
/*
Copyright (c) 2006-2007, The Xooki project
http://xooki.sourceforge.net/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Some code is largely inspired by code found in the dojo toolkit,
see http://dojotoolkit.org/ for more information.
*/
// this file is included only in edit mode
xooki.url.include("tiddly/util.js");
if (typeof xooki.io == "undefined") {
xooki.io = {};
}
xooki.io.removeFile = function (filePath) {
var r = null;
if((r == null) || (r == false))
r = xooki.io.mozillaRemoveFile(filePath);
if((r == null) || (r == false))
r = xooki.io.ieRemoveFile(filePath);
return(r);
}
xooki.io.mozillaRemoveFile = function(filePath) {
if(window.Components)
try
{
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);
if (!file.exists())
return null;
file.remove(false);
return(true);
}
catch(e)
{
return(false);
}
return(null);
}
xooki.io.ieRemoveFile = function(filePath) {
try
{
var fso = new ActiveXObject("Scripting.FileSystemObject");
}
catch(e)
{
//alert("Exception while attempting to save\n\n" + e.toString());
return(null);
}
fso.DeleteFile(filePath, false);
return(true);
}
// fix EOL characters in text to use native characters
xooki.io.fixEOL = function(text) {
var nativeEOL = navigator.platform.indexOf('Win') != -1 ? '\r\n' : '\n';
return text.replace(/\r?\n/g, nativeEOL);
}
if (typeof xooki.string == "undefined") {
xooki.string = {};
}
xooki.string.escapeString = function(str) {
// borrowed from dojo
//summary:
// Adds escape sequences for non-visual characters, double quote and backslash
// and surrounds with double quotes to form a valid string literal.
return ('"' + str.replace(/(["\\])/g, '\\$1') + '"'
).replace(/[\f]/g, "\\f"
).replace(/[\b]/g, "\\b"
).replace(/[\n]/g, "\\n"
).replace(/[\t]/g, "\\t"
).replace(/[\r]/g, "\\r"); // string
};
if (typeof xooki.json == "undefined") {
xooki.json = {};
}
xooki.json.serialize = function (o, indent) {
// borrowed and adapted from dojo
// summary:
// Create a JSON serialization of the object.
// return:
// a String representing the serialized version of the passed object
if (!indent) {
indent = "";
}
var objtype = typeof(o);
if(objtype == "undefined"){
return "undefined";
}else if((objtype == "number")||(objtype == "boolean")){
return o + "";
}else if(o === null){
return "null";
}
if (objtype == "string") { return xooki.string.escapeString(o); }
if(objtype == "function"){
// do not encode functions
return null;
}
// recurse
var me = arguments.callee;
// short-circuit for objects that support "json" serialization
// if they return "self" then just pass-through...
var newObj;
// array
if(objtype != "function" && typeof(o.length) == "number"){
var res = [];
for(var i = 0; i < o.length; i++){
var val = me(o[i], indent+" ");
if(typeof(val) != "string"){
val = "undefined";
}
res.push(val);
}
return " [\n" + res.join(",\n") + "\n"+indent+"]\n";
}
// generic object code path
res = [];
for (var k in o){
if ("meta" == k) {
continue;
}
// let a chance to the object to define its transient keys, using a meta.isTransient function
if (typeof o.meta != 'undefined'
&& typeof o.meta.isTransient == 'function'
&& o.meta.isTransient(k)) {
continue;
}
var useKey;
if (typeof(k) == "number"){
useKey = '"' + k + '"';
}else if (typeof(k) == "string"){
useKey = xooki.string.escapeString(k);
}else{
// skip non-string or number keys
continue;
}
val = o[k];
// let a chance to the object to define its serialized value
if (typeof o.meta != 'undefined'
&& typeof o.meta.getSerializeValue == 'function') {
val = o.meta.getSerializeValue(o, k);
}
val = me(val, indent+" ");
if(typeof(val) != "string"){
// skip non-serializable values
continue;
}
res.push(indent+" "+useKey + ":" + val);
}
return indent+"{\n" + res.join(",\n") + indent+"}";
};
xooki.component.toolbar = function () {
return '<div style="position:absolute;top:2px;right:30px;" id="xooki-toolbar">'
+ '<a href="javascript:xooki.action.toggleEdit()"><img src="'+xooki.u('images/edit.gif')+'" title="toggle edit'+(xooki.c.browser.NS?' (CTRL+E)':'')+'"/></a>'
+ '<a href="javascript:xooki.action.saveChanges()"><img src="'+xooki.u('images/save.gif')+'" title="save'+(xooki.c.browser.NS?' (CTRL+S)':'')+'"/></a>'
+ '<a href="javascript:xooki.action.remove()"><img src="'+xooki.u('images/delete.gif')+'" title="remove"/></a>'
+ '<a href="javascript:xooki.action.createChild()"><img src="'+xooki.u('images/addchild.gif')+'" title="create child"/></a>'
+ '<a href="javascript:xooki.action.movePageUp()"><img src="'+xooki.u('images/up.gif')+'" title="move page up in TOC"/></a>'
+ '<a href="javascript:xooki.action.movePageDown()"><img src="'+xooki.u('images/down.gif')+'" title="move page down in TOC"/></a>'
+ (xooki.c.debug?'<a href="javascript:xooki.action.toggleDebug()"><img src="'+xooki.u('images/debug.gif')+'" title="toggle xooki debug mode"/></a>':'')
+ '</div>';
};
xooki.component.editZone = function () {
return '<div id="xooki-edit" style="display:none">'
+ '<table border="0"><tr><td valign="top">Title</td><td><input id="xooki-input-title" type="text" value="'+xooki.page.title+'"></input></td></tr>'
+ '<tr><td valign="top">Content</td><td><textarea rows="20" cols="80" id="xooki-source">'+xooki.input.source()+'</textarea></td></tr>'
+ '<tr><td colspan="2" align="right"><input type="button" value="Save" onclick="javascript:xooki.action.saveChanges()"/> <input type="button" value="Preview" onclick="javascript:xooki.action.previewChanges()"/> <input type="button" value="Discard" onclick="javascript:xooki.action.discardChanges()"/></td></tr></table></div>';
}
xooki.url.reload = function() {
window.location = window.location;
}
if (typeof xooki.action == "undefined") {
xooki.action = {};
}
xooki.action.quitEdit = function () {
xooki.input.applyChanges();
xooki.html.hide('xooki-edit');
xooki.html.show('xooki-content');
}
xooki.action.edit = function () {
xooki.html.hide('xooki-content');
xooki.html.show('xooki-edit');
}
xooki.action.toggleEdit = function () {
if (document.getElementById('xooki-edit').style.display == 'none') {
xooki.action.edit();
} else {
xooki.action.quitEdit();
}
}
xooki.action.remove = function () {
if (confirm(t("The current page will be removed from the table of content, and deleted on file system.\nNote that all children will be removed from the table of content too, but not from the file system!\nAre you sure you want to delete the current page?"))) {
// the page to which we'll be redirected...
var nextPage;
var index = xooki.page.meta.index;
var parent = xooki.page.meta.parent;
if (index > 0) {
// ... will be the previous sibling if there is one ...
nextPage = parent.children[index - 1];
} else if (parent.children.length > 1) {
// ... or the next sibling if there is one ...
nextPage = parent.children[index + 1];
} else if (parent != xooki.toc) {
// ... or the parent if the parent is not the toc root ...
nextPage = parent;
} else {
// ... otherwise it s a problem
xooki.error(t("Cannot delete the sole page!"));
return;
}
parent.children.splice(index, 1); // remove node from toc
xooki.toc.save();
xooki.io.removeFile(xooki.io.getLocalPath(window.location.toString()));
window.location = pu(nextPage.id);
}
}
xooki.action.discardChanges = function () {
xooki.url.reload();
}
xooki.action.previewChanges = function () {
xooki.action.quitEdit();
}
xooki.action.saveChanges = function () {
var originalPath = document.location.toString();
var localPath = xooki.io.getLocalPath(originalPath);
// Load the original file
var original = xooki.io.loadFile(localPath);
if(original == null) {
xooki.error(t("Impossible to load original file: ${0}", localPath));
return;
}
var startSaveArea = '<textarea id="xooki-source">';
var posOpeningArea = original.indexOf(startSaveArea);
var posClosingArea = original.indexOf('</textarea>');
xooki.page.title = document.getElementById('xooki-input-title').value;
xooki.toc.save();
var save;
try {
// Save new file
var revised = original.substr(0,posOpeningArea + startSaveArea.length) + "\n" +
xooki.input.source() +
original.substr(posClosingArea);
save = xooki.io.saveFile(localPath,xooki.io.fixEOL(revised));
} catch (e) {
xooki.error(e);
}
if(save) {
xooki.info(t("saved to ${0}",localPath));
// TODO: see if we are able to apply title change without reloading
setTimeout(function() {xooki.url.reload();}, 800);
} else
xooki.error(t("Impossible to save changes to ${0}", localPath));
}
xooki.action.movePageUp = function () {
xooki.action.movePage(-1);
}
xooki.action.movePageDown = function () {
xooki.action.movePage(1);
}
xooki.action.movePage = function (delta) {
var index = xooki.page.meta.index;
var parent = xooki.page.meta.parent;
// check if node can move
if (index + delta < 0) {
xooki.info(t("Can't move first page up"));
return;
}
if (index + delta >= parent.children.length) {
xooki.info(t("Can't move last page down"));
return;
}
// move node in toc
parent.children.splice(index, 1);
parent.children.splice(index+delta, 0, xooki.page);
xooki.toc.save();
xooki.url.reload();
}
xooki.action.createChild = function () {
titleToId = function (title) {
return title.replace(/\s+/g, '');
}
var title = prompt("Child page title?", "");
var id = prompt("Child page path?", titleToId(title));
xooki.action.createChildPage({"id": id, "title": title, "children": []});
}
xooki.action.createChildPage = function (child) {
if (typeof child.meta == 'undefined' || typeof child.meta.level == 'undefined') {
if (typeof child.meta == 'undefined') child.meta = {};
child.meta.level = child.id.split('/').length - 1;
}
var pagetpl = xooki.url.loadURL(cu("blankPageTpl"));
if (pagetpl != null) {
var childURL = pu(child.id);
var localPath = xooki.io.getLocalPath(childURL);
var original = xooki.io.loadFile(localPath);
if (original != null) {
if (!window.confirm(t("File for child page:\n${0}\nalready exists.\nAre you sure you want to continue and overwrite it?", localPath)))
return;
}
xooki.page.children.push(child);
xooki.toc.save();
// usually used by templates
if (typeof child.relroot == 'undefined') {
child.relroot = "";
for (var i=0; i < child.meta.level; i++) {
child.relroot += "../";
}
}
child.level = child.meta.level;
var revised = xooki.string.processTemplate(pagetpl, child);
var save;
try {
// Save new file
save = xooki.io.saveFile(localPath,xooki.io.fixEOL(revised));
} catch (e) {
xooki.error(e);
}
if(save) {
// go to child page
window.location = childURL;
} else
xooki.error(t("Impossible to save changes to ${0}", localPath));
}
}
xooki.toc.save = function (revised) {
if (!revised) {
revised = xooki.json.serialize({children: this.actualRoot.children});
}
var save;
var tocPath = xooki.io.getLocalPath(this.url);
try {
save = xooki.io.saveFile(tocPath, xooki.io.fixEOL(revised));
} catch (e) {
xooki.error(e);
}
if(!save)
xooki.error(t("Impossible to save changes to ${0}", tocPath));
}
if (typeof xooki.util == 'undefined') xooki.util = {}
xooki.util.copy = function(o) {
var copy = {};
for (var k in o) {
copy[k] = o[k];
}
return copy;
}