antville/code/Image/Image.js

403 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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$
//
this.handleMetadata("contentLength");
this.handleMetadata("contentType");
this.handleMetadata("description");
this.handleMetadata("fileName");
this.handleMetadata("height");
this.handleMetadata("thumbnailHeight");
this.handleMetadata("thumbnailName");
this.handleMetadata("thumbnailWidth");
this.handleMetadata("origin");
this.handleMetadata("width");
Image.THUMBNAILWIDTH = 100;
Image.KEYS = ["name", "created", "modified", "origin", "description",
"contentType", "contentLength", "width", "height", "thumbnailName",
"thumbnailWidth", "thumbnailHeight", "fileName", "site"];
Image.remove = function() {
this.removeFiles();
this.setTags(null);
this.remove();
return;
}
Image.getFileExtension = function(type) {
switch (type) {
//case "image/x-icon":
//return ".ico";
case "image/gif":
return ".gif";
case "image/jpeg":
case "image/pjpeg":
return ".jpg";
case "image/png":
case "image/x-png":
return ".png";
}
return null;
}
Image.prototype.constructor = function(data) {
// Images.Default is using the constructor on code compilation
if (typeof session !== "undefined") {
this.creator = session.user;
this.touch();
}
if (data) {
for each (var key in Image.KEYS) {
this[key] = data[key];
}
}
this.created = new Date;
return this;
}
Image.prototype.getPermission = function(action) {
var defaultGrant = this._parent.getPermission("main");
switch (action) {
case ".":
case "main":
return true;
case "delete":
return defaultGrant && this.creator === session.user ||
Membership.require(Membership.MANAGER) ||
User.require(User.PRIVILEGED);
case "edit":
return defaultGrant && this.creator === session.user ||
Membership.require(Membership.MANAGER) ||
User.require(User.PRIVILEGED) &&
this.parent_type !== "Layout" ||
this.parent === path.layout;
case "replace":
return defaultGrant && (User.require(User.PRIVILEGED) ||
Membership.require(Membership.MANAGER)) &&
(this.parent_type === "Layout" &&
this.parent !== path.layout);
}
return false;
}
Image.prototype.href = function(action) {
if (action !== "replace") {
if (this.parent_type === "Layout" && this.parent !== path.layout) {
return this.getUrl();
}
} else {
return res.handlers.images.href("create") + "?name=" + this.name;
}
return HopObject.prototype.href.apply(this, arguments);
}
Image.prototype.main_action = function() {
res.data.title = gettext("Image {0}", this.name);
res.data.body = this.renderSkinAsString("Image#main");
res.handlers.site.renderSkin("Site#page");
return;
}
Image.prototype.edit_action = function() {
if (req.postParams.save) {
try {
this.update(req.postParams);
// FIXME: To be removed if work-around for Helma bug #607 passes
//this.setTags(req.postParams.tags || req.postParams.tag_array);
res.message = gettext("The changes were saved successfully.");
res.redirect(this.href());
} catch (ex) {
res.message = ex;
app.log(ex);
}
}
res.data.action = this.href(req.action);
res.data.title = gettext("Edit image {0}", this.name);
res.data.body = this.renderSkinAsString("$Image#edit");
res.handlers.site.renderSkin("Site#page");
return;
}
Image.prototype.getFormValue = function(name) {
var self = this;
var getOrigin = function(str) {
var origin = req.postParams.file_origin || self.origin;
if (origin && origin.contains("://")) {
return origin;
}
return null;
}
if (req.isPost()) {
if (name === "file") {
return getOrigin();
}
return req.postParams[name];
}
switch (name) {
case "file":
return getOrigin();
case "maxWidth":
case "maxHeight":
return this[name] || 400;
case "tags":
return this.getTags();
}
return this[name] || req.queryParams[name];
}
Image.prototype.update = function(data) {
if (data.uploadError) {
app.log(data.uploadError);
// Looks like the file uploaded has exceeded the upload limit ...
throw Error(gettext("File size is exceeding the upload limit."));
}
if (!data.file_origin) {
if (this.isTransient()) {
throw Error(gettext("There was nothing to upload. Please be sure to choose a file."));
}
} else if (data.file_origin !== this.origin) {
var mime = data.file;
if (mime.contentLength < 1) {
mime = getURL(data.file_origin);
if (!mime) {
throw Error(gettext("Could not fetch the image from the given URL."));
}
}
var extension = Image.getFileExtension(mime.contentType);
if (!extension) {
throw Error(gettext("This type of file cannot be uploaded as image."));
}
this.origin = data.file_origin;
var mimeName = mime.normalizeFilename(mime.name);
this.contentLength = mime.contentLength;
this.contentType = mime.contentType;
if (!this.name) {
var name = File.getName(data.name) || mimeName.split(".")[0];
this.name = this.site.images.getAccessName(name);
}
var image = this.getConstraint(mime, data.maxWidth, data.maxHeight);
this.height = image.height;
this.width = image.width;
var thumbnail;
if (image.width > Image.THUMBNAILWIDTH) {
thumbnail = this.getConstraint(mime, Image.THUMBNAILWIDTH);
this.thumbnailWidth = thumbnail.width;
this.thumbnailHeight = thumbnail.height;
} else if (this.isPersistent()) {
this.getThumbnailFile().remove();
// NOTE: delete won't work here due to getter/setter methods
this.metadata.remove("thumbnailName");
this.metadata.remove("thumbnailWidth");
this.metadata.remove("thumbnailHeight");
}
// Make the image persistent before proceeding with writing files and
// setting tags (also see Helma bug #607)
this.isTransient() && this.persist();
var fileName = this.name + extension;
if (fileName !== this.fileName) {
// Remove existing image files if the file name has changed
this.removeFiles();
}
this.fileName = fileName;
thumbnail && (this.thumbnailName = this.name + "_small" + extension);
this.writeFiles(image.resized || mime, thumbnail && thumbnail.resized);
}
if (this.parent_type !== "Layout") {
this.setTags(data.tags || data.tag_array);
}
this.description = data.description;
this.touch();
return;
}
Image.prototype.tags_macro = function() {
return res.write(this.getFormValue("tags"));
}
Image.prototype.contentLength_macro = function() {
res.write((this.contentLength / 1024).format("###,###") + " KB");
return;
}
Image.prototype.url_macro = function() {
return res.write(this.getUrl());
}
Image.prototype.macro_macro = function() {
return HopObject.prototype.macro_macro.call(this, null,
this.parent.constructor === Layout ? "layout.image" : "image");
}
Image.prototype.thumbnail_macro = function(param) {
if (!this.thumbnailName) {
return this.render_macro(param);
}
param.src = this.getUrl(this.getThumbnailFile().getName());
param.title || (param.title = encode(this.description));
param.alt = encode(param.alt || param.title);
param.width = this.thumbnailWidth || String.EMPTY;
param.height = this.thumbnailHeight || String.EMPTY;
param.border = (param.border = 0);
html.tag("img", param);
return;
}
Image.prototype.render_macro = function(param) {
param.src = this.getUrl();
param.title || (param.title = encode(this.description));
param.alt = encode(param.alt || param.title);
param.width || (param.width = this.width);
param.height || (param.height = this.height);
param.border || (param.border = 0);
html.tag("img", param);
return;
}
Image.prototype.getFile = function(name) {
name || (name = this.fileName);
if (this.parent_type === "Layout") {
var layout = this.parent || res.handlers.layout;
return layout.getFile(name);
}
var site = this.parent || res.handlers.site;
return site.getStaticFile("images/" + name);
}
Image.prototype.getUrl = function(name) {
name || (name = this.fileName);
//name = encodeURIComponent(name);
if (this.parent_type === "Layout") {
var layout = this.parent || res.handlers.layout;
res.push();
res.write("layout/");
res.write(name);
return layout.site.getStaticUrl(res.pop());
}
var site = this.parent || res.handlers.site;
return site.getStaticUrl("images/" + name);
// FIXME: testing free proxy for images
/* var result = "http://www.freeproxy.ca/index.php?url=" +
encodeURIComponent(res.pop().rot13()) + "&flags=11111";
return result; */
}
Image.prototype.getThumbnailFile = function() {
return this.getFile(this.thumbnailName);
// || this.fileName.replace(/(\.[^.]+)?$/, "_small$1"));
}
Image.prototype.getJSON = function() {
return {
name: this.name,
origin: this.origin,
description: this.description,
contentType: this.contentType,
contentLength: this.contentLength,
width: this.width,
height: this.height,
thumbnailName: this.thumbnailName,
thumbnailWidth: this.thumbnailWidth,
thumbnailHeight: this.thumbnailHeight,
created: this.created,
creator: this.creator ? this.creator.name : null,
modified: this.modified,
modifier: this.modifier ? this.modifier.name : null,
}.toSource();
}
Image.prototype.getConstraint = function(mime, maxWidth, maxHeight) {
try {
var image = new helma.Image(mime.inputStream);
var factorH = 1, factorV = 1;
if (maxWidth && image.width > maxWidth) {
factorH = maxWidth / image.width;
}
if (maxHeight && image.height > maxHeight) {
factorV = maxHeight / image.height;
}
if (factorH !== 1 || factorV !== 1) {
var width = Math.ceil(image.width *
(factorH < factorV ? factorH : factorV));
var height = Math.ceil(image.height *
(factorH < factorV ? factorH : factorV));
image.resize(width, height);
if (mime.contentType.endsWith("gif")) {
image.reduceColors(256);
}
return {resized: image, width: image.width, height: image.height};
}
return {width: image.width, height: image.height};
} catch (ex) {
app.log(ex);
throw Error(gettext("Could not resize the image."));
}
}
Image.prototype.writeFiles = function(data, thumbnail) {
if (data) {
try {
// If data is a MimeObject (ie. has the writeToFile method)
// the image was not resized and thus, we directly write it to disk
var file = this.getFile();
if (data.saveAs) {
data.saveAs(file);
} else if (data.writeToFile) {
data.writeToFile(file.getParent(), file.getName());
}
if (thumbnail) {
thumbnail.saveAs(this.getThumbnailFile());
}
} catch (ex) {
app.log(ex);
throw Error(gettext("Could not save the images files on disk."));
}
}
return;
}
Image.prototype.removeFiles = function() {
try {
this.getFile().remove();
var thumbnail = this.getThumbnailFile();
if (thumbnail) {
thumbnail.remove();
}
} catch (ex) {
app.log(ex);
throw Error(gettext("Could not remove the image's files from disk."));
}
return;
}