Adding hidden URL (*.edit) to edit captions through web interface.
This commit is contained in:
parent
99afd6d29f
commit
ad19ca5200
6 changed files with 876 additions and 0 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package org.forkalsrud.album.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
|
|
@ -26,6 +28,7 @@ import org.forkalsrud.album.exif.DirectoryEntry;
|
|||
import org.forkalsrud.album.exif.Entry;
|
||||
import org.forkalsrud.album.exif.FileEntry;
|
||||
import org.forkalsrud.album.exif.Thumbnail;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import com.sleepycat.je.Environment;
|
||||
import com.sleepycat.je.EnvironmentConfig;
|
||||
|
|
@ -163,6 +166,13 @@ public class AlbumServlet
|
|||
environment.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
doGet(req, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse res)
|
||||
throws ServletException, IOException
|
||||
|
|
@ -192,6 +202,12 @@ public class AlbumServlet
|
|||
return;
|
||||
}
|
||||
|
||||
if (pathInfo.endsWith(".edit")) {
|
||||
pathInfo = pathInfo.substring(0, pathInfo.length() - ".edit".length());
|
||||
handleEdit(req, res, (FileEntry)resolveEntry(pathInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(base, pathInfo);
|
||||
if (!file.canRead()) {
|
||||
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
|
|
@ -237,6 +253,34 @@ public class AlbumServlet
|
|||
}
|
||||
}
|
||||
|
||||
void handleEdit(HttpServletRequest req, HttpServletResponse res, FileEntry entry) {
|
||||
try {
|
||||
String value = req.getParameter("value");
|
||||
if (value != null) {
|
||||
File propertyFile = new File(entry.getPath().getParent(), "album.properties");
|
||||
Properties props = new Properties();
|
||||
if (propertyFile.exists()) {
|
||||
FileInputStream fis = new FileInputStream(propertyFile);
|
||||
props.load(fis);
|
||||
fis.close();
|
||||
}
|
||||
props.setProperty("file." + entry.getName() + ".caption", value);
|
||||
FileOutputStream fos = new FileOutputStream(propertyFile);
|
||||
props.store(fos, "online editor");
|
||||
fos.close();
|
||||
res.setContentType("text/html");
|
||||
res.getWriter().println(HtmlUtils.htmlEscape(value));
|
||||
return;
|
||||
}
|
||||
res.setContentType("text/html");
|
||||
req.setAttribute("entry", entry);
|
||||
req.setAttribute("thmb", new Integer(640));
|
||||
RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/velocity/edit.vm");
|
||||
rd.forward(req, res);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("sadness", ex);
|
||||
}
|
||||
}
|
||||
|
||||
boolean etagMatches(HttpServletRequest req, String fileEtag) {
|
||||
|
||||
|
|
|
|||
81
src/main/webapp/WEB-INF/velocity/edit.vm
Normal file
81
src/main/webapp/WEB-INF/velocity/edit.vm
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width = 600" />
|
||||
<title>$entry.name</title>
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="${assets}/jeditable/jquery.autogrow.js"></script>
|
||||
<script type="text/javascript" src="${assets}/jeditable/jquery.jeditable.js"></script>
|
||||
<script type="text/javascript" src="${assets}/jeditable/jquery.jeditable.autogrow.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-size: 11px;
|
||||
font-family: "Lucida Grande", "Lucida Sans", Arial, sans-serif;
|
||||
color: #6d6d6d;
|
||||
background: #acc95f;
|
||||
margin: 10px auto;
|
||||
}
|
||||
h1 {
|
||||
text-align: left;
|
||||
}
|
||||
a:link, a:visited {
|
||||
text-decoration: none;
|
||||
color: #4c4c4c;
|
||||
font-weight: 700;
|
||||
}
|
||||
a:hover, a:focus {
|
||||
text-decoration: underline;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
p.caption {
|
||||
width: ${thmb}px;
|
||||
}
|
||||
img.picture {
|
||||
box-shadow: 5px 5px 5px #777;
|
||||
-webkit-box-shadow: 5px 5px 5px #777;
|
||||
-moz-box-shadow: 5px 5px 5px #777;
|
||||
}
|
||||
div.imgborder {
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
#set($editUrl = $mapper.map(${entry.getPath()}))
|
||||
|
||||
$(".caption").editable("http://localhost:8080${base}${editUrl}.edit", {
|
||||
method : "GET",
|
||||
callback : function(value, settings) {
|
||||
console.log(this);
|
||||
console.log(value);
|
||||
console.log(settings);
|
||||
},
|
||||
type : "autogrow",
|
||||
submit : "OK",
|
||||
cancel : "Cancel",
|
||||
tooltip : "Click to edit...",
|
||||
submitdata : { foo: "bar" },
|
||||
autogrow : {
|
||||
lineHeight : 16,
|
||||
minHeight : 32
|
||||
},
|
||||
onblur : "ignore"
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>$entry.name</h1>
|
||||
<hr/>
|
||||
#set($dim = $entry.thumbnail.size.scaled($thmb))
|
||||
#set($thpath = $mapper.map(${entry.thumbnail.getPath()}))
|
||||
<div class="imgborder"><img class="picture" src="${base}${thpath}?size=${thmb}" border="0" width="${dim.width}" height="${dim.height}"/></a></div>
|
||||
<p class="caption">$!entry.caption</p>
|
||||
</body>
|
||||
</html>
|
||||
132
src/main/webapp/assets/jeditable/jquery.autogrow.js
Normal file
132
src/main/webapp/assets/jeditable/jquery.autogrow.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Auto Expanding Text Area (1.2.2)
|
||||
* by Chrys Bader (www.chrysbader.com)
|
||||
* chrysb@gmail.com
|
||||
*
|
||||
* Special thanks to:
|
||||
* Jake Chapa - jake@hybridstudio.com
|
||||
* John Resig - jeresig@gmail.com
|
||||
*
|
||||
* Copyright (c) 2008 Chrys Bader (www.chrysbader.com)
|
||||
* Licensed under the GPL (GPL-LICENSE.txt) license.
|
||||
*
|
||||
*
|
||||
* NOTE: This script requires jQuery to work. Download jQuery at www.jquery.com
|
||||
*
|
||||
*/
|
||||
|
||||
(function(jQuery) {
|
||||
|
||||
var self = null;
|
||||
|
||||
jQuery.fn.autogrow = function(o)
|
||||
{
|
||||
return this.each(function() {
|
||||
new jQuery.autogrow(this, o);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The autogrow object.
|
||||
*
|
||||
* @constructor
|
||||
* @name jQuery.autogrow
|
||||
* @param Object e The textarea to create the autogrow for.
|
||||
* @param Hash o A set of key/value pairs to set as configuration properties.
|
||||
* @cat Plugins/autogrow
|
||||
*/
|
||||
|
||||
jQuery.autogrow = function (e, o)
|
||||
{
|
||||
this.options = o || {};
|
||||
this.dummy = null;
|
||||
this.interval = null;
|
||||
this.line_height = this.options.lineHeight || parseInt(jQuery(e).css('line-height'));
|
||||
this.min_height = this.options.minHeight || parseInt(jQuery(e).css('min-height'));
|
||||
this.max_height = this.options.maxHeight || parseInt(jQuery(e).css('max-height'));;
|
||||
this.textarea = jQuery(e);
|
||||
|
||||
if(this.line_height == NaN)
|
||||
this.line_height = 0;
|
||||
|
||||
// Only one textarea activated at a time, the one being used
|
||||
this.init();
|
||||
};
|
||||
|
||||
jQuery.autogrow.fn = jQuery.autogrow.prototype = {
|
||||
autogrow: '1.2.2'
|
||||
};
|
||||
|
||||
jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend;
|
||||
|
||||
jQuery.autogrow.fn.extend({
|
||||
|
||||
init: function() {
|
||||
var self = this;
|
||||
this.textarea.css({overflow: 'hidden', display: 'block'});
|
||||
this.textarea.bind('focus', function() { self.startExpand() } ).bind('blur', function() { self.stopExpand() });
|
||||
this.checkExpand();
|
||||
},
|
||||
|
||||
startExpand: function() {
|
||||
var self = this;
|
||||
this.interval = window.setInterval(function() {self.checkExpand()}, 400);
|
||||
},
|
||||
|
||||
stopExpand: function() {
|
||||
clearInterval(this.interval);
|
||||
},
|
||||
|
||||
checkExpand: function() {
|
||||
|
||||
if (this.dummy == null)
|
||||
{
|
||||
this.dummy = jQuery('<div></div>');
|
||||
this.dummy.css({
|
||||
'font-size' : this.textarea.css('font-size'),
|
||||
'font-family': this.textarea.css('font-family'),
|
||||
'width' : this.textarea.css('width'),
|
||||
'padding' : this.textarea.css('padding'),
|
||||
'line-height': this.line_height + 'px',
|
||||
'overflow-x' : 'hidden',
|
||||
'position' : 'absolute',
|
||||
'top' : 0,
|
||||
'left' : -9999
|
||||
}).appendTo('body');
|
||||
}
|
||||
|
||||
// Strip HTML tags
|
||||
var html = this.textarea.val().replace(/(<|>)/g, '');
|
||||
|
||||
// IE is different, as per usual
|
||||
if ($.browser.msie)
|
||||
{
|
||||
html = html.replace(/\n/g, '<BR>new');
|
||||
}
|
||||
else
|
||||
{
|
||||
html = html.replace(/\n/g, '<br>new');
|
||||
}
|
||||
|
||||
if (this.dummy.html() != html)
|
||||
{
|
||||
this.dummy.html(html);
|
||||
|
||||
if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height))
|
||||
{
|
||||
this.textarea.css('overflow-y', 'auto');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.textarea.css('overflow-y', 'hidden');
|
||||
if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height()))
|
||||
{
|
||||
this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
})(jQuery);
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Autogrow textarea for Jeditable
|
||||
*
|
||||
* Copyright (c) 2008 Mika Tuupola
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Depends on Autogrow jQuery plugin by Chrys Bader:
|
||||
* http://www.aclevercookie.com/facebook-like-auto-growing-textarea/
|
||||
*
|
||||
* Project home:
|
||||
* http://www.appelsiini.net/projects/jeditable
|
||||
*
|
||||
* Revision: $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
$.editable.addInputType('autogrow', {
|
||||
element : function(settings, original) {
|
||||
var textarea = $('<textarea />');
|
||||
if (settings.rows) {
|
||||
textarea.attr('rows', settings.rows);
|
||||
} else {
|
||||
textarea.height(settings.height);
|
||||
}
|
||||
if (settings.cols) {
|
||||
textarea.attr('cols', settings.cols);
|
||||
} else {
|
||||
textarea.width(settings.width);
|
||||
}
|
||||
$(this).append(textarea);
|
||||
return(textarea);
|
||||
},
|
||||
plugin : function(settings, original) {
|
||||
$('textarea', this).autogrow(settings.autogrow);
|
||||
}
|
||||
});
|
||||
543
src/main/webapp/assets/jeditable/jquery.jeditable.js
Normal file
543
src/main/webapp/assets/jeditable/jquery.jeditable.js
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
/*
|
||||
* Jeditable - jQuery in place edit plugin
|
||||
*
|
||||
* Copyright (c) 2006-2009 Mika Tuupola, Dylan Verheul
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Project home:
|
||||
* http://www.appelsiini.net/projects/jeditable
|
||||
*
|
||||
* Based on editable by Dylan Verheul <dylan_at_dyve.net>:
|
||||
* http://www.dyve.net/jquery/?editable
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Version 1.7.1
|
||||
*
|
||||
* ** means there is basic unit tests for this parameter.
|
||||
*
|
||||
* @name Jeditable
|
||||
* @type jQuery
|
||||
* @param String target (POST) URL or function to send edited content to **
|
||||
* @param Hash options additional options
|
||||
* @param String options[method] method to use to send edited content (POST or PUT) **
|
||||
* @param Function options[callback] Function to run after submitting edited content **
|
||||
* @param String options[name] POST parameter name of edited content
|
||||
* @param String options[id] POST parameter name of edited div id
|
||||
* @param Hash options[submitdata] Extra parameters to send when submitting edited content.
|
||||
* @param String options[type] text, textarea or select (or any 3rd party input type) **
|
||||
* @param Integer options[rows] number of rows if using textarea **
|
||||
* @param Integer options[cols] number of columns if using textarea **
|
||||
* @param Mixed options[height] 'auto', 'none' or height in pixels **
|
||||
* @param Mixed options[width] 'auto', 'none' or width in pixels **
|
||||
* @param String options[loadurl] URL to fetch input content before editing **
|
||||
* @param String options[loadtype] Request type for load url. Should be GET or POST.
|
||||
* @param String options[loadtext] Text to display while loading external content.
|
||||
* @param Mixed options[loaddata] Extra parameters to pass when fetching content before editing.
|
||||
* @param Mixed options[data] Or content given as paramameter. String or function.**
|
||||
* @param String options[indicator] indicator html to show when saving
|
||||
* @param String options[tooltip] optional tooltip text via title attribute **
|
||||
* @param String options[event] jQuery event such as 'click' of 'dblclick' **
|
||||
* @param String options[submit] submit button value, empty means no button **
|
||||
* @param String options[cancel] cancel button value, empty means no button **
|
||||
* @param String options[cssclass] CSS class to apply to input form. 'inherit' to copy from parent. **
|
||||
* @param String options[style] Style to apply to input form 'inherit' to copy from parent. **
|
||||
* @param String options[select] true or false, when true text is highlighted ??
|
||||
* @param String options[placeholder] Placeholder text or html to insert when element is empty. **
|
||||
* @param String options[onblur] 'cancel', 'submit', 'ignore' or function ??
|
||||
*
|
||||
* @param Function options[onsubmit] function(settings, original) { ... } called before submit
|
||||
* @param Function options[onreset] function(settings, original) { ... } called before reset
|
||||
* @param Function options[onerror] function(settings, original, xhr) { ... } called on error
|
||||
*
|
||||
* @param Hash options[ajaxoptions] jQuery Ajax options. See docs.jquery.com.
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.fn.editable = function(target, options) {
|
||||
|
||||
if ('disable' == target) {
|
||||
$(this).data('disabled.editable', true);
|
||||
return;
|
||||
}
|
||||
if ('enable' == target) {
|
||||
$(this).data('disabled.editable', false);
|
||||
return;
|
||||
}
|
||||
if ('destroy' == target) {
|
||||
$(this)
|
||||
.unbind($(this).data('event.editable'))
|
||||
.removeData('disabled.editable')
|
||||
.removeData('event.editable');
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = $.extend({}, $.fn.editable.defaults, {target:target}, options);
|
||||
|
||||
/* setup some functions */
|
||||
var plugin = $.editable.types[settings.type].plugin || function() { };
|
||||
var submit = $.editable.types[settings.type].submit || function() { };
|
||||
var buttons = $.editable.types[settings.type].buttons
|
||||
|| $.editable.types['defaults'].buttons;
|
||||
var content = $.editable.types[settings.type].content
|
||||
|| $.editable.types['defaults'].content;
|
||||
var element = $.editable.types[settings.type].element
|
||||
|| $.editable.types['defaults'].element;
|
||||
var reset = $.editable.types[settings.type].reset
|
||||
|| $.editable.types['defaults'].reset;
|
||||
var callback = settings.callback || function() { };
|
||||
var onedit = settings.onedit || function() { };
|
||||
var onsubmit = settings.onsubmit || function() { };
|
||||
var onreset = settings.onreset || function() { };
|
||||
var onerror = settings.onerror || reset;
|
||||
|
||||
/* show tooltip */
|
||||
if (settings.tooltip) {
|
||||
$(this).attr('title', settings.tooltip);
|
||||
}
|
||||
|
||||
settings.autowidth = 'auto' == settings.width;
|
||||
settings.autoheight = 'auto' == settings.height;
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
/* save this to self because this changes when scope changes */
|
||||
var self = this;
|
||||
|
||||
/* inlined block elements lose their width and height after first edit */
|
||||
/* save them for later use as workaround */
|
||||
var savedwidth = $(self).width();
|
||||
var savedheight = $(self).height();
|
||||
|
||||
/* save so it can be later used by $.editable('destroy') */
|
||||
$(this).data('event.editable', settings.event);
|
||||
|
||||
/* if element is empty add something clickable (if requested) */
|
||||
if (!$.trim($(this).html())) {
|
||||
$(this).html(settings.placeholder);
|
||||
}
|
||||
|
||||
$(this).bind(settings.event, function(e) {
|
||||
|
||||
/* abort if disabled for this element */
|
||||
if (true === $(this).data('disabled.editable')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* prevent throwing an exeption if edit field is clicked again */
|
||||
if (self.editing) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* abort if onedit hook returns false */
|
||||
if (false === onedit.apply(this, [settings, self])) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* prevent default action and bubbling */
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
/* remove tooltip */
|
||||
if (settings.tooltip) {
|
||||
$(self).removeAttr('title');
|
||||
}
|
||||
|
||||
/* figure out how wide and tall we are, saved width and height */
|
||||
/* are workaround for http://dev.jquery.com/ticket/2190 */
|
||||
if (0 == $(self).width()) {
|
||||
//$(self).css('visibility', 'hidden');
|
||||
settings.width = savedwidth;
|
||||
settings.height = savedheight;
|
||||
} else {
|
||||
if (settings.width != 'none') {
|
||||
settings.width =
|
||||
settings.autowidth ? $(self).width() : settings.width;
|
||||
}
|
||||
if (settings.height != 'none') {
|
||||
settings.height =
|
||||
settings.autoheight ? $(self).height() : settings.height;
|
||||
}
|
||||
}
|
||||
//$(this).css('visibility', '');
|
||||
|
||||
/* remove placeholder text, replace is here because of IE */
|
||||
if ($(this).html().toLowerCase().replace(/(;|")/g, '') ==
|
||||
settings.placeholder.toLowerCase().replace(/(;|")/g, '')) {
|
||||
$(this).html('');
|
||||
}
|
||||
|
||||
self.editing = true;
|
||||
self.revert = $(self).html();
|
||||
$(self).html('');
|
||||
|
||||
/* create the form object */
|
||||
var form = $('<form />');
|
||||
|
||||
/* apply css or style or both */
|
||||
if (settings.cssclass) {
|
||||
if ('inherit' == settings.cssclass) {
|
||||
form.attr('class', $(self).attr('class'));
|
||||
} else {
|
||||
form.attr('class', settings.cssclass);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.style) {
|
||||
if ('inherit' == settings.style) {
|
||||
form.attr('style', $(self).attr('style'));
|
||||
/* IE needs the second line or display wont be inherited */
|
||||
form.css('display', $(self).css('display'));
|
||||
} else {
|
||||
form.attr('style', settings.style);
|
||||
}
|
||||
}
|
||||
|
||||
/* add main input element to form and store it in input */
|
||||
var input = element.apply(form, [settings, self]);
|
||||
|
||||
/* set input content via POST, GET, given data or existing value */
|
||||
var input_content;
|
||||
|
||||
if (settings.loadurl) {
|
||||
var t = setTimeout(function() {
|
||||
input.disabled = true;
|
||||
content.apply(form, [settings.loadtext, settings, self]);
|
||||
}, 100);
|
||||
|
||||
var loaddata = {};
|
||||
loaddata[settings.id] = self.id;
|
||||
if ($.isFunction(settings.loaddata)) {
|
||||
$.extend(loaddata, settings.loaddata.apply(self, [self.revert, settings]));
|
||||
} else {
|
||||
$.extend(loaddata, settings.loaddata);
|
||||
}
|
||||
$.ajax({
|
||||
type : settings.loadtype,
|
||||
url : settings.loadurl,
|
||||
data : loaddata,
|
||||
async : false,
|
||||
success: function(result) {
|
||||
window.clearTimeout(t);
|
||||
input_content = result;
|
||||
input.disabled = false;
|
||||
}
|
||||
});
|
||||
} else if (settings.data) {
|
||||
input_content = settings.data;
|
||||
if ($.isFunction(settings.data)) {
|
||||
input_content = settings.data.apply(self, [self.revert, settings]);
|
||||
}
|
||||
} else {
|
||||
input_content = self.revert;
|
||||
}
|
||||
content.apply(form, [input_content, settings, self]);
|
||||
|
||||
input.attr('name', settings.name);
|
||||
|
||||
/* add buttons to the form */
|
||||
buttons.apply(form, [settings, self]);
|
||||
|
||||
/* add created form to self */
|
||||
$(self).append(form);
|
||||
|
||||
/* attach 3rd party plugin if requested */
|
||||
plugin.apply(form, [settings, self]);
|
||||
|
||||
/* focus to first visible form element */
|
||||
$(':input:visible:enabled:first', form).focus();
|
||||
|
||||
/* highlight input contents when requested */
|
||||
if (settings.select) {
|
||||
input.select();
|
||||
}
|
||||
|
||||
/* discard changes if pressing esc */
|
||||
input.keydown(function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
e.preventDefault();
|
||||
//self.reset();
|
||||
reset.apply(form, [settings, self]);
|
||||
}
|
||||
});
|
||||
|
||||
/* discard, submit or nothing with changes when clicking outside */
|
||||
/* do nothing is usable when navigating with tab */
|
||||
var t;
|
||||
if ('cancel' == settings.onblur) {
|
||||
input.blur(function(e) {
|
||||
/* prevent canceling if submit was clicked */
|
||||
t = setTimeout(function() {
|
||||
reset.apply(form, [settings, self]);
|
||||
}, 500);
|
||||
});
|
||||
} else if ('submit' == settings.onblur) {
|
||||
input.blur(function(e) {
|
||||
/* prevent double submit if submit was clicked */
|
||||
t = setTimeout(function() {
|
||||
form.submit();
|
||||
}, 200);
|
||||
});
|
||||
} else if ($.isFunction(settings.onblur)) {
|
||||
input.blur(function(e) {
|
||||
settings.onblur.apply(self, [input.val(), settings]);
|
||||
});
|
||||
} else {
|
||||
input.blur(function(e) {
|
||||
/* TODO: maybe something here */
|
||||
});
|
||||
}
|
||||
|
||||
form.submit(function(e) {
|
||||
|
||||
if (t) {
|
||||
clearTimeout(t);
|
||||
}
|
||||
|
||||
/* do no submit */
|
||||
e.preventDefault();
|
||||
|
||||
/* call before submit hook. */
|
||||
/* if it returns false abort submitting */
|
||||
if (false !== onsubmit.apply(form, [settings, self])) {
|
||||
/* custom inputs call before submit hook. */
|
||||
/* if it returns false abort submitting */
|
||||
if (false !== submit.apply(form, [settings, self])) {
|
||||
|
||||
/* check if given target is function */
|
||||
if ($.isFunction(settings.target)) {
|
||||
var str = settings.target.apply(self, [input.val(), settings]);
|
||||
$(self).html(str);
|
||||
self.editing = false;
|
||||
callback.apply(self, [self.innerHTML, settings]);
|
||||
/* TODO: this is not dry */
|
||||
if (!$.trim($(self).html())) {
|
||||
$(self).html(settings.placeholder);
|
||||
}
|
||||
} else {
|
||||
/* add edited content and id of edited element to POST */
|
||||
var submitdata = {};
|
||||
submitdata[settings.name] = input.val();
|
||||
submitdata[settings.id] = self.id;
|
||||
/* add extra data to be POST:ed */
|
||||
if ($.isFunction(settings.submitdata)) {
|
||||
$.extend(submitdata, settings.submitdata.apply(self, [self.revert, settings]));
|
||||
} else {
|
||||
$.extend(submitdata, settings.submitdata);
|
||||
}
|
||||
|
||||
/* quick and dirty PUT support */
|
||||
if ('PUT' == settings.method) {
|
||||
submitdata['_method'] = 'put';
|
||||
}
|
||||
|
||||
/* show the saving indicator */
|
||||
$(self).html(settings.indicator);
|
||||
|
||||
/* defaults for ajaxoptions */
|
||||
var ajaxoptions = {
|
||||
type : 'POST',
|
||||
data : submitdata,
|
||||
dataType: 'html',
|
||||
url : settings.target,
|
||||
success : function(result, status) {
|
||||
if (ajaxoptions.dataType == 'html') {
|
||||
$(self).html(result);
|
||||
}
|
||||
self.editing = false;
|
||||
callback.apply(self, [result, settings]);
|
||||
if (!$.trim($(self).html())) {
|
||||
$(self).html(settings.placeholder);
|
||||
}
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
onerror.apply(form, [settings, self, xhr]);
|
||||
}
|
||||
};
|
||||
|
||||
/* override with what is given in settings.ajaxoptions */
|
||||
$.extend(ajaxoptions, settings.ajaxoptions);
|
||||
$.ajax(ajaxoptions);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* show tooltip again */
|
||||
$(self).attr('title', settings.tooltip);
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
/* privileged methods */
|
||||
this.reset = function(form) {
|
||||
/* prevent calling reset twice when blurring */
|
||||
if (this.editing) {
|
||||
/* before reset hook, if it returns false abort reseting */
|
||||
if (false !== onreset.apply(form, [settings, self])) {
|
||||
$(self).html(self.revert);
|
||||
self.editing = false;
|
||||
if (!$.trim($(self).html())) {
|
||||
$(self).html(settings.placeholder);
|
||||
}
|
||||
/* show tooltip again */
|
||||
if (settings.tooltip) {
|
||||
$(self).attr('title', settings.tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
$.editable = {
|
||||
types: {
|
||||
defaults: {
|
||||
element : function(settings, original) {
|
||||
var input = $('<input type="hidden"></input>');
|
||||
$(this).append(input);
|
||||
return(input);
|
||||
},
|
||||
content : function(string, settings, original) {
|
||||
$(':input:first', this).val(string);
|
||||
},
|
||||
reset : function(settings, original) {
|
||||
original.reset(this);
|
||||
},
|
||||
buttons : function(settings, original) {
|
||||
var form = this;
|
||||
if (settings.submit) {
|
||||
/* if given html string use that */
|
||||
if (settings.submit.match(/>$/)) {
|
||||
var submit = $(settings.submit).click(function() {
|
||||
if (submit.attr("type") != "submit") {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
/* otherwise use button with given string as text */
|
||||
} else {
|
||||
var submit = $('<button type="submit" />');
|
||||
submit.html(settings.submit);
|
||||
}
|
||||
$(this).append(submit);
|
||||
}
|
||||
if (settings.cancel) {
|
||||
/* if given html string use that */
|
||||
if (settings.cancel.match(/>$/)) {
|
||||
var cancel = $(settings.cancel);
|
||||
/* otherwise use button with given string as text */
|
||||
} else {
|
||||
var cancel = $('<button type="cancel" />');
|
||||
cancel.html(settings.cancel);
|
||||
}
|
||||
$(this).append(cancel);
|
||||
|
||||
$(cancel).click(function(event) {
|
||||
//original.reset();
|
||||
if ($.isFunction($.editable.types[settings.type].reset)) {
|
||||
var reset = $.editable.types[settings.type].reset;
|
||||
} else {
|
||||
var reset = $.editable.types['defaults'].reset;
|
||||
}
|
||||
reset.apply(form, [settings, original]);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
text: {
|
||||
element : function(settings, original) {
|
||||
var input = $('<input />');
|
||||
if (settings.width != 'none') { input.width(settings.width); }
|
||||
if (settings.height != 'none') { input.height(settings.height); }
|
||||
/* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
|
||||
//input[0].setAttribute('autocomplete','off');
|
||||
input.attr('autocomplete','off');
|
||||
$(this).append(input);
|
||||
return(input);
|
||||
}
|
||||
},
|
||||
textarea: {
|
||||
element : function(settings, original) {
|
||||
var textarea = $('<textarea />');
|
||||
if (settings.rows) {
|
||||
textarea.attr('rows', settings.rows);
|
||||
} else if (settings.height != "none") {
|
||||
textarea.height(settings.height);
|
||||
}
|
||||
if (settings.cols) {
|
||||
textarea.attr('cols', settings.cols);
|
||||
} else if (settings.width != "none") {
|
||||
textarea.width(settings.width);
|
||||
}
|
||||
$(this).append(textarea);
|
||||
return(textarea);
|
||||
}
|
||||
},
|
||||
select: {
|
||||
element : function(settings, original) {
|
||||
var select = $('<select />');
|
||||
$(this).append(select);
|
||||
return(select);
|
||||
},
|
||||
content : function(data, settings, original) {
|
||||
/* If it is string assume it is json. */
|
||||
if (String == data.constructor) {
|
||||
eval ('var json = ' + data);
|
||||
} else {
|
||||
/* Otherwise assume it is a hash already. */
|
||||
var json = data;
|
||||
}
|
||||
for (var key in json) {
|
||||
if (!json.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
if ('selected' == key) {
|
||||
continue;
|
||||
}
|
||||
var option = $('<option />').val(key).append(json[key]);
|
||||
$('select', this).append(option);
|
||||
}
|
||||
/* Loop option again to set selected. IE needed this... */
|
||||
$('select', this).children().each(function() {
|
||||
if ($(this).val() == json['selected'] ||
|
||||
$(this).text() == $.trim(original.revert)) {
|
||||
$(this).attr('selected', 'selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Add new input type */
|
||||
addInputType: function(name, input) {
|
||||
$.editable.types[name] = input;
|
||||
}
|
||||
};
|
||||
|
||||
// publicly accessible defaults
|
||||
$.fn.editable.defaults = {
|
||||
name : 'value',
|
||||
id : 'id',
|
||||
type : 'text',
|
||||
width : 'auto',
|
||||
height : 'auto',
|
||||
event : 'click.editable',
|
||||
onblur : 'cancel',
|
||||
loadtype : 'GET',
|
||||
loadtext : 'Loading...',
|
||||
placeholder: 'Click to edit',
|
||||
loaddata : {},
|
||||
submitdata : {},
|
||||
ajaxoptions: {}
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
38
src/main/webapp/assets/jeditable/jquery.jeditable.mini.js
Normal file
38
src/main/webapp/assets/jeditable/jquery.jeditable.mini.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
(function($){$.fn.editable=function(target,options){if('disable'==target){$(this).data('disabled.editable',true);return;}
|
||||
if('enable'==target){$(this).data('disabled.editable',false);return;}
|
||||
if('destroy'==target){$(this).unbind($(this).data('event.editable')).removeData('disabled.editable').removeData('event.editable');return;}
|
||||
var settings=$.extend({},$.fn.editable.defaults,{target:target},options);var plugin=$.editable.types[settings.type].plugin||function(){};var submit=$.editable.types[settings.type].submit||function(){};var buttons=$.editable.types[settings.type].buttons||$.editable.types['defaults'].buttons;var content=$.editable.types[settings.type].content||$.editable.types['defaults'].content;var element=$.editable.types[settings.type].element||$.editable.types['defaults'].element;var reset=$.editable.types[settings.type].reset||$.editable.types['defaults'].reset;var callback=settings.callback||function(){};var onedit=settings.onedit||function(){};var onsubmit=settings.onsubmit||function(){};var onreset=settings.onreset||function(){};var onerror=settings.onerror||reset;if(settings.tooltip){$(this).attr('title',settings.tooltip);}
|
||||
settings.autowidth='auto'==settings.width;settings.autoheight='auto'==settings.height;return this.each(function(){var self=this;var savedwidth=$(self).width();var savedheight=$(self).height();$(this).data('event.editable',settings.event);if(!$.trim($(this).html())){$(this).html(settings.placeholder);}
|
||||
$(this).bind(settings.event,function(e){if(true===$(this).data('disabled.editable')){return;}
|
||||
if(self.editing){return;}
|
||||
if(false===onedit.apply(this,[settings,self])){return;}
|
||||
e.preventDefault();e.stopPropagation();if(settings.tooltip){$(self).removeAttr('title');}
|
||||
if(0==$(self).width()){settings.width=savedwidth;settings.height=savedheight;}else{if(settings.width!='none'){settings.width=settings.autowidth?$(self).width():settings.width;}
|
||||
if(settings.height!='none'){settings.height=settings.autoheight?$(self).height():settings.height;}}
|
||||
if($(this).html().toLowerCase().replace(/(;|")/g,'')==settings.placeholder.toLowerCase().replace(/(;|")/g,'')){$(this).html('');}
|
||||
self.editing=true;self.revert=$(self).html();$(self).html('');var form=$('<form />');if(settings.cssclass){if('inherit'==settings.cssclass){form.attr('class',$(self).attr('class'));}else{form.attr('class',settings.cssclass);}}
|
||||
if(settings.style){if('inherit'==settings.style){form.attr('style',$(self).attr('style'));form.css('display',$(self).css('display'));}else{form.attr('style',settings.style);}}
|
||||
var input=element.apply(form,[settings,self]);var input_content;if(settings.loadurl){var t=setTimeout(function(){input.disabled=true;content.apply(form,[settings.loadtext,settings,self]);},100);var loaddata={};loaddata[settings.id]=self.id;if($.isFunction(settings.loaddata)){$.extend(loaddata,settings.loaddata.apply(self,[self.revert,settings]));}else{$.extend(loaddata,settings.loaddata);}
|
||||
$.ajax({type:settings.loadtype,url:settings.loadurl,data:loaddata,async:false,success:function(result){window.clearTimeout(t);input_content=result;input.disabled=false;}});}else if(settings.data){input_content=settings.data;if($.isFunction(settings.data)){input_content=settings.data.apply(self,[self.revert,settings]);}}else{input_content=self.revert;}
|
||||
content.apply(form,[input_content,settings,self]);input.attr('name',settings.name);buttons.apply(form,[settings,self]);$(self).append(form);plugin.apply(form,[settings,self]);$(':input:visible:enabled:first',form).focus();if(settings.select){input.select();}
|
||||
input.keydown(function(e){if(e.keyCode==27){e.preventDefault();reset.apply(form,[settings,self]);}});var t;if('cancel'==settings.onblur){input.blur(function(e){t=setTimeout(function(){reset.apply(form,[settings,self]);},500);});}else if('submit'==settings.onblur){input.blur(function(e){t=setTimeout(function(){form.submit();},200);});}else if($.isFunction(settings.onblur)){input.blur(function(e){settings.onblur.apply(self,[input.val(),settings]);});}else{input.blur(function(e){});}
|
||||
form.submit(function(e){if(t){clearTimeout(t);}
|
||||
e.preventDefault();if(false!==onsubmit.apply(form,[settings,self])){if(false!==submit.apply(form,[settings,self])){if($.isFunction(settings.target)){var str=settings.target.apply(self,[input.val(),settings]);$(self).html(str);self.editing=false;callback.apply(self,[self.innerHTML,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}}else{var submitdata={};submitdata[settings.name]=input.val();submitdata[settings.id]=self.id;if($.isFunction(settings.submitdata)){$.extend(submitdata,settings.submitdata.apply(self,[self.revert,settings]));}else{$.extend(submitdata,settings.submitdata);}
|
||||
if('PUT'==settings.method){submitdata['_method']='put';}
|
||||
$(self).html(settings.indicator);var ajaxoptions={type:'POST',data:submitdata,dataType:'html',url:settings.target,success:function(result,status){if(ajaxoptions.dataType=='html'){$(self).html(result);}
|
||||
self.editing=false;callback.apply(self,[result,settings]);if(!$.trim($(self).html())){$(self).html(settings.placeholder);}},error:function(xhr,status,error){onerror.apply(form,[settings,self,xhr]);}};$.extend(ajaxoptions,settings.ajaxoptions);$.ajax(ajaxoptions);}}}
|
||||
$(self).attr('title',settings.tooltip);return false;});});this.reset=function(form){if(this.editing){if(false!==onreset.apply(form,[settings,self])){$(self).html(self.revert);self.editing=false;if(!$.trim($(self).html())){$(self).html(settings.placeholder);}
|
||||
if(settings.tooltip){$(self).attr('title',settings.tooltip);}}}};});};$.editable={types:{defaults:{element:function(settings,original){var input=$('<input type="hidden"></input>');$(this).append(input);return(input);},content:function(string,settings,original){$(':input:first',this).val(string);},reset:function(settings,original){original.reset(this);},buttons:function(settings,original){var form=this;if(settings.submit){if(settings.submit.match(/>$/)){var submit=$(settings.submit).click(function(){if(submit.attr("type")!="submit"){form.submit();}});}else{var submit=$('<button type="submit" />');submit.html(settings.submit);}
|
||||
$(this).append(submit);}
|
||||
if(settings.cancel){if(settings.cancel.match(/>$/)){var cancel=$(settings.cancel);}else{var cancel=$('<button type="cancel" />');cancel.html(settings.cancel);}
|
||||
$(this).append(cancel);$(cancel).click(function(event){if($.isFunction($.editable.types[settings.type].reset)){var reset=$.editable.types[settings.type].reset;}else{var reset=$.editable.types['defaults'].reset;}
|
||||
reset.apply(form,[settings,original]);return false;});}}},text:{element:function(settings,original){var input=$('<input />');if(settings.width!='none'){input.width(settings.width);}
|
||||
if(settings.height!='none'){input.height(settings.height);}
|
||||
input.attr('autocomplete','off');$(this).append(input);return(input);}},textarea:{element:function(settings,original){var textarea=$('<textarea />');if(settings.rows){textarea.attr('rows',settings.rows);}else if(settings.height!="none"){textarea.height(settings.height);}
|
||||
if(settings.cols){textarea.attr('cols',settings.cols);}else if(settings.width!="none"){textarea.width(settings.width);}
|
||||
$(this).append(textarea);return(textarea);}},select:{element:function(settings,original){var select=$('<select />');$(this).append(select);return(select);},content:function(data,settings,original){if(String==data.constructor){eval('var json = '+data);}else{var json=data;}
|
||||
for(var key in json){if(!json.hasOwnProperty(key)){continue;}
|
||||
if('selected'==key){continue;}
|
||||
var option=$('<option />').val(key).append(json[key]);$('select',this).append(option);}
|
||||
$('select',this).children().each(function(){if($(this).val()==json['selected']||$(this).text()==$.trim(original.revert)){$(this).attr('selected','selected');}});}}},addInputType:function(name,input){$.editable.types[name]=input;}};$.fn.editable.defaults={name:'value',id:'id',type:'text',width:'auto',height:'auto',event:'click.editable',onblur:'cancel',loadtype:'GET',loadtext:'Loading...',placeholder:'Click to edit',loaddata:{},submitdata:{},ajaxoptions:{}};})(jQuery);
|
||||
Loading…
Add table
Reference in a new issue