* Improved tag framework * Added support for image tags * Moved most code of StoryMgr.evalNewStory to Story.evalStory to decrease redundancy * Added compatibility module (including drafts for database conversions) * Moved code for topics to compatibility module * Removed obsolete code
508 lines
14 KiB
JavaScript
508 lines
14 KiB
JavaScript
//
|
|
// The Antville Project
|
|
// http://code.google.com/p/antville
|
|
//
|
|
// Copyright 2001-2007 by The Antville People
|
|
//
|
|
// 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.
|
|
//
|
|
// $Revision$
|
|
// $LastChangedBy$
|
|
// $LastChangedDate$
|
|
// $URL$
|
|
//
|
|
|
|
/**
|
|
* constructor function for image objects
|
|
*/
|
|
Image.prototype.constructor = function(creator) {
|
|
this.creator = creator;
|
|
this.createtime = new Date();
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* main action
|
|
*/
|
|
Image.prototype.main_action = function() {
|
|
res.debug(this._parent);
|
|
res.data.title = getMessage("Image.viewTitle", {imageAlias: this.alias});
|
|
res.data.body = this.renderSkinAsString("main");
|
|
res.handlers.context.renderSkin("page");
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* edit action
|
|
*/
|
|
Image.prototype.edit_action = function() {
|
|
if (req.data.cancel)
|
|
res.redirect(this.href());
|
|
else if (req.data.save) {
|
|
res.message = this.evalImg(req.data, session.user);
|
|
res.redirect(this.href());
|
|
}
|
|
|
|
res.data.action = this.href(req.action);
|
|
res.data.title = getMessage("Image.editTitle", {imageAlias: this.alias});
|
|
res.data.body = this.renderSkinAsString("edit");
|
|
res.handlers.context.renderSkin("page");
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* delete action
|
|
*/
|
|
Image.prototype.delete_action = function() {
|
|
if (req.data.cancel)
|
|
res.redirect(path.ImageMgr.href());
|
|
else if (req.data.remove) {
|
|
try {
|
|
var url = this._parent.href();
|
|
res.message = this._parent.deleteImage(this);
|
|
res.redirect(url);
|
|
} catch (err) {
|
|
res.message = err.toString();
|
|
}
|
|
}
|
|
|
|
res.data.action = this.href(req.action);
|
|
res.data.title = getMessage("Image.deleteTitle", {imageAlias: this.alias});
|
|
var skinParam = {
|
|
description: getMessage("Image.deleteDescription"),
|
|
detail: this.alias
|
|
};
|
|
res.data.body = this.renderSkinAsString("delete", skinParam);
|
|
res.handlers.context.renderSkin("page");
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro rendering alias of image
|
|
*/
|
|
Image.prototype.alias_macro = function(param) {
|
|
if (param.as == "editor")
|
|
Html.input(this.createInputParam("alias", param));
|
|
else
|
|
res.write(this.alias);
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro rendering alternate text of image
|
|
*/
|
|
Image.prototype.alttext_macro = function(param) {
|
|
if (param.as == "editor")
|
|
Html.textArea(this.createInputParam("alttext", param));
|
|
else
|
|
res.write(this.alttext);
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro renders the width of the image
|
|
*/
|
|
Image.prototype.width_macro = function(param) {
|
|
res.write(this.width);
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro renders the height of the image
|
|
*/
|
|
Image.prototype.height_macro = function(param) {
|
|
res.write(this.height);
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro rendering filesize
|
|
*/
|
|
Image.prototype.filesize_macro = function(param) {
|
|
res.write((this.filesize / 1024).format("###,###") + " KB");
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* macro renders the url to this image
|
|
*/
|
|
Image.prototype.url_macro = function(param) {
|
|
res.write(this.getUrl());
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* render a link to image-edit
|
|
*/
|
|
Image.prototype.editlink_macro = function(param) {
|
|
if (this.getContext() === "Layout" && path.layout !== this.parent) {
|
|
return;
|
|
}
|
|
if (session.user) {
|
|
try {
|
|
this.checkEdit(session.user, req.data.memberlevel);
|
|
} catch (deny) {
|
|
return;
|
|
}
|
|
Html.openLink({href: this.href("edit")});
|
|
if (param.image && this.parent.images.get(param.image))
|
|
renderImage(this.parent.images.get(param.image), param);
|
|
else
|
|
res.write(param.text ? param.text : getMessage("generic.edit"));
|
|
Html.closeLink();
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* render a link to delete action
|
|
*/
|
|
Image.prototype.deletelink_macro = function(param) {
|
|
if (this.getContext() === "Layout" && path.Layout !== this.parent) {
|
|
return;
|
|
}
|
|
if (session.user) {
|
|
try {
|
|
this.checkDelete(session.user, req.data.memberlevel);
|
|
} catch (deny) {
|
|
return;
|
|
}
|
|
Html.openLink({href: this.href("delete")});
|
|
if (param.image && this.site.images.get(param.image))
|
|
renderImage(this.site.images.get(param.image), param);
|
|
else
|
|
res.write(param.text ? param.text : getMessage("generic.delete"));
|
|
Html.closeLink();
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* render the image-tag (link to main action if image
|
|
* is a thumbnail)
|
|
*/
|
|
Image.prototype.show_macro = function(param) {
|
|
var img = this;
|
|
// if we have a thumbnail, display that
|
|
if (param.as == "thumbnail" && this.thumbnail) {
|
|
var url = this.href();
|
|
img = this.thumbnail;
|
|
} else
|
|
var url = img.getUrl();
|
|
delete param.what;
|
|
delete param.as;
|
|
param.src = img.getUrl();
|
|
Html.openLink({href: url});
|
|
renderImage(img, param);
|
|
Html.closeLink();
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* render the code for embedding this image
|
|
*/
|
|
Image.prototype.code_macro = function(param) {
|
|
res.write("<% ");
|
|
res.write(this.getContext() === "Layout" ? "layout.image" : "image");
|
|
res.write(" name=\"" + this.alias + "\" %>");
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* render a link to delete action
|
|
* calls image.deletelink_macro, but only
|
|
* if the layout in path is the one this image
|
|
* belongs to
|
|
*/
|
|
Image.prototype.replacelink_macro = function(param) {
|
|
if (this.layout && path.Layout != this.layout) {
|
|
if (session.user) {
|
|
try {
|
|
path.Layout.images.checkAdd(session.user, req.data.memberlevel);
|
|
} catch (deny) {
|
|
return;
|
|
}
|
|
Html.openLink({href: path.Layout.images.href("create") + "?alias=" + this.alias});
|
|
if (param.image && this.site.images.get(param.image))
|
|
renderImage(this.site.images.get(param.image), param);
|
|
else
|
|
res.write(param.text ? param.text : getMessage("generic.replace"));
|
|
Html.closeLink();
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* save image as file on local disk
|
|
* but before check if image should be resized
|
|
* @param Object uploaded image
|
|
* @param Object File-Object representing the destination directory
|
|
* @param Int maximum width
|
|
* @param Int maximum height
|
|
*/
|
|
Image.prototype.save = function(rawimage, dir, maxWidth, maxHeight) {
|
|
// determine filetype of image (one could do this also by checking the mimetype)
|
|
this.fileext = evalImgType(rawimage.contentType);
|
|
if (this.fileext == "ico") {
|
|
// the image is an .ico, so we directory write it to disk and return
|
|
rawimage.writeToFile(dir.getPath(), this.filename + "." + this.fileext);
|
|
return true;
|
|
}
|
|
var img = new Helma.Image(rawimage.getContent());
|
|
this.width = img.getWidth();
|
|
this.height = img.getHeight();
|
|
var resize = false;
|
|
var hfact = 1;
|
|
var vfact = 1;
|
|
if (maxWidth && this.width > maxWidth) {
|
|
hfact = maxWidth / this.width;
|
|
resize = true;
|
|
}
|
|
if (maxHeight && this.height > maxHeight) {
|
|
vfact = maxHeight / this.height;
|
|
resize = true;
|
|
}
|
|
|
|
if (resize) {
|
|
this.width = Math.ceil(this.width * (hfact < vfact ? hfact : vfact));
|
|
this.height = Math.ceil(this.height * (hfact < vfact ? hfact : vfact));
|
|
try {
|
|
img.resize(this.width, this.height);
|
|
if (rawimage.contentType == 'image/gif' || this.fileext == "gif")
|
|
img.reduceColors(256);
|
|
} catch (err) {
|
|
throw new Exception("imageResize");
|
|
}
|
|
}
|
|
// finally we try to save the resized image
|
|
try {
|
|
if (resize)
|
|
img.saveAs(dir.getPath() + "/" + this.filename + "." + this.fileext);
|
|
else
|
|
rawimage.writeToFile(dir.getPath(), this.filename + "." + this.fileext);
|
|
} catch (err) {
|
|
app.log("Error in image.save(): can't save image to "+dir);
|
|
throw new Exception("imageSave");
|
|
}
|
|
var f = new Helma.File(dir.getPath(), this.filename + "." + this.fileext);
|
|
this.filesize = f.getLength();
|
|
return;
|
|
};
|
|
|
|
|
|
/**
|
|
* function checks if new Image-parameters are correct ...
|
|
* @param Obj Object containing the form values
|
|
* @param Obj User-Object modifying this image
|
|
* @return Obj Object containing two properties:
|
|
* - error (boolean): true if error happened, false if everything went fine
|
|
* - message (String): containing a message to user
|
|
*/
|
|
Image.prototype.evalImg = function(param, modifier) {
|
|
this.alttext = param.alttext;
|
|
this.modifier = modifier;
|
|
this.modifytime = new Date();
|
|
|
|
param.tags = Story.prototype.setTopic.call(this,
|
|
param.topic || param.addToTopic);
|
|
Story.prototype.setTags.call(this, param.tags);
|
|
|
|
if (this.thumbnail) {
|
|
this.thumbnail.alttext = this.alttext;
|
|
this.thumbnail.modifytime = this.modifytime;
|
|
this.thumbnail.modifier = this.modifier;
|
|
}
|
|
return new Message("update");
|
|
};
|
|
|
|
|
|
/**
|
|
* function creates a thumbnail of this image
|
|
* does nothing if the image uploaded is smaller than 100x100px
|
|
* @param uploaded image
|
|
* @return Boolean true in any case ...
|
|
*/
|
|
|
|
Image.prototype.createThumbnail = function(rawimage, dir) {
|
|
var thumb = new Image(this.creator);
|
|
thumb.site = this.site;
|
|
thumb.layout = this.layout;
|
|
thumb.filename = this.filename + "_small";
|
|
thumb.save(rawimage, dir, THUMBNAILWIDTH);
|
|
thumb.alttext = this.alttext;
|
|
thumb.alias = this.alias;
|
|
thumb.parent = this;
|
|
this.thumbnail = thumb;
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* return the call to the client-side popup-script
|
|
* for image-object
|
|
* @return String call of popup-script
|
|
*/
|
|
Image.prototype.getPopupUrl = function() {
|
|
res.push();
|
|
res.write("javascript:openPopup('");
|
|
res.write(this.getUrl());
|
|
res.write("',");
|
|
res.write(this.width);
|
|
res.write(",");
|
|
res.write(this.height);
|
|
res.write(");return false;");
|
|
return res.pop();
|
|
};
|
|
|
|
|
|
/**
|
|
* return the url of the image
|
|
*/
|
|
Image.prototype.getUrl = function() {
|
|
res.push();
|
|
switch (this.getContext()) {
|
|
case "Site":
|
|
this.parent.staticUrl("images/");
|
|
break;
|
|
case "Layout":
|
|
this.parent.staticUrl();
|
|
break;
|
|
case "Image":
|
|
switch (this.parent.getContext()) {
|
|
case "Site":
|
|
this.parent.parent.staticUrl("images/");
|
|
break
|
|
case "Layout":
|
|
this.parent.parent.staticUrl();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
res.write(this.filename);
|
|
res.write(".");
|
|
res.write(this.fileext);
|
|
return res.pop();
|
|
|
|
// FIXME: testing free proxy for images
|
|
var result = "http://www.freeproxy.ca/index.php?url=" +
|
|
encodeURIComponent(res.pop().rot13()) + "&flags=11111";
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* return the image file on disk
|
|
* @return Object File object
|
|
*/
|
|
Image.prototype.getFile = function() {
|
|
var staticPath;
|
|
if (this.getContext() !== "Image") {
|
|
staticPath = this.parent.getStaticPath();
|
|
} else {
|
|
staticPath = this.parent.parent.getStaticPath();
|
|
}
|
|
return new Helma.File(staticPath, this.filename + "." + this.fileext);
|
|
};
|
|
|
|
Image.prototype.getContext = function() {
|
|
//res.debug("this.parentType + : " + this.parentType)
|
|
//res.debug("this.prototype + : " + this.prototype)
|
|
//res.debug("this.parent.parentType + : " + this.parent.parentType)
|
|
//res.debug("this.parent.prototype + : " + this.parent.prototype)
|
|
return this.parentType || this._prototype;
|
|
//return ImageMgr.prototype.getContext.call(this.parent);
|
|
};
|
|
|
|
/**
|
|
* dump an image to a zip file passed as argument
|
|
* @return Object HopObject containing the metadata of the image(s)
|
|
*/
|
|
Image.prototype.dumpToZip = function(z) {
|
|
var data = new HopObject();
|
|
if (this.thumbnail)
|
|
data.thumbnail = this.thumbnail.dumpToZip(z);
|
|
data.alias = this.alias;
|
|
data.filename = this.filename;
|
|
data.fileext = this.fileext;
|
|
data.width = this.width;
|
|
data.height = this.height;
|
|
data.alttext = this.alttext;
|
|
data.createtime = this.createtime;
|
|
data.modifytime = this.modifytime;
|
|
data.exporttime = new Date();
|
|
data.creator = this.creator ? this.creator.name : null;
|
|
data.modifier = this.modifier ? this.modifier.name : null;
|
|
var file = this.getFile();
|
|
if (file.exists()) {
|
|
// add the image file to the zip archive
|
|
z.add(file, "images");
|
|
}
|
|
return data;
|
|
};
|
|
/**
|
|
* permission check (called by hopobject.onRequest())
|
|
* @param String name of action
|
|
* @param Obj User object
|
|
* @param Int Membership level
|
|
* @return Obj Exception object or null
|
|
*/
|
|
Image.prototype.checkAccess = function(action, usr, level) {
|
|
try {
|
|
switch (action) {
|
|
case "edit" :
|
|
checkIfLoggedIn(this.href(req.action));
|
|
this.checkEdit(usr, level);
|
|
break;
|
|
case "delete" :
|
|
checkIfLoggedIn();
|
|
this.checkDelete(usr, level);
|
|
break;
|
|
}
|
|
} catch (deny) {
|
|
res.message = deny.toString();
|
|
res.redirect(this._parent.href());
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* check if user is allowed to edit an image
|
|
* @param Obj Userobject
|
|
* @param Int Permission-Level
|
|
* @return Obj Exception or null (if allowed)
|
|
*/
|
|
Image.prototype.checkEdit = function(usr, level) {
|
|
switch (this.getContext()) {
|
|
case "Site":
|
|
if (this.creator != usr && (level & MAY_EDIT_ANYIMAGE) == 0) {
|
|
throw new DenyException("imageEdit");
|
|
}
|
|
break;
|
|
case "Layout":
|
|
this.parent.images.checkAdd(usr, level);
|
|
break;
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* check if user is allowed to delete an image
|
|
* @param Obj Userobject
|
|
* @param Int Permission-Level
|
|
* @return Obj Exception or null (if allowed)
|
|
*/
|
|
Image.prototype.checkDelete = function(usr, level) {
|
|
if (this.creator != usr && (level & MAY_DELETE_ANYIMAGE) == 0)
|
|
throw new DenyException("imageDelete");
|
|
return;
|
|
};
|