Proof of concept - Image upload
This commit is contained in:
parent
c59076a19a
commit
bf2ed5c339
9 changed files with 248 additions and 63 deletions
|
@ -36,6 +36,7 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.backend.FileStorageSetup;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.model.FileInfo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.model.ImageInfo;
|
||||||
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;
|
import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServletRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil;
|
import edu.cornell.mannlib.vitro.webapp.web.images.PlaceholderUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +49,9 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
private static final String ATTRIBUTE_REFERRING_PAGE = "ImageUploadController.referringPage";
|
private static final String ATTRIBUTE_REFERRING_PAGE = "ImageUploadController.referringPage";
|
||||||
|
|
||||||
|
private static final String ERROR_CODE_UNRECOGNIZED_URI = "imageUpload.errorUnrecognizedURI";
|
||||||
|
private static final String ERROR_CODE_NO_URI = "imageUpload.errorNoURI";
|
||||||
|
|
||||||
/** Limit file size to 6 megabytes. */
|
/** Limit file size to 6 megabytes. */
|
||||||
public static final int MAXIMUM_FILE_SIZE = 6 * 1024 * 1024;
|
public static final int MAXIMUM_FILE_SIZE = 6 * 1024 * 1024;
|
||||||
|
|
||||||
|
@ -97,6 +101,14 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
private static final String URL_HERE = UrlBuilder.getUrl("/uploadImages");
|
private static final String URL_HERE = UrlBuilder.getUrl("/uploadImages");
|
||||||
|
|
||||||
|
private static final String TEXT_BUNDLE = "imageUpload";
|
||||||
|
private static final String TEXT_STRING_UPLOAD_TITLE = "upload_page_title";
|
||||||
|
private static final String TEXT_STRING_UPLOAD_TITLE_WITH_NAME = "upload_page_title_with_name";
|
||||||
|
private static final String TEXT_STRING_REPLACE_TITLE = "replace_page_title";
|
||||||
|
private static final String TEXT_STRING_REPLACE_TITLE_WITH_NAME = "replace_page_title_with_name";
|
||||||
|
private static final String TEXT_STRING_CROP_TITLE = "crop_page_title";
|
||||||
|
private static final String TEXT_STRING_CROP_TITLE_WITH_NAME = "crop_page_title_with_name";
|
||||||
|
|
||||||
private FileStorage fileStorage;
|
private FileStorage fileStorage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,7 +230,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
}
|
}
|
||||||
} catch (UserMistakeException e) {
|
} catch (UserMistakeException e) {
|
||||||
// Can't find the entity? Complain.
|
// Can't find the entity? Complain.
|
||||||
return showAddImagePageWithError(vreq, null, e.getMessage());
|
return showAddImagePageWithError(vreq, null, e.formatMessage(vreq));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// We weren't expecting this - log it, and apologize to the user.
|
// We weren't expecting this - log it, and apologize to the user.
|
||||||
return new ExceptionResponseValues(e);
|
return new ExceptionResponseValues(e);
|
||||||
|
@ -274,7 +286,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
return showCropImagePage(vreq, entity,
|
return showCropImagePage(vreq, entity,
|
||||||
fileInfo.getBytestreamAliasUrl(), size);
|
fileInfo.getBytestreamAliasUrl(), size);
|
||||||
} catch (UserMistakeException e) {
|
} catch (UserMistakeException e) {
|
||||||
return showErrorMessage(vreq, entity, e.getMessage());
|
return showErrorMessage(vreq, entity, e.formatMessage(vreq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +296,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
*/
|
*/
|
||||||
private ResponseValues showErrorMessage(VitroRequest vreq,
|
private ResponseValues showErrorMessage(VitroRequest vreq,
|
||||||
Individual entity, String message) {
|
Individual entity, String message) {
|
||||||
|
|
||||||
ImageInfo imageInfo = ImageInfo.instanceFromEntityUri(
|
ImageInfo imageInfo = ImageInfo.instanceFromEntityUri(
|
||||||
vreq.getFullWebappDaoFactory(), entity);
|
vreq.getFullWebappDaoFactory(), entity);
|
||||||
if (imageInfo == null) {
|
if (imageInfo == null) {
|
||||||
|
@ -313,7 +326,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
return showExitPage(vreq, entity);
|
return showExitPage(vreq, entity);
|
||||||
} catch (UserMistakeException e) {
|
} catch (UserMistakeException e) {
|
||||||
return showErrorMessage(vreq, entity, e.getMessage());
|
return showErrorMessage(vreq, entity, e.formatMessage(vreq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,15 +363,14 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
throws UserMistakeException {
|
throws UserMistakeException {
|
||||||
String entityUri = vreq.getParameter(PARAMETER_ENTITY_URI);
|
String entityUri = vreq.getParameter(PARAMETER_ENTITY_URI);
|
||||||
if (entityUri == null) {
|
if (entityUri == null) {
|
||||||
throw new UserMistakeException("No entity URI was provided");
|
throw new UserMistakeException(ERROR_CODE_NO_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
Individual entity = vreq.getFullWebappDaoFactory().getIndividualDao()
|
Individual entity = vreq.getFullWebappDaoFactory().getIndividualDao()
|
||||||
.getIndividualByURI(entityUri);
|
.getIndividualByURI(entityUri);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
throw new UserMistakeException(
|
throw new UserMistakeException(ERROR_CODE_UNRECOGNIZED_URI,
|
||||||
"This URI is not recognized as belonging to anyone: '"
|
entityUri);
|
||||||
+ entityUri + "'");
|
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
@ -416,7 +428,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
rv.put(BODY_THUMBNAIL_URL, placeholderUrl);
|
rv.put(BODY_THUMBNAIL_URL, placeholderUrl);
|
||||||
rv.put(BODY_FORM_ACTION, formAction);
|
rv.put(BODY_FORM_ACTION, formAction);
|
||||||
rv.put(BODY_CANCEL_URL, cancelUrl);
|
rv.put(BODY_CANCEL_URL, cancelUrl);
|
||||||
rv.put(BODY_TITLE, "Upload image" + forName(entity));
|
rv.put(BODY_TITLE, figureUploadPageTitle(vreq, entity));
|
||||||
rv.put(BODY_MAX_FILE_SIZE, MAXIMUM_FILE_SIZE / (1024 * 1024));
|
rv.put(BODY_MAX_FILE_SIZE, MAXIMUM_FILE_SIZE / (1024 * 1024));
|
||||||
rv.put(BODY_THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT);
|
rv.put(BODY_THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT);
|
||||||
rv.put(BODY_THUMBNAIL_WIDTH, THUMBNAIL_WIDTH);
|
rv.put(BODY_THUMBNAIL_WIDTH, THUMBNAIL_WIDTH);
|
||||||
|
@ -442,7 +454,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
rv.put(BODY_DELETE_URL, formAction(entity.getURI(), ACTION_DELETE_EDIT));
|
rv.put(BODY_DELETE_URL, formAction(entity.getURI(), ACTION_DELETE_EDIT));
|
||||||
rv.put(BODY_FORM_ACTION, formAction(entity.getURI(), ACTION_UPLOAD));
|
rv.put(BODY_FORM_ACTION, formAction(entity.getURI(), ACTION_UPLOAD));
|
||||||
rv.put(BODY_CANCEL_URL, exitPageUrl(vreq, entity.getURI()));
|
rv.put(BODY_CANCEL_URL, exitPageUrl(vreq, entity.getURI()));
|
||||||
rv.put(BODY_TITLE, "Replace image" + forName(entity));
|
rv.put(BODY_TITLE, figureReplacePageTitle(vreq, entity));
|
||||||
rv.put(BODY_MAX_FILE_SIZE, MAXIMUM_FILE_SIZE / (1024 * 1024));
|
rv.put(BODY_MAX_FILE_SIZE, MAXIMUM_FILE_SIZE / (1024 * 1024));
|
||||||
rv.put(BODY_THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT);
|
rv.put(BODY_THUMBNAIL_HEIGHT, THUMBNAIL_HEIGHT);
|
||||||
rv.put(BODY_THUMBNAIL_WIDTH, THUMBNAIL_WIDTH);
|
rv.put(BODY_THUMBNAIL_WIDTH, THUMBNAIL_WIDTH);
|
||||||
|
@ -472,7 +484,7 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
rv.put(BODY_MAIN_IMAGE_WIDTH, dimensions.width);
|
rv.put(BODY_MAIN_IMAGE_WIDTH, dimensions.width);
|
||||||
rv.put(BODY_FORM_ACTION, formAction(entity.getURI(), ACTION_SAVE));
|
rv.put(BODY_FORM_ACTION, formAction(entity.getURI(), ACTION_SAVE));
|
||||||
rv.put(BODY_CANCEL_URL, exitPageUrl(vreq, entity.getURI()));
|
rv.put(BODY_CANCEL_URL, exitPageUrl(vreq, entity.getURI()));
|
||||||
rv.put(BODY_TITLE, "Crop Photo" + forName(entity));
|
rv.put(BODY_TITLE, figureCropPageTitle(vreq, entity));
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,24 +534,59 @@ public class ImageUploadController extends FreemarkerHttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the entity's name for display as part of the page title.
|
* Format the title for the Upload page.
|
||||||
*/
|
*/
|
||||||
private String forName(Individual entity) {
|
private String figureUploadPageTitle(HttpServletRequest req,
|
||||||
|
Individual entity) {
|
||||||
|
return figurePageTitle(req, entity, TEXT_STRING_UPLOAD_TITLE,
|
||||||
|
TEXT_STRING_UPLOAD_TITLE_WITH_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the title for the Replace page.
|
||||||
|
*/
|
||||||
|
private String figureReplacePageTitle(HttpServletRequest req,
|
||||||
|
Individual entity) {
|
||||||
|
return figurePageTitle(req, entity, TEXT_STRING_REPLACE_TITLE,
|
||||||
|
TEXT_STRING_REPLACE_TITLE_WITH_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the title for the Crop page.
|
||||||
|
*/
|
||||||
|
private String figureCropPageTitle(HttpServletRequest req, Individual entity) {
|
||||||
|
return figurePageTitle(req, entity, TEXT_STRING_CROP_TITLE,
|
||||||
|
TEXT_STRING_CROP_TITLE_WITH_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format one of two page titles, depending on whether the entity has a
|
||||||
|
* name.
|
||||||
|
*/
|
||||||
|
private String figurePageTitle(HttpServletRequest req, Individual entity,
|
||||||
|
String noNameTitleKey, String nameTitleKey) {
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
String name = entity.getName();
|
String name = entity.getName();
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
return " for " + name;
|
return I18n.text(req, TEXT_BUNDLE, nameTitleKey, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return I18n.text(req, TEXT_BUNDLE, noNameTitleKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds an error message to use as a complaint to the user.
|
* Holds an error message to use as a complaint to the user.
|
||||||
*/
|
*/
|
||||||
static class UserMistakeException extends Exception {
|
static class UserMistakeException extends Exception {
|
||||||
UserMistakeException(String message) {
|
private final Object[] parameters;
|
||||||
|
|
||||||
|
UserMistakeException(String message, Object... parameters) {
|
||||||
super(message);
|
super(message);
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String formatMessage(HttpServletRequest req) {
|
||||||
|
return I18n.text(req, getMessage(), parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,18 @@ import edu.cornell.mannlib.vitro.webapp.filestorage.uploadrequest.FileUploadServ
|
||||||
public class ImageUploadHelper {
|
public class ImageUploadHelper {
|
||||||
private static final Log log = LogFactory.getLog(ImageUploadHelper.class);
|
private static final Log log = LogFactory.getLog(ImageUploadHelper.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keys to text strings for error messages.
|
||||||
|
*/
|
||||||
|
private static final String ERROR_CODE_NO_IMAGE_TO_CROP = "imageUpload.errorNoImageForCropping";
|
||||||
|
private static final String ERROR_CODE_IMAGE_TOO_SMALL = "imageUpload.errorImageTooSmall";
|
||||||
|
private static final String ERROR_CODE_UNKNOWN = "imageUpload.errorUnknown";
|
||||||
|
private static final String ERROR_CODE_FILE_TOO_BIG = "imageUpload.errorFileTooBig";
|
||||||
|
private static final String ERROR_CODE_UNRECOGNIZED_FILE_TYPE = "imageUpload.errorUnrecognizedFileType";
|
||||||
|
private static final String ERROR_CODE_NO_PHOTO_SELECTED = "imageUpload.errorNoPhotoSelected";
|
||||||
|
private static final String ERROR_CODE_BAD_MULTIPART_REQUEST = "imageUpload.errorBadMultipartRequest";
|
||||||
|
private static final String ERROR_CODE_FORM_FIELD_MISSING = "imageUpload.errorFormFieldMissing";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When they upload a new image, store it as this session attribute until
|
* When they upload a new image, store it as this session attribute until
|
||||||
* we're ready to attach it to the Individual.
|
* we're ready to attach it to the Individual.
|
||||||
|
@ -127,35 +139,31 @@ public class ImageUploadHelper {
|
||||||
Object exception = request.getAttribute(FILE_UPLOAD_EXCEPTION);
|
Object exception = request.getAttribute(FILE_UPLOAD_EXCEPTION);
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
int limit = MAXIMUM_FILE_SIZE / (1024 * 1024);
|
int limit = MAXIMUM_FILE_SIZE / (1024 * 1024);
|
||||||
throw new UserMistakeException(
|
throw new UserMistakeException(ERROR_CODE_FILE_TOO_BIG, limit);
|
||||||
"Please upload an image smaller than " + limit
|
|
||||||
+ " megabytes");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, List<FileItem>> map = (Map<String, List<FileItem>>) request
|
Map<String, List<FileItem>> map = (Map<String, List<FileItem>>) request
|
||||||
.getAttribute(FILE_ITEM_MAP);
|
.getAttribute(FILE_ITEM_MAP);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
throw new IllegalStateException("Failed to parse the "
|
throw new IllegalStateException(ERROR_CODE_BAD_MULTIPART_REQUEST);
|
||||||
+ "multi-part request for uploading an image.");
|
|
||||||
}
|
}
|
||||||
List<FileItem> list = map.get(PARAMETER_UPLOADED_FILE);
|
List<FileItem> list = map.get(PARAMETER_UPLOADED_FILE);
|
||||||
if ((list == null) || list.isEmpty()) {
|
if ((list == null) || list.isEmpty()) {
|
||||||
throw new UserMistakeException("The form did not contain a '"
|
throw new UserMistakeException(ERROR_CODE_FORM_FIELD_MISSING,
|
||||||
+ PARAMETER_UPLOADED_FILE + "' field.");
|
PARAMETER_UPLOADED_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileItem file = list.get(0);
|
FileItem file = list.get(0);
|
||||||
if (file.getSize() == 0) {
|
if (file.getSize() == 0) {
|
||||||
throw new UserMistakeException("Please browse and select a photo.");
|
throw new UserMistakeException(ERROR_CODE_NO_PHOTO_SELECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
String filename = getSimpleFilename(file);
|
String filename = getSimpleFilename(file);
|
||||||
String mimeType = getMimeType(file);
|
String mimeType = getMimeType(file);
|
||||||
if (!RECOGNIZED_FILE_TYPES.containsValue(mimeType)) {
|
if (!RECOGNIZED_FILE_TYPES.containsValue(mimeType)) {
|
||||||
log.debug("Unrecognized MIME type: '" + mimeType + "'");
|
log.debug("Unrecognized MIME type: '" + mimeType + "'");
|
||||||
throw new UserMistakeException("'" + filename
|
throw new UserMistakeException(ERROR_CODE_UNRECOGNIZED_FILE_TYPE,
|
||||||
+ "' is not a recognized image file type. "
|
filename);
|
||||||
+ "Please upload JPEG, GIF, or PNG files only.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
|
@ -221,10 +229,8 @@ public class ImageUploadHelper {
|
||||||
|
|
||||||
if ((size.height < THUMBNAIL_HEIGHT)
|
if ((size.height < THUMBNAIL_HEIGHT)
|
||||||
|| (size.width < THUMBNAIL_WIDTH)) {
|
|| (size.width < THUMBNAIL_WIDTH)) {
|
||||||
throw new UserMistakeException(
|
throw new UserMistakeException(ERROR_CODE_IMAGE_TOO_SMALL,
|
||||||
"The uploaded image should be at least "
|
THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH);
|
||||||
+ THUMBNAIL_HEIGHT + " pixels high and "
|
|
||||||
+ THUMBNAIL_WIDTH + " pixels wide.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -237,8 +243,7 @@ public class ImageUploadHelper {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Unexpected exception in image handling", e);
|
log.warn("Unexpected exception in image handling", e);
|
||||||
throw new UserMistakeException("Sorry, we were unable to process "
|
throw new UserMistakeException(ERROR_CODE_UNKNOWN);
|
||||||
+ "the photo you provided. Please try another photo.");
|
|
||||||
} finally {
|
} finally {
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -261,8 +266,7 @@ public class ImageUploadHelper {
|
||||||
ATTRIBUTE_TEMP_FILE);
|
ATTRIBUTE_TEMP_FILE);
|
||||||
|
|
||||||
if (fileInfo == null) {
|
if (fileInfo == null) {
|
||||||
throw new UserMistakeException(
|
throw new UserMistakeException(ERROR_CODE_NO_IMAGE_TO_CROP);
|
||||||
"There is no image file to be cropped.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
|
|
73
webapp/web/i18n/all.properties
Normal file
73
webapp/web/i18n/all.properties
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#
|
||||||
|
# Text strings for the controllers and templates
|
||||||
|
#
|
||||||
|
# Default (English)
|
||||||
|
#
|
||||||
|
save_changes = Save changes
|
||||||
|
cancel_link = Cancel
|
||||||
|
cancel_title = cancel
|
||||||
|
required_fields = required fields
|
||||||
|
or = or
|
||||||
|
alt_error_alert = Error alert icon
|
||||||
|
alt_confirmation = Confirmation icon
|
||||||
|
|
||||||
|
email_address = Email address
|
||||||
|
first_name = First name
|
||||||
|
last_name = Last name
|
||||||
|
roles = Roles
|
||||||
|
status = Status
|
||||||
|
|
||||||
|
ascending_order = ascending order
|
||||||
|
descending_order = descending order
|
||||||
|
select_one = Select one
|
||||||
|
|
||||||
|
type_more_characters = type more characters
|
||||||
|
no_match = no match
|
||||||
|
|
||||||
|
request_failed = Request failed. Please contact your system administrator.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Image upload pages
|
||||||
|
#
|
||||||
|
upload_page_title = Upload image
|
||||||
|
upload_page_title_with_name = Upload image for {0}
|
||||||
|
upload_heading = Photo Upload
|
||||||
|
|
||||||
|
replace_page_title = Replace image
|
||||||
|
replace_page_title_with_name = Replace image for {0}
|
||||||
|
|
||||||
|
crop_page_title = Crop image
|
||||||
|
crop_page_title_with_name = Crop image for {0}
|
||||||
|
|
||||||
|
current_photo = Current Photo
|
||||||
|
upload_photo = Upload a photo
|
||||||
|
replace_photo = Replace Photo
|
||||||
|
photo_types = (JPEG, GIF or PNG)
|
||||||
|
maximum_file_size = Maximum file size: {0} megabytes
|
||||||
|
minimum_image_dimensions = Minimum image dimensions: {0} x {1} pixels
|
||||||
|
|
||||||
|
cropping_caption = Your profile photo will look like the image below.
|
||||||
|
cropping_note = To make adjustments, you can drag around and resize the photo to the right. \
|
||||||
|
When you are happy with your photo click the "Save Photo" button.
|
||||||
|
|
||||||
|
alt_thumbnail_photo = Individual photo
|
||||||
|
alt_image_to_crop = Image to be cropped
|
||||||
|
alt_preview_crop = Preview of photo cropped
|
||||||
|
|
||||||
|
delete_link = Delete photo
|
||||||
|
submit_upload = Upload photo
|
||||||
|
submit_save = Save photo
|
||||||
|
|
||||||
|
confirm_delete = Are you sure you want to delete this photo?
|
||||||
|
|
||||||
|
imageUpload.errorNoURI = No entity URI was provided
|
||||||
|
imageUpload.errorUnrecognizedURI = This URI is not recognized as belonging to anyone: ''{0}''
|
||||||
|
imageUpload.errorNoImageForCropping = There is no image file to be cropped.
|
||||||
|
imageUpload.errorImageTooSmall = The uploaded image should be at least {0} pixels high and {1} pixels wide.
|
||||||
|
imageUpload.errorUnknown = Sorry, we were unable to process the photo you provided. Please try another photo.
|
||||||
|
imageUpload.errorFileTooBig = Please upload an image smaller than {0} megabytes.
|
||||||
|
imageUpload.errorUnrecognizedFileType = ''{0}'' is not a recognized image file type. Please upload JPEG, GIF, or PNG files only.
|
||||||
|
imageUpload.errorNoPhotoSelected = Please browse and select a photo.
|
||||||
|
imageUpload.errorBadMultipartRequest = Failed to parse the multi-part request for uploading an image.
|
||||||
|
imageUpload.errorFormFieldMissing = The form did not contain a ''{0}'' field."
|
||||||
|
|
43
webapp/web/i18n/all_es.properties
Normal file
43
webapp/web/i18n/all_es.properties
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#
|
||||||
|
# Text strings for the controllers and templates
|
||||||
|
#
|
||||||
|
# Spanish
|
||||||
|
#
|
||||||
|
cancel_link = Cancelar
|
||||||
|
or = o
|
||||||
|
alt_error_alert = Icono de alerta con error
|
||||||
|
|
||||||
|
#
|
||||||
|
# Image upload pages
|
||||||
|
#
|
||||||
|
upload_page_title = Subir foto
|
||||||
|
upload_page_title_with_name = Subir imagen para {0}
|
||||||
|
upload_heading = Subir foto
|
||||||
|
|
||||||
|
replace_page_title = Reemplazar imagen
|
||||||
|
replace_page_title_with_name = Cambie la imagen por {0}
|
||||||
|
|
||||||
|
crop_page_title = Recortar imagen
|
||||||
|
crop_page_title_with_name = Recorte imagen para {0}
|
||||||
|
|
||||||
|
current_photo = Foto actual
|
||||||
|
upload_photo = Suba foto
|
||||||
|
replace_photo = Reemplace foto
|
||||||
|
photo_types = (JPEG, GIF, o PNG)
|
||||||
|
maximum_file_size = Tamaño máximo de archivo: {0} megabytes
|
||||||
|
minimum_image_dimensions = Dimensiones mínimas de imagen: {0} x {1} pixels
|
||||||
|
|
||||||
|
cropping_caption = La foto de tu perfil se verá como la imagen de abajo.
|
||||||
|
cropping_note = Para realizar ajustes, arrastre alrededor y cambie el tamaño de la foto de la derecha. \
|
||||||
|
Cuando esté satisfecho con su foto, haga clic en el botón "Guardar foto".
|
||||||
|
|
||||||
|
alt_thumbnail_photo = Foto de individuo
|
||||||
|
alt_image_to_crop = Imagen que desea recortar
|
||||||
|
alt_preview_crop = Vista previa de la foto recortada
|
||||||
|
|
||||||
|
delete_link = Borrar foto
|
||||||
|
submit_upload = Subir foto
|
||||||
|
submit_save = Guardar foto
|
||||||
|
|
||||||
|
confirm_delete = ¿Seguro que quiere borrar esta foto?
|
||||||
|
|
|
@ -4,7 +4,7 @@ $(document).ready(function(){
|
||||||
|
|
||||||
// Confirmation alert for photo deletion in image upload and individual templates
|
// Confirmation alert for photo deletion in image upload and individual templates
|
||||||
$('#photoUploadDefaultImage a.thumbnail, a.delete-mainImage').click(function(){
|
$('#photoUploadDefaultImage a.thumbnail, a.delete-mainImage').click(function(){
|
||||||
var answer = confirm('Are you sure you want to delete this photo?');
|
var answer = confirm(i18n_confirmDelete);
|
||||||
return answer;
|
return answer;
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -21,20 +21,22 @@ ${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.cs
|
||||||
</#macro>-->
|
</#macro>-->
|
||||||
|
|
||||||
|
|
||||||
|
<#assign i18n = i18n() >
|
||||||
|
|
||||||
<section id="photoCroppingContainer" role="region">
|
<section id="photoCroppingContainer" role="region">
|
||||||
<h2>Photo Upload</h2>
|
<h2>${i18n.upload_heading}</h2>
|
||||||
|
|
||||||
<!-- This is the image we're attaching Jcrop to -->
|
<!-- This is the image we're attaching Jcrop to -->
|
||||||
<section id="photoCroppingPreview" role="region">
|
<section id="photoCroppingPreview" role="region">
|
||||||
|
|
||||||
<p class="photoCroppingTitleBody">Your profile photo will look like the image below. </p>
|
<p class="photoCroppingTitleBody">${i18n.cropping_caption}</p>
|
||||||
|
|
||||||
<section class="photoCroppedPreview" role="region">
|
<section class="photoCroppedPreview" role="region">
|
||||||
<img src="${imageUrl}" id="preview" alt="Image to be cropped"/>
|
<img src="${imageUrl}" id="preview" alt="${i18n.alt_image_to_crop}"/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="photoCroppingHowTo" role="region">
|
<section id="photoCroppingHowTo" role="region">
|
||||||
<p class="photoCroppingNote">To make adjustments, you can drag around and resize the photo to the right. When you are happy with your photo click the "Save Photo" button. </p>
|
<p class="photoCroppingNote">${i18n.cropping_note}</p>
|
||||||
|
|
||||||
<form id="cropImage" action="${formAction}" method="post" role="form">
|
<form id="cropImage" action="${formAction}" method="post" role="form">
|
||||||
<!-- Javascript will populate these values -->
|
<!-- Javascript will populate these values -->
|
||||||
|
@ -43,15 +45,15 @@ ${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.cs
|
||||||
<input type="hidden" name="w" value="" />
|
<input type="hidden" name="w" value="" />
|
||||||
<input type="hidden" name="h" value="" />
|
<input type="hidden" name="h" value="" />
|
||||||
|
|
||||||
<input class="submit" type="submit" value="Save photo">
|
<input class="submit" type="submit" value="${i18n.submit_save}">
|
||||||
|
|
||||||
<span class="or"> or <a class="cancel" href="${cancelUrl}" title="cancel">Cancel</a></span>
|
<span class="or"> ${i18n.or} <a class="cancel" href="${cancelUrl}" title="${i18n.cancel_title}">${i18n.cancel_link}</a></span>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="photoCropping" role="region">
|
<section id="photoCropping" role="region">
|
||||||
<img src="${imageUrl}" id="cropbox" alt="Preview of photo cropped" />
|
<img src="${imageUrl}" id="cropbox" alt="${i18n.alt_preview_crop}" />
|
||||||
</section
|
</section
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -7,29 +7,35 @@ ${scripts.add('<script type="text/javascript" src="${urls.base}/js/jquery.js"></
|
||||||
|
|
||||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.css" />')}
|
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.css" />')}
|
||||||
|
|
||||||
|
<#assign i18n = i18n() >
|
||||||
|
|
||||||
<section id="photoUploadContainer" role="region">
|
<section id="photoUploadContainer" role="region">
|
||||||
<h2>Photo Upload</h2>
|
<h2>${i18n.upload_heading}</h2>
|
||||||
|
|
||||||
<#if errorMessage??>
|
<#if errorMessage??>
|
||||||
<section id="error-alert" role="alert"><img src="${urls.images}/iconAlert.png" alt="Error alert icon" />
|
<section id="error-alert" role="alert"><img src="${urls.images}/iconAlert.png" alt="${i18n.alt_error_alert}" />
|
||||||
<p>${errorMessage}</p>
|
<p>${errorMessage}</p>
|
||||||
</section>
|
</section>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<section id="photoUploadDefaultImage" role="region">
|
<section id="photoUploadDefaultImage" role="region">
|
||||||
<h3>Current Photo</h3>
|
<h3>${i18n.current_photo}</h3>
|
||||||
|
|
||||||
<img src="${thumbnailUrl}" width="115" height="115" alt="Individual photo" />
|
<img src="${thumbnailUrl}" width="115" height="115" alt="${i18n.alt_thumbnail_photo}" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<form id="photoUploadForm" action="${formAction}" enctype="multipart/form-data" method="post" role="form">
|
<form id="photoUploadForm" action="${formAction}" enctype="multipart/form-data" method="post" role="form">
|
||||||
<label>Upload a photo <span> (JPEG, GIF or PNG)</span></label>
|
<label>${i18n.upload_photo} <span>${i18n.photo_types}</span></label>
|
||||||
|
|
||||||
<input id="datafile" type="file" name="datafile" size="30" />
|
<input id="datafile" type="file" name="datafile" size="30" />
|
||||||
<p class="note">Maximum file size: ${maxFileSize} megabytes<br />
|
<p class="note">${i18n.maximum_file_size(maxFileSize)}<br />
|
||||||
Minimum image dimensions: ${thumbnailWidth} x ${thumbnailHeight} pixels</p>
|
${i18n.minimum_image_dimensions(thumbnailWidth, thumbnailHeight)}</p>
|
||||||
<input class="submit" type="submit" value="Upload photo"/>
|
<input class="submit" type="submit" value="${i18n.submit_upload}"/>
|
||||||
|
|
||||||
<span class="or"> or <a class="cancel" href="${cancelUrl}" title="cancel">Cancel</a></span>
|
<span class="or"> ${i18n.or} <a class="cancel" href="${cancelUrl}" title="${i18n.cancel_title}">${i18n.cancel_link}</a></span>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
i18n_confirmDelete = ${i18n.confirm_delete}
|
||||||
|
</script>
|
||||||
|
|
|
@ -7,30 +7,36 @@ ${scripts.add('<script type="text/javascript" src="${urls.base}/js/jquery.js"></
|
||||||
|
|
||||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.css" />')}
|
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/css/uploadImages.css" />')}
|
||||||
|
|
||||||
|
<#assign i18n = i18n() >
|
||||||
|
|
||||||
<section id="photoUpload" role="region">
|
<section id="photoUpload" role="region">
|
||||||
<h2>Photo Upload</h2>
|
<h2>${i18n.upload_heading}</h2>
|
||||||
|
|
||||||
<#if errorMessage??>
|
<#if errorMessage??>
|
||||||
<section id="error-alert" role="alert"><img src="${urls.images}/iconAlert.png" alt="Error alert icon" />
|
<section id="error-alert" role="alert"><img src="${urls.images}/iconAlert.png" alt="${i18n.alt_error_alert}" />
|
||||||
<p>${errorMessage}</p>
|
<p>${errorMessage}</p>
|
||||||
</section>
|
</section>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
<section id="photoUploadDefaultImage" role="region">
|
<section id="photoUploadDefaultImage" role="region">
|
||||||
<h3>Current Photo</h3>
|
<h3>${i18n.current_photo}</h3>
|
||||||
<img src="${thumbnailUrl}" width="115" alt="Individual photo" />
|
<img src="${thumbnailUrl}" width="115" alt="${i18n.alt_thumbnail_photo}" />
|
||||||
|
|
||||||
<a class="thumbnail" href="${deleteUrl}">Delete photo</a>
|
<a class="thumbnail" href="${deleteUrl}">${i18n.delete_link}</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<form id="photoUploadForm" action="${formAction}" enctype="multipart/form-data" method="post" role="form">
|
<form id="photoUploadForm" action="${formAction}" enctype="multipart/form-data" method="post" role="form">
|
||||||
<label>Replace Photo <span> (JPEG, GIF or PNG)</span></label>
|
<label>${i18n.replace_photo} <span>${i18n.photo_types}</span></label>
|
||||||
|
|
||||||
<input type="file" name="datafile" size="30">
|
<input type="file" name="datafile" size="30">
|
||||||
<p class="note">Maximum file size: ${maxFileSize} megabytes<br />
|
<p class="note">${i18n.maximum_file_size(maxFileSize)}<br />
|
||||||
Minimum image dimensions: ${thumbnailWidth}x${thumbnailHeight} pixels</p>
|
${i18n.minimum_image_dimensions(thumbnailWidth, thumbnailHeight)}</p>
|
||||||
<input class="submit" type="submit" value="Upload photo">
|
<input class="submit" type="submit" value="${i18n.submit_upload}">
|
||||||
|
|
||||||
<span class="or"> or <a class="cancel" href="${cancelUrl}" title="cancel">Cancel</a></span>
|
<span class="or"> ${i18n.or} <a class="cancel" href="${cancelUrl}" title="${i18n.cancel_title}">${i18n.cancel_link}</a></span>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
i18n_confirmDelete = "${i18n.confirm_delete}"
|
||||||
|
</script>
|
||||||
|
|
|
@ -77,3 +77,7 @@ ${headScripts.add('<script type="text/javascript" src="${urls.base}/js/jquery_pl
|
||||||
|
|
||||||
${scripts.add('<script type="text/javascript" src="${urls.base}/js/imageUpload/imageUploadUtils.js"></script>',
|
${scripts.add('<script type="text/javascript" src="${urls.base}/js/imageUpload/imageUploadUtils.js"></script>',
|
||||||
'<script type="text/javascript" src="${urls.base}/js/individual/individualUriRdf.js"></script>')}
|
'<script type="text/javascript" src="${urls.base}/js/individual/individualUriRdf.js"></script>')}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
i18n_confirmDelete = "${i18n().confirm_delete}"
|
||||||
|
</script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue