Test jQuery: jeditable is best

This commit is contained in:
Regis Houssin 2010-10-20 06:50:45 +00:00
parent 63b3cf65ec
commit 46eacb1b1a
7 changed files with 0 additions and 1372 deletions

View File

@ -1,479 +0,0 @@
2010-05-23 Martin Haecker <spamfaenger@gmx.de>
split out the callback tests from main test file
2010-05-23 Martin Haecker <spamfaenger@gmx.de>
figured out how to have two more tests be in the generic suite
2010-05-23 Martin Haecker <spamfaenger@gmx.de>
started splitting the testsuite into multiple files and also started breaking down the tests for the different editor types into their own describe blocks that share behaviour with more generic blocks
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
starte splitting test suite into multiple files for more clarity. First stage involves pushing out setup into 'shared setup' and referencing that with should_behave_like in each testsuite. Works fine so far. :)
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
more todos
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
started experimenting with jquery 1.4 - it all seems to work quite fine, apart from a few testsuite fixes because hasClass has become stricter in jquery 1.4
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
applied patch from superami to allow the callback to handle the dom reset itself. Thanks again!
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
documented that input sizing via css is preferred
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
applied patch from superami to add input size support
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
more thoughts on the future...
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
better documentation
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
no longer accidentally committing in textareas when entering a newline
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
deprecated preinit and postclose callbacks as better alternatives are now implemented
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
added missing semicolons
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
added some documentation on the callbacks
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
changed openEditor to return the :input field directly to shorten testcode
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
added should- will- and did- open / close callbacks to the inplace editor
2010-05-22 Martin Haecker <spamfaenger@gmx.de>
what I'm up to changes...
2010-05-20 Martin Haecker <spamfaenger@gmx.de>
renamed back to release notes, thats what they really are
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
renamed release notes to backwards compatibility notes as I won't be writing real release notes for now
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
switched default behaviour of editor to use .text() to extract values from dom. Use use_html:true to switch this behaviour
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
should really use JSpect context to bring in my helpers
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
updated version for next release
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
changed deprecation marker to denote the version something was deprecated for easier removal and extended it to the documentation too
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
worked on todos and on designing the callback interface
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
updated changelog before release
2010-05-14 Martin Haecker <spamfaenger@gmx.de>
markdowned the documentation and moved more of it out of the source file so the source code is shorter and it is clearer where to find what information
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
added some documentation and moved a test to a more logical location
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
updated changelog before release
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
simplified test suite by introducing edit openEditor and enableEditor helpers that set some default default settings
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
reworked all callbacks to receive the editor dom node as their this argument
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
moved documentation into RELEASE NOTES and TODO files
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
updated changelog before release
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
the editor will now throw if you provide neither a callback or a url parameter to it. This lead to quite some fallout in the testsuite as it still enabled lots of editors with neither option...
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
updated to jspec 4.3.1
2010-05-13 Martin Haecker <spamfaenger@gmx.de>
updated documentation to be easier to grasp and more in line to what the documentation of the homepage has been
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
updated version to something more sane for the next release
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
more documentation fixes and some generall small cleanup
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
small enhancements to documentation but mostly removed and reordered TODOs and REFACTs
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
improved documentation with an overview of how the inline editor works
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
fixed missing var statements
2010-05-11 Martin Haecker <spamfaenger@gmx.de>
applied patch from robert that adds a cancel option like in jquery-ui to not open the editor when the click event happened on a cancel event
2010-05-10 Martin Haecker <spamfaenger@gmx.de>
added missing documentation
2010-05-10 Martin Haecker <spamfaenger@gmx.de>
enhanced callback protocol, added postclose and now checking the returnvalue of preinit. If it returns false, the editor is not opened
2010-05-07 Martin Haecker <spamfaenger@gmx.de>
fixed postclose callback to always be called after the editor has restored the new value either from the server or from the callback
2010-05-07 Martin Haecker <spamfaenger@gmx.de>
added postclose callback to do cleanup work after the editor has closed
2010-05-07 Martin Haecker <spamfaenger@gmx.de>
added preinit callback to the options
2010-05-06 Martin Haecker <spamfaenger@gmx.de>
added test and fix that return commits in all browsers
2010-05-04 Martin Haecker <spamfaenger@gmx.de>
removed stray debugger statement
2010-04-27 Martin Haecker <spamfaenger@gmx.de>
fixed test in firefox (background-color was not returned as part of background and transparent was used as the default background color for p elements (instead of inherit as we expected)) and added another fix for firefox to send blur events to other open editors.
2010-04-22 Martin Haecker <spamfaenger@gmx.de>
added documentation on how to use the callback interface for the callback submit
2010-04-22 Martin Haecker <spamfaenger@gmx.de>
added tests to verify that the animation color can be specified by a parameter
2010-04-22 Martin Haecker <spamfaenger@gmx.de>
added jquery ui
2010-04-22 Martin Haecker <spamfaenger@gmx.de>
added saving animation support
2010-04-22 Martin Haecker <spamfaenger@gmx.de>
fixed failuresOnly by not overwriting this.options in the tests and some small cleanups
2010-04-21 Martin Haecker <spamfaenger@gmx.de>
added a callback interface to submit to callback that allows the editor to know when the callback is done saving it's values
2010-04-21 Martin Haecker <spamfaenger@gmx.de>
added field type to tests that where applied to text, textarea and select fields
2010-04-21 Martin Haecker <spamfaenger@gmx.de>
added todos
2010-04-21 Martin Haecker <spamfaenger@gmx.de>
updated to 4.2.1 of jspec
2010-03-28 Martin Haecker <spamfaenger@gmx.de>
updated jspec to 4.1.0
2010-03-28 Martin Haecker <spamfaenger@gmx.de>
added testcase to ensure all commits include the params optional parameter
2010-03-25 mhaecker
setting correct mime types for the demo files
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
updated changelog before release
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
removed todos from release script
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
updated release script to say what it does and tagg and push the release
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
added changelog updating to the release script
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
ignoring script file that stores my username and password, so I don't accidentally commit it. :)
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
added scripts to automate releasing to google code
2010-03-23 Martin Haecker <spamfaenger@gmx.de>
ignoring build directory
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
fixed select support to not submit the default choice accidentally
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
experimental changes to get rhino to work (still a total failure though)
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
reworked demo to go all through the callback function so no server side functionality is required for the demo
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
bugfix for testfailure resulting from jspec 3.3.3's strictire matching comparison
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
updated jspec to 3.3.3
2010-03-22 Martin Haecker <spamfaenger@gmx.de>
tried to activate failures only mode
2010-03-18 Martin Haecker <spamfaenger@gmx.de>
cleanup and comments
2010-03-05 Martin Haecker <spamfaenger@gmx.de>
fixed bug where changing the text of an inline editor that put its own default text in the editor after it was created would lead to it loosing that value on click
2010-03-05 Martin Haecker <spamfaenger@gmx.de>
new version of env.js
2010-03-01 Martin Haecker <spamfaenger@gmx.de>
setting background color directly and not via the background property
2010-03-01 Martin Haecker <spamfaenger@gmx.de>
do not overwrite background-color if it hover_class is specified
2010-02-19 Martin Haecker <spamfaenger@gmx.de>
trying failuresOnly option but it doesn't seem to work. :/
2010-02-19 Martin Haecker <spamfaenger@gmx.de>
updated jspec version
2010-02-19 Martin Haecker <spamfaenger@gmx.de>
removed callbackShowErrors option as there is now an error sink that can be used to disable all errors if required
2010-02-19 Martin Haecker <spamfaenger@gmx.de>
changed refact comments
2010-02-18 Martin Haecker <spamfaenger@gmx.de>
added error_sink option to get all error messages via a callback out of the editor
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
removed leftover bug comment
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
allow 0 or empty string as valid return values from submit callback
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
do not commit if nothing was changed in the editor
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
changes to not commit if nothing was changed in the editor - even if commit was pressed
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
escape submitted text so that special charactes like &/=<> do not make problems
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
removed stray debugger statements
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
added changelog entry and added information about patches
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
added changelog entry and added information about patches
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
removed unneeded demo files
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
new feature: allow css class for hover instead of immediate values
2010-02-14 Martin Haecker <mhaecker@cs.tu-berlin.de>
updated testrunners to allow mocking of ajax requests
2010-02-13 Martin Haecker <mhaecker@cs.tu-berlin.de>
preventing multiple editors on the same element and changed the way the editor is preventing opening it twice to not use an instance variable
2010-02-13 Martin Haecker <mhaecker@cs.tu-berlin.de>
finished objectifying the editor and the first round of method breakdown into relatively manageable bits
2010-02-13 Martin Haecker <mhaecker@cs.tu-berlin.de>
more preparation for breakdown into smaller functions + small reorganizaton of testsuite to make it shorter and sweeter
2010-02-13 Martin Haecker <mhaecker@cs.tu-berlin.de>
expanded checks and documentation for select element to allow extra speces and real arrays for select option definitions
2010-02-13 Martin Haecker <mhaecker@cs.tu-berlin.de>
more cleanup and small bugfixes to how selects are generated
2010-02-11 Martin Haecker <mhaecker@cs.tu-berlin.de>
slowly moving the methods into the InlineEditor object and breaking them down into smaller ones. Plus fix to the escaping of stuff in the inline editor
2010-02-11 Martin Haecker <mhaecker@cs.tu-berlin.de>
even more breaking down into functions for prettier code
2010-02-11 Martin Haecker <mhaecker@cs.tu-berlin.de>
running the demo from the latest source
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
wrapped in (function($){})(jQuery) for more compatibility and removed the String prototype changes
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
reworked intro comment to contain refact and todo sections
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
merged documentation and custom settings declaration to get rid of duplication
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
first batch of testcases for the inline editor
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
added some todos
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
updated testrunners to run jquery.editinplace.js (rhino doesn't work yet as the latest release of env.js fails to load propperly
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
added support libraries for rhino and jquery
2010-02-07 Martin Haecker <mhaecker@cs.tu-berlin.de>
removed leftover from template - tests are now written for jquery.editinplace.js
2010-02-06 Martin Haecker <mhaecker@cs.tu-berlin.de>
moved edit in place into lib folder
2010-02-06 Martin Haecker <mhaecker@cs.tu-berlin.de>
added local jspec instance
2009-06-09 DaveHauenstein
added a new parameter
2009-04-09 davehauenstein
- Minor Updates
- Script: Changed default save and cancel input fields to button elements
- Demo: Minor text changes and added link to demo.js file
- Demo: Added local version of jQuery lib instead of linking to google's
2009-04-06 davehauenstein
updated link in demo
2009-04-06 davehauenstein
initial import
2009-04-06
Initial directory structure.

View File

@ -1,8 +0,0 @@
Hacking
=======
To run the teststuite just open [the testrunner](spec/dom.html) in your browser of choice. (I found Webkit Nightlies to be most pleasant to debug in). For more comfort install jspec via `gem install jspec` then you can run `jspec bind --browser <yourprobwser>` in the root directory of the project to re-execute the testsuite whenever you save changes to a file.
If you don't see any tests when executing the testsuite, don't worry, it is set up to only show failing tests.
If you see an enhancement or happen to need one of the things mentioned in the [TODO](TODO) file, please don't hesitate to implement them with a testsuite to boost and send me a patch.

View File

@ -1,31 +0,0 @@
Software License Agreement (BSD License)
Copyright (c) 2009, Dave Hauenstein <davehauenstein@gmail.com>
All rights reserved.
Redistribution and use of this software in source and binary forms, with or
without modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Dave Hauenstein, nor the names of any contributors may be
used to endorse or promote products derived from this software without
specific prior written permission of the contributor.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,58 +0,0 @@
INTRODUCTION
------------
editInPlace is a jQuery plugin that turns any element or group of elements
into an Ajax in-place editor using only one line of code. Its written using the jQuery
library, which is freely available at http://jquery.com.
SUPPORT AND BUG REPORTS
-----------------------
Bug reports, as well as feature requests, may be submitted [on the google code page](http://code.google.com/p/jquery-in-place-editor/issues/list)
QUICK START
-----------
Include jquery and the editin place scripts in your html page (preferably at the bottom so the page loads faster).
<script type="text/javascript" src="path/to/js/jquery.js"></script>
<script type="text/javascript" src="path/to/js/jquery.editinplace.js"></script>
<script type="text/javascript">
$(".inplace-editor").editInPlace({
url: "path/to/server/script.php"
});
</script>
Create a div with the class 'inplace-editor'
<div class="inplace-editor"></div>
Create a server side handler script (php, python, etc...), this example will use php
The following parameters will be sent via a POST requeset to the server script
* update_value
* element_id
* original_html
e.g. in script.php:
$_POST['update_value']
$_POST['element_id']
$_POST['original_html']
Alternatively you can set the option callback, so you can controll the whole saving process yourself (update other parts of the webpage and possibly not even save to the server at all). The editor accepts a wealth of other options to customize how it behaves. They are documented inline [in the sourcecode](lib/jquery.editInPlace.js) and are exposed as $.fn.editInPlace.defaults where you can change them globally for your app. For more examples of how to use the editor, have [a look at the demo html](demo/index.html) and [javascript](demo/js/demo.js).
DOCUMENTATION
-------------
The Editor works in two stages. After initialization it is closed, wich means that it listens to a click on the element it was bound to. When clicked it will open, which means it replaces the content of the bound field with the configured GUI (input, textarea or select), preinitialized to show the value that was shown in that DOM element before. If the user then cancels or doesn't change anything, everything is returned to what it was before. If the user makes a change and commits, that new value is either submitted to the configured URL or to the configured callback and then the editor GUI is again replaced by just the edited value and the editor again listenes to a click.
To support automated acceptance tests better the editor will set the class .editInPlace-active as soon as it opens, and will only remove it when it has finished any interaction with the server or the callback interface has told it so.
More documenataion can be found on [the google code page of this product](http://code.google.com/p/jquery-in-place-editor/)
Thats it! Have fun using it!

View File

@ -1,12 +0,0 @@
Backwards compatibility breaks in 2.3.0:
- Default saving text is changed to the just edited value
Backwards compatibility breaks in 2.2.0:
- Now using .text() to get the value of the inline editor by default, you can set extract_with_html:true to override this.
- submit to callback with hand over originalValue as third argument instead of originalHTML
- submit to server now uses originalValue on the original_html value
Backwards compatibility breaks in 2.1.0:
- All callbacks now recieve the DOM-Node of the editor set as their this context

View File

@ -1,140 +0,0 @@
TODO
====
- do not change editor content on cancel if callback doesn't return anything
- saving animation doesn't work when jquery-ui isn't present. Find workaround or have other default saving animation
- Consider to deprecate the ajax callbacks in favor of the delegate interface.
- consider to remove / deprecate the textarea sizing support, css is a much better interface to this
- Find a workable solution to the textareay enters are not preserved problem. Many people have stumbled about it, either document solutions to it or create a default behaviour that works nicely.
- consolidate documentation for options and callbacks
- Rename settings so they make more sense (e.g. saving_image -> saving_image_url) but keep backwards compatible to old settings
also make all settings consistent in their underscore usage (i.e. don't use any. :)
params -> extra_submit_parameters / context_parametes
- consider to accept string parameters like jquery UI for 'disable', 'enable', 'remove' etc.
- Rework parameters of success and error server callback
- Change deprecation notes to state the version the deprecation was put in, not when it will be removed.
- rename RELEASE NOTES to BACKWARDS COMPATIBILITY NOTES or BACKWARDS INCOMPATIBLE CHANGES or BACKWARDS COMPATIBILITY CHANGES as I don't see myself as writing release notes anytime soon
- Allow the user to chose if html source should be edited or text (default to text). Probably needs a way
for the user to decide how the result should be embedded (think about editing wiki-text and inserting rendered html)
- Update to jQuery 1.4.x, aparently something breaks
- expand the interface to submit to functions to make it easier to integrate into custom applications
(fold in show progress, offer callbacks for different lifecycle events, ...)
- consider to pass the original dom element instead of it's id in the callback function. (However $('#' + original_id) also accomplishes this)
- support live events to trigger inline editing to ease highly dynamic websites better
- when using live events, the editor can't guarantee the order of ediors if multiple editors register for the same element.
- could add debug mode to raise / show error if this is detected on click (multiple editors where bound, mixture of live / immediate events)
- select on choosing if no buttons are shown (should be able to disable this if wanted)
- Allow the editor to show up on hoverig above it (make sure to do it in a way that doesn't crash IE 7)
- More animations during submit: show spinner
- Unify usage of text and html to take and deliver content to the inline editor and enable the user to choose with a setting (document carefully as that will change the default behaviour)
Solve by callback interface that can transform the code if needed.
- Allow continous validation / transformation while the user types. I.e. wiki-edit with live preview (from server / function)
- add validation callback to be asked before any submitting (this could also be called continuous while editing
(for each character?) maybe a dedicated callback for each would be valuable)
- allow aditional_params to be set as json/object that is then serialized with correct encoding on submit
- consider size parameter for the inline edit box (but this can already nicely accomplished through css)
- Replace argument list of saving callback with dictionary
- Option to always restore the original content, could help for editors that you would always want to render empty, i.e. they display their results somewhere else
- Change all callbacks to get the editor dom node as the first argument, so the editor object itself is never exposed
- Consider to expose the options argument as a second argument to all callbacks
- Consider adding $(..).editInPlace().destroy() or something similar to completely remove the editor
- Support overriding individual options with the metadata plugin
- Option to load URL for editor content
- Group options sensibly and have section headers for them.
- Move documentation out of edit in place into the README and update that
- deprecate callback arguments that are no longer usefull / needed. For example:
- The first argument of the 'callback' option was removed. Use $(this).attr('id') instead if you need it.
- success and error callbacks got the editor DOM element as the second argument. Use $(this) instead.
- Consider editor types as subclasses so different inline editors can be built more easily.
- Could also break out functional classes, callback handling, lifecycle events / delegate behaviour
- Consider every optional callback as optional delegete call?
- dependencies of editors, i.e. typing in one will update another aka bindings?
- Could also be live updating of delegate / calling of callbacks
- consider to trigger all the callbacks as events?
- could be an alternative, might be more idiomatic event driven dom programming
- include spinner image as data url into javascript (add code that writes this as mime thingy for IE)
- consider to enable the client to specify a prefix / namespace for all css-classes in the inplace editor to make it easier to avoid clashes with outside css
Expansions to jspec
-------------------
- add jspec with focus support
- change the way the grammar works to have less magic and more plain javascript (i.e. use 'with' statement less, support real throwaway this objects for the tests)
REFACT
------
- Find a way to share enableEditor, openEditor and edit between different testsuites
- Extract parts of the testsuite to be run with should_behave_like
- Split testsuite into different files, at least one per editor type that should just inlcude generic tests with should_behave_like
Thoughts about a detailed callback
----------------------------------
Could also use callbacks to interact with child-classes, i.e. do the actual work. That could be a really nice interface for child-classes, not sure if it works for everything though, so deeper subclassing may be neccessary
// these would come just before shouldOpen when using live events
shouldInit:
willInit:
init:
didInit:
shouldHover:
willHover:
hover:
didHover:
shouldUnhover:
willUnhover:
unHover:
didUnhover:
// prio 1
// maybe combine should and will callbacks?
shouldOpen:
willOpen: // could be usefull to customize settings? // transform content here
open:
didOpen:
// for open editor?
// user enters stuff, keypress / changed selection on select
// how to deal with validation?
shouldChangeContent: // should this be accepted
willChangeContent: // transform?
changeContent:
didChangeContent: // do something with the new information
shouldSubmitContent: // first callback after submit was called - does it make sense to call something like this if validation didn't work?
shouldEnableSubmit: // didChangeContent
willSubmitContent: // maybe transform what goes to the server
submit:
didSubmitContent:
// seems not enough, doesn't handle select fields
// for closed editor? would be really nice to unify with open editor
// could be a generic interface to update the displayed values
// what about when the editor is open? what interface to use then?
shouldUpdateContent: // get notification to update the content, either the view, wrong direction..., something should call this¿
willUpdateContent: // could be callback after we get something from the server (also didUpdateContent)
updateContent: // could use this to decide between html() and text(), could call changeContent
didUpdateContent:
// maybe
shouldSendToServer:
willSendToServer:
sendToServer
didSendToServer:
progressFromServer: // probably impossible
// prio 1
shouldClose: // willChangeContent / didChangeContent ?
willClose: // transform content, could be willSubmitContent
close:
didClose: // could return false to prevent reinit - not very clear though
// this should also work when the editor submits the data to the server itself
// need callback to compute the data that is sent to the server (e.g. to provide arbitrary json)
// need ability to specify http verb to use (PUT, POST, DELETE, etc.)
shouldReinit: // could be able to customize reinit behaviour?, maybe better shouldOpen? didClose could also remove editor
Consider to all suffix them with .editInPlace?

View File

@ -1,644 +0,0 @@
/*
A jQuery edit in place plugin
Version 2.2.0
Authors:
Dave Hauenstein
Martin Häcker <spamfaenger [at] gmx [dot] de>
Project home:
http://code.google.com/p/jquery-in-place-editor/
Patches with tests welcomed! For guidance see the tests at </spec/unit/spec.js>. To submit, attach them to the bug tracker.
License:
This source file is subject to the BSD license bundled with this package.
Available online: {@link http://www.opensource.org/licenses/bsd-license.php}
If you did not receive a copy of the license, and are unable to obtain it,
learn to use a search engine.
*/
(function($){
$.fn.editInPlace = function(options) {
var settings = $.extend({}, $.fn.editInPlace.defaults, options);
assertMandatorySettingsArePresent(settings);
preloadImage(settings.saving_image);
return this.each(function() {
var dom = $(this);
// This won't work with live queries as there is no specific element to attach this
// one way to deal with this could be to store a reference to self and then compare that in click?
if (dom.data('editInPlace'))
return; // already an editor here
dom.data('editInPlace', true);
new InlineEditor(settings, dom).init();
});
};
/// Switch these through the dictionary argument to $(aSelector).editInPlace(overideOptions)
/// Required Options: Either url or callback, so the editor knows what to do with the edited values.
$.fn.editInPlace.defaults = {
url: "", // string: POST URL to send edited content
bg_over: "#ffc", // string: background color of hover of unactivated editor
bg_out: "transparent", // string: background color on restore from hover
hover_class: "", // string: class added to root element during hover. Will override bg_over and bg_out
show_buttons: false, // boolean: will show the buttons: cancel or save; will automatically cancel out the onBlur functionality
save_button: '<button class="inplace_save">Save</button>', // string: image button tag to use as “Save” button
cancel_button: '<button class="inplace_cancel">Cancel</button>', // string: image button tag to use as “Cancel” button
params: "", // string: example: first_name=dave&last_name=hauenstein extra paramters sent via the post request to the server
field_type: "text", // string: "text", "textarea", or "select"; The type of form field that will appear on instantiation
default_text: "(Click here to add text)", // string: text to show up if the element that has this functionality is empty
use_html: false, // boolean, set to true if the editor should use jQuery.fn.html() to extract the value to show from the dom node
textarea_rows: 10, // integer: set rows attribute of textarea, if field_type is set to textarea. Use CSS if possible though
textarea_cols: 25, // integer: set cols attribute of textarea, if field_type is set to textarea. Use CSS if possible though
select_text: "Choose new value", // string: default text to show up in select box
select_options: "", // string or array: Used if field_type is set to 'select'. Can be comma delimited list of options 'textandValue,text:value', Array of options ['textAndValue', 'text:value'] or array of arrays ['textAndValue', ['text', 'value']]. The last form is especially usefull if your labels or values contain colons)
text_size: null, // integer: set cols attribute of text input, if field_type is set to text. Use CSS if possible though
// Specifying callback_skip_dom_reset will disable all saving_* options
saving_text: undefined, // string: text to be used when server is saving information. Example "Saving..."
saving_image: "", // string: uses saving text specify an image location instead of text while server is saving
saving_animation_color: 'transparent', // hex color string, will be the color the pulsing animation during the save pulses to. Note: Only works if jquery-ui is loaded
value_required: false, // boolean: if set to true, the element will not be saved unless a value is entered
element_id: "element_id", // string: name of parameter holding the id or the editable
update_value: "update_value", // string: name of parameter holding the updated/edited value
original_value: 'original_value', // string: name of parameter holding the updated/edited value
original_html: "original_html", // string: name of parameter holding original_html value of the editable /* DEPRECATED in 2.2.0 */ use original_value instead.
save_if_nothing_changed: false, // boolean: submit to function or server even if the user did not change anything
on_blur: "save", // string: "save" or null; what to do on blur; will be overridden if show_buttons is true
cancel: "", // string: if not empty, a jquery selector for elements that will not cause the editor to open even though they are clicked. E.g. if you have extra buttons inside editable fields
// All callbacks will have this set to the DOM node of the editor that triggered the callback
callback: null, // function: function to be called when editing is complete; cancels ajax submission to the url param. Prototype: function(idOfEditor, enteredText, orinalHTMLContent, settingsParams, callbacks). The function needs to return the value that should be shown in the dom. Returning undefined means cancel and will restore the dom and trigger an error. callbacks is a dictionary with two functions didStartSaving and didEndSaving() that you can use to tell the inline editor that it should start and stop any saving animations it has configured. /* DEPRECATED in 2.1.0 */ Parameter idOfEditor, use $(this).attr('id') instead
callback_skip_dom_reset: false, // boolean: set this to true if the callback should handle replacing the editor with the new value to show
success: null, // function: this function gets called if server responds with a success. Prototype: function(newEditorContentString)
error: null, // function: this function gets called if server responds with an error. Prototype: function(request)
error_sink: function(idOfEditor, errorString) { alert(errorString); }, // function: gets id of the editor and the error. Make sure the editor has an id, or it will just be undefined. If set to null, no error will be reported. /* DEPRECATED in 2.1.0 */ Parameter idOfEditor, use $(this).attr('id') instead
preinit: null, // function: this function gets called after a click on an editable element but before the editor opens. If you return false, the inline editor will not open. Prototype: function(currentDomNode). DEPRECATED in 2.2.0 use delegate shouldOpenEditInPlace call instead
postclose: null, // function: this function gets called after the inline editor has closed and all values are updated. Prototype: function(currentDomNode). DEPRECATED in 2.2.0 use delegate didCloseEditInPlace call instead
delegate: null // object: if it has methods with the name of the callbacks documented below in delegateExample these will be called. This means that you just need to impelment the callbacks you are interested in.
};
// Lifecycle events that the delegate can implement
// this will always be fixed to the delegate
var delegateExample = {
// called while opening the editor.
// return false to prevent editor from opening
shouldOpenEditInPlace: function(aDOMNode, aSettingsDict, triggeringEvent) {},
// return content to show in inplace editor
willOpenEditInPlace: function(aDOMNode, aSettingsDict) {},
didOpenEditInPlace: function(aDOMNode, aSettingsDict) {},
// called while closing the editor
// return false to prevent the editor from closing
shouldCloseEditInPlace: function(aDOMNode, aSettingsDict, triggeringEvent) {},
// return value will be shown during saving
willCloseEditInPlace: function(aDOMNode, aSettingsDict) {},
didCloseEditInPlace: function(aDOMNode, aSettingsDict) {},
missingCommaErrorPreventer:''
};
function InlineEditor(settings, dom) {
this.settings = settings;
this.dom = dom;
this.originalValue = null;
this.didInsertDefaultText = false;
this.shouldDelayReinit = false;
};
$.extend(InlineEditor.prototype, {
init: function() {
this.setDefaultTextIfNeccessary();
this.connectOpeningEvents();
},
reinit: function() {
if (this.shouldDelayReinit)
return;
this.triggerCallback(this.settings.postclose, /* DEPRECATED in 2.1.0 */ this.dom);
this.triggerDelegateCall('didCloseEditInPlace');
this.markEditorAsInactive();
this.connectOpeningEvents();
},
setDefaultTextIfNeccessary: function() {
if('' !== this.dom.html())
return;
this.dom.html(this.settings.default_text);
this.didInsertDefaultText = true;
},
connectOpeningEvents: function() {
var that = this;
this.dom
.bind('mouseenter.editInPlace', function(){ that.addHoverEffect(); })
.bind('mouseleave.editInPlace', function(){ that.removeHoverEffect(); })
.bind('click.editInPlace', function(anEvent){ that.openEditor(anEvent); });
},
disconnectOpeningEvents: function() {
// prevent re-opening the editor when it is already open
this.dom.unbind('.editInPlace');
},
addHoverEffect: function() {
if (this.settings.hover_class)
this.dom.addClass(this.settings.hover_class);
else
this.dom.css("background-color", this.settings.bg_over);
},
removeHoverEffect: function() {
if (this.settings.hover_class)
this.dom.removeClass(this.settings.hover_class);
else
this.dom.css("background-color", this.settings.bg_out);
},
openEditor: function(anEvent) {
if ( ! this.shouldOpenEditor(anEvent))
return;
this.workAroundFirefoxBlurBug();
this.disconnectOpeningEvents();
this.removeHoverEffect();
this.removeInsertedDefaultTextIfNeccessary();
this.saveOriginalValue();
this.markEditorAsActive();
this.replaceContentWithEditor();
this.connectOpeningEventsToEditor();
this.triggerDelegateCall('didOpenEditInPlace');
},
shouldOpenEditor: function(anEvent) {
if (this.isClickedObjectCancelled(anEvent.target))
return false;
if (false === this.triggerCallback(this.settings.preinit, /* DEPRECATED in 2.1.0 */ this.dom))
return false;
if (false === this.triggerDelegateCall('shouldOpenEditInPlace', true, anEvent))
return false;
return true;
},
removeInsertedDefaultTextIfNeccessary: function() {
if ( ! this.didInsertDefaultText
|| this.dom.html() !== this.settings.default_text)
return;
this.dom.html('');
this.didInsertDefaultText = false;
},
isClickedObjectCancelled: function(eventTarget) {
if ( ! this.settings.cancel)
return false;
var eventTargetAndParents = $(eventTarget).parents().andSelf();
var elementsMatchingCancelSelector = eventTargetAndParents.filter(this.settings.cancel);
return 0 !== elementsMatchingCancelSelector.length;
},
saveOriginalValue: function() {
if (this.settings.use_html)
this.originalValue = this.dom.html();
else
this.originalValue = trim(this.dom.text());
},
restoreOriginalValue: function() {
this.setClosedEditorContent(this.originalValue);
},
setClosedEditorContent: function(aValue) {
if (this.settings.use_html)
this.dom.html(aValue);
else
this.dom.text(aValue);
},
workAroundFirefoxBlurBug: function() {
if ( ! $.browser.mozilla)
return;
// TODO: Opera seems to also have this bug....
// Firefox will forget to send a blur event to an input element when another one is
// created and selected programmatically. This means that if another inline editor is
// opened, existing inline editors will _not_ close if they are configured to submit when blurred.
// This is actually the first time I've written browser specific code for a browser different than IE! Wohoo!
// Using parents() instead document as base to workaround the fact that in the unittests
// the editor is not a child of window.document but of a document fragment
this.dom.parents(':last').find('.editInPlace-active :input').blur();
},
replaceContentWithEditor: function() {
var buttons_html = (this.settings.show_buttons) ? this.settings.save_button + ' ' + this.settings.cancel_button : '';
var editorElement = this.createEditorElement(); // needs to happen before anything is replaced
/* insert the new in place form after the element they click, then empty out the original element */
this.dom.html('<form class="inplace_form" style="display: inline; margin: 0; padding: 0;"></form>')
.find('form')
.append(editorElement)
.append(buttons_html);
},
createEditorElement: function() {
if (-1 === $.inArray(this.settings.field_type, ['text', 'textarea', 'select']))
throw "Unknown field_type <fnord>, supported are 'text', 'textarea' and 'select'";
var editor = null;
if ("select" === this.settings.field_type)
editor = this.createSelectEditor();
else if ("text" === this.settings.field_type)
editor = $('<input type="text" ' + this.inputNameAndClass()
+ ' size="' + this.settings.text_size + '" />');
else if ("textarea" === this.settings.field_type)
editor = $('<textarea ' + this.inputNameAndClass()
+ ' rows="' + this.settings.textarea_rows + '" '
+ ' cols="' + this.settings.textarea_cols + '" />');
editor.val(this.triggerDelegateCall('willOpenEditInPlace', this.originalValue));
return editor;
},
inputNameAndClass: function() {
return ' name="inplace_value" class="inplace_field" ';
},
createSelectEditor: function() {
var editor = $('<select' + this.inputNameAndClass() + '>'
+ '<option disabled="true" value="">' + this.settings.select_text + '</option>'
+ '</select>');
var optionsArray = this.settings.select_options;
if ( ! $.isArray(optionsArray))
optionsArray = optionsArray.split(',');
for (var i=0; i<optionsArray.length; i++) {
var currentTextAndValue = optionsArray[i];
if ( ! $.isArray(currentTextAndValue))
currentTextAndValue = currentTextAndValue.split(':');
var value = trim(currentTextAndValue[1] || currentTextAndValue[0]);
var text = trim(currentTextAndValue[0]);
var selected = (value == this.originalValue) ? 'selected="selected" ' : '';
var option = $('<option ' + selected + ' ></option>').val(value).text(text);
editor.append(option);
}
return editor;
},
// REFACT: rename opening is not what it's about. Its about closing events really
connectOpeningEventsToEditor: function() {
var that = this;
function cancelEditorAction(anEvent) {
that.handleCancelEditor(anEvent);
return false; // stop event bubbling
}
function saveEditorAction(anEvent) {
that.handleSaveEditor(anEvent);
return false; // stop event bubbling
}
var form = this.dom.find("form");
form.find(".inplace_field").focus().select();
form.find(".inplace_cancel").click(cancelEditorAction);
form.find(".inplace_save").click(saveEditorAction);
if ( ! this.settings.show_buttons) {
// TODO: Firefox has a bug where blur is not reliably called when focus is lost
// (for example by another editor appearing)
if ("save" === this.settings.on_blur)
form.find(".inplace_field").blur(saveEditorAction);
else
form.find(".inplace_field").blur(cancelEditorAction);
// workaround for firefox bug where it won't submit on enter if no button is shown
if ($.browser.mozilla)
this.bindSubmitOnEnterInInput();
}
form.keyup(function(anEvent) {
// allow canceling with escape
var escape = 27;
if (escape === anEvent.which)
return cancelEditorAction();
});
// workaround for webkit nightlies where they won't submit at all on enter
// REFACT: find a way to just target the nightlies
if ($.browser.safari)
this.bindSubmitOnEnterInInput();
form.submit(saveEditorAction);
},
bindSubmitOnEnterInInput: function() {
if ('textarea' === this.settings.field_type)
return; // can't enter newlines otherwise
var that = this;
this.dom.find(':input').keyup(function(event) {
var enter = 13;
if (enter === event.which)
return that.dom.find('form').submit();
});
},
handleCancelEditor: function(anEvent) {
// REFACT: remove duplication between save and cancel
if (false === this.triggerDelegateCall('shouldCloseEditInPlace', true, anEvent))
return;
var enteredText = this.dom.find(':input').val();
enteredText = this.triggerDelegateCall('willCloseEditInPlace', enteredText);
this.restoreOriginalValue();
if (hasContent(enteredText)
&& ! this.isDisabledDefaultSelectChoice())
this.setClosedEditorContent(enteredText);
this.reinit();
},
handleSaveEditor: function(anEvent) {
if (false === this.triggerDelegateCall('shouldCloseEditInPlace', true, anEvent))
return;
var enteredText = this.dom.find(':input').val();
enteredText = this.triggerDelegateCall('willCloseEditInPlace', enteredText);
if (this.isDisabledDefaultSelectChoice()
|| this.isUnchangedInput(enteredText)) {
this.handleCancelEditor(anEvent);
return;
}
if (this.didForgetRequiredText(enteredText)) {
this.handleCancelEditor(anEvent);
this.reportError("Error: You must enter a value to save this field");
return;
}
this.showSaving(enteredText);
if (this.settings.callback)
this.handleSubmitToCallback(enteredText);
else
this.handleSubmitToServer(enteredText);
},
didForgetRequiredText: function(enteredText) {
return this.settings.value_required
&& ("" === enteredText
|| undefined === enteredText
|| null === enteredText);
},
isDisabledDefaultSelectChoice: function() {
return this.dom.find('option').eq(0).is(':selected:disabled');
},
isUnchangedInput: function(enteredText) {
return ! this.settings.save_if_nothing_changed
&& this.originalValue === enteredText;
},
showSaving: function(enteredText) {
if (this.settings.callback && this.settings.callback_skip_dom_reset)
return;
var savingMessage = enteredText;
if (hasContent(this.settings.saving_text))
savingMessage = this.settings.saving_text;
if(hasContent(this.settings.saving_image))
// REFACT: alt should be the configured saving message
savingMessage = $('<img />').attr('src', this.settings.saving_image).attr('alt', savingMessage);
this.dom.html(savingMessage);
},
handleSubmitToCallback: function(enteredText) {
// REFACT: consider to encode enteredText and originalHTML before giving it to the callback
this.enableOrDisableAnimationCallbacks(true, false);
var newHTML = this.triggerCallback(this.settings.callback, /* DEPRECATED in 2.1.0 */ this.id(), enteredText, this.originalValue,
this.settings.params, this.savingAnimationCallbacks());
if (this.settings.callback_skip_dom_reset)
; // do nothing
else if (undefined === newHTML) {
// failure; put original back
this.reportError("Error: Failed to save value: " + enteredText);
this.restoreOriginalValue();
}
else
// REFACT: use setClosedEditorContent
this.dom.html(newHTML);
if (this.didCallNoCallbacks()) {
this.enableOrDisableAnimationCallbacks(false, false);
this.reinit();
}
},
handleSubmitToServer: function(enteredText) {
var data = this.settings.update_value + '=' + encodeURIComponent(enteredText)
+ '&' + this.settings.element_id + '=' + this.dom.attr("id")
+ ((this.settings.params) ? '&' + this.settings.params : '')
+ '&' + this.settings.original_html + '=' + encodeURIComponent(this.originalValue) /* DEPRECATED in 2.2.0 */
+ '&' + this.settings.original_value + '=' + encodeURIComponent(this.originalValue);
this.enableOrDisableAnimationCallbacks(true, false);
this.didStartSaving();
var that = this;
$.ajax({
url: that.settings.url,
type: "POST",
data: data,
dataType: "html",
complete: function(request){
that.didEndSaving();
},
success: function(html){
var new_text = html || that.settings.default_text;
/* put the newly updated info into the original element */
// FIXME: should be affected by the preferences switch
that.dom.html(new_text);
// REFACT: remove dom parameter, already in this, not documented, should be easy to remove
// REFACT: callback should be able to override what gets put into the DOM
that.triggerCallback(that.settings.success, html);
},
error: function(request) {
that.dom.html(that.originalHTML); // REFACT: what about a restorePreEditingContent()
if (that.settings.error)
// REFACT: remove dom parameter, already in this, not documented, can remove without deprecation
// REFACT: callback should be able to override what gets entered into the DOM
that.triggerCallback(that.settings.error, request);
else
that.reportError("Failed to save value: " + request.responseText || 'Unspecified Error');
}
});
},
// Utilities .........................................................
triggerCallback: function(aCallback /*, arguments */) {
if ( ! aCallback)
return; // callback wasn't specified after all
var callbackArguments = Array.prototype.splice.call(arguments, 1);
return aCallback.apply(this.dom[0], callbackArguments);
},
/// defaultReturnValue is only used if the delegate returns undefined
triggerDelegateCall: function(aDelegateMethodName, defaultReturnValue, optionalEvent) {
// REFACT: consider to trigger equivalent callbacks automatically via a mapping table?
if ( ! this.settings.delegate
|| ! $.isFunction(this.settings.delegate[aDelegateMethodName]))
return defaultReturnValue;
var delegateReturnValue = this.settings.delegate[aDelegateMethodName](this.dom, this.settings, optionalEvent);
return (undefined === delegateReturnValue)
? defaultReturnValue
: delegateReturnValue;
},
reportError: function(anErrorString) {
this.triggerCallback(this.settings.error_sink, /* DEPRECATED in 2.1.0 */ this.id(), anErrorString);
},
// REFACT: this method should go, callbacks should get the dom node itself as an argument
id: function() {
return this.dom.attr('id');
},
markEditorAsActive: function() {
this.dom.addClass('editInPlace-active');
},
markEditorAsInactive: function() {
this.dom.removeClass('editInPlace-active');
},
// REFACT: consider rename, doesn't deal with animation directly
savingAnimationCallbacks: function() {
var that = this;
return {
didStartSaving: function() { that.didStartSaving(); },
didEndSaving: function() { that.didEndSaving(); }
};
},
enableOrDisableAnimationCallbacks: function(shouldEnableStart, shouldEnableEnd) {
this.didStartSaving.enabled = shouldEnableStart;
this.didEndSaving.enabled = shouldEnableEnd;
},
didCallNoCallbacks: function() {
return this.didStartSaving.enabled && ! this.didEndSaving.enabled;
},
assertCanCall: function(methodName) {
if ( ! this[methodName].enabled)
throw new Error('Cannot call ' + methodName + ' now. See documentation for details.');
},
didStartSaving: function() {
this.assertCanCall('didStartSaving');
this.shouldDelayReinit = true;
this.enableOrDisableAnimationCallbacks(false, true);
this.startSavingAnimation();
},
didEndSaving: function() {
this.assertCanCall('didEndSaving');
this.shouldDelayReinit = false;
this.enableOrDisableAnimationCallbacks(false, false);
this.reinit();
this.stopSavingAnimation();
},
startSavingAnimation: function() {
var that = this;
this.dom
.animate({ backgroundColor: this.settings.saving_animation_color }, 400)
.animate({ backgroundColor: 'transparent'}, 400, 'swing', function(){
// In the tests animations are turned off - i.e they happen instantaneously.
// Hence we need to prevent this from becomming an unbounded recursion.
setTimeout(function(){ that.startSavingAnimation(); }, 10);
});
},
stopSavingAnimation: function() {
this.dom
.stop(true)
.css({backgroundColor: ''});
},
missingCommaErrorPreventer:''
});
// Private helpers .......................................................
function assertMandatorySettingsArePresent(options) {
// one of these needs to be non falsy
if (options.url || options.callback)
return;
throw new Error("Need to set either url: or callback: option for the inline editor to work.");
}
/* preload the loading icon if it is configured */
function preloadImage(anImageURL) {
if ('' === anImageURL)
return;
var loading_image = new Image();
loading_image.src = anImageURL;
}
function trim(aString) {
return aString
.replace(/^\s+/, '')
.replace(/\s+$/, '');
}
function hasContent(something) {
if (undefined === something || null === something)
return false;
if (0 === something.length)
return false;
return true;
}
})(jQuery);