active_scaffold_san 3.0.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +27 -0
- data/.document +5 -0
- data/CHANGELOG +179 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/MIT-LICENSE +20 -0
- data/README +69 -0
- data/Rakefile +53 -0
- data/active_scaffold_vho.gemspec +388 -0
- data/frontends/default/images/add.gif +0 -0
- data/frontends/default/images/arrow_down.gif +0 -0
- data/frontends/default/images/arrow_up.gif +0 -0
- data/frontends/default/images/close.gif +0 -0
- data/frontends/default/images/config.png +0 -0
- data/frontends/default/images/cross.png +0 -0
- data/frontends/default/images/gears.png +0 -0
- data/frontends/default/images/indicator-small.gif +0 -0
- data/frontends/default/images/indicator.gif +0 -0
- data/frontends/default/images/magnifier.png +0 -0
- data/frontends/default/javascripts/jquery/active_scaffold.js +1004 -0
- data/frontends/default/javascripts/jquery/jquery.editinplace.js +743 -0
- data/frontends/default/javascripts/prototype/active_scaffold.js +1003 -0
- data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
- data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
- data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
- data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
- data/frontends/default/stylesheets/stylesheet.css +973 -0
- data/frontends/default/views/_action_group.html.erb +20 -0
- data/frontends/default/views/_add_existing_form.html.erb +30 -0
- data/frontends/default/views/_base_form.html.erb +51 -0
- data/frontends/default/views/_create_form.html.erb +8 -0
- data/frontends/default/views/_create_form_on_list.html.erb +6 -0
- data/frontends/default/views/_field_search.html.erb +32 -0
- data/frontends/default/views/_form.html.erb +24 -0
- data/frontends/default/views/_form_association.html.erb +19 -0
- data/frontends/default/views/_form_association_footer.html.erb +40 -0
- data/frontends/default/views/_form_attribute.html.erb +15 -0
- data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
- data/frontends/default/views/_form_messages.html.erb +5 -0
- data/frontends/default/views/_horizontal_subform.html.erb +29 -0
- data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
- data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
- data/frontends/default/views/_human_conditions.html.erb +1 -0
- data/frontends/default/views/_list.html.erb +18 -0
- data/frontends/default/views/_list_actions.html.erb +15 -0
- data/frontends/default/views/_list_calculations.html.erb +16 -0
- data/frontends/default/views/_list_column_headings.html.erb +12 -0
- data/frontends/default/views/_list_header.html.erb +10 -0
- data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
- data/frontends/default/views/_list_messages.html.erb +32 -0
- data/frontends/default/views/_list_pagination.html.erb +11 -0
- data/frontends/default/views/_list_pagination_links.html.erb +9 -0
- data/frontends/default/views/_list_record.html.erb +14 -0
- data/frontends/default/views/_list_record_columns.html.erb +8 -0
- data/frontends/default/views/_list_with_header.html.erb +32 -0
- data/frontends/default/views/_messages.html.erb +10 -0
- data/frontends/default/views/_render_field.js.rjs +10 -0
- data/frontends/default/views/_row.html.erb +12 -0
- data/frontends/default/views/_search.html.erb +34 -0
- data/frontends/default/views/_search_attribute.html.erb +10 -0
- data/frontends/default/views/_show.html.erb +8 -0
- data/frontends/default/views/_show_columns.html.erb +15 -0
- data/frontends/default/views/_update_actions.html.erb +9 -0
- data/frontends/default/views/_update_form.html.erb +6 -0
- data/frontends/default/views/_vertical_subform.html.erb +12 -0
- data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
- data/frontends/default/views/action_confirmation.html.erb +13 -0
- data/frontends/default/views/add_existing.js.rjs +17 -0
- data/frontends/default/views/add_existing_form.html.erb +5 -0
- data/frontends/default/views/create.html.erb +5 -0
- data/frontends/default/views/delete.html.erb +13 -0
- data/frontends/default/views/destroy.js.rjs +23 -0
- data/frontends/default/views/edit_associated.js.rjs +11 -0
- data/frontends/default/views/field_search.html.erb +5 -0
- data/frontends/default/views/form_messages.js.rjs +1 -0
- data/frontends/default/views/list.html.erb +1 -0
- data/frontends/default/views/list.js.rjs +1 -0
- data/frontends/default/views/on_action_update.js.rjs +8 -0
- data/frontends/default/views/on_create.js.rjs +41 -0
- data/frontends/default/views/on_mark_all.js.rjs +4 -0
- data/frontends/default/views/on_update.js.rjs +28 -0
- data/frontends/default/views/search.html.erb +5 -0
- data/frontends/default/views/show.html.erb +5 -0
- data/frontends/default/views/update.html.erb +8 -0
- data/frontends/default/views/update_column.js.rjs +13 -0
- data/frontends/default/views/update_row.js.rjs +1 -0
- data/init.rb +8 -0
- data/lib/active_scaffold.rb +360 -0
- data/lib/active_scaffold/actions/common_search.rb +22 -0
- data/lib/active_scaffold/actions/core.rb +180 -0
- data/lib/active_scaffold/actions/create.rb +149 -0
- data/lib/active_scaffold/actions/delete.rb +75 -0
- data/lib/active_scaffold/actions/field_search.rb +82 -0
- data/lib/active_scaffold/actions/list.rb +184 -0
- data/lib/active_scaffold/actions/mark.rb +63 -0
- data/lib/active_scaffold/actions/nested.rb +250 -0
- data/lib/active_scaffold/actions/search.rb +47 -0
- data/lib/active_scaffold/actions/show.rb +61 -0
- data/lib/active_scaffold/actions/subform.rb +27 -0
- data/lib/active_scaffold/actions/update.rb +151 -0
- data/lib/active_scaffold/active_record_permissions.rb +134 -0
- data/lib/active_scaffold/attribute_params.rb +211 -0
- data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +39 -0
- data/lib/active_scaffold/bridges/bridge.rb +59 -0
- data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
- data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +83 -0
- data/lib/active_scaffold/bridges/cancan/bridge.rb +12 -0
- data/lib/active_scaffold/bridges/cancan/lib/cancan_bridge.rb +107 -0
- data/lib/active_scaffold/bridges/carrierwave/bridge.rb +9 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +33 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +12 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +45 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
- data/lib/active_scaffold/bridges/date_picker/bridge.rb +24 -0
- data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
- data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
- data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
- data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
- data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
- data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
- data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
- data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
- data/lib/active_scaffold/bridges/paperclip/bridge.rb +12 -0
- data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
- data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
- data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
- data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
- data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +209 -0
- data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +61 -0
- data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
- data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
- data/lib/active_scaffold/config/base.rb +62 -0
- data/lib/active_scaffold/config/core.rb +220 -0
- data/lib/active_scaffold/config/create.rb +51 -0
- data/lib/active_scaffold/config/delete.rb +34 -0
- data/lib/active_scaffold/config/field_search.rb +75 -0
- data/lib/active_scaffold/config/form.rb +47 -0
- data/lib/active_scaffold/config/list.rb +174 -0
- data/lib/active_scaffold/config/mark.rb +22 -0
- data/lib/active_scaffold/config/nested.rb +44 -0
- data/lib/active_scaffold/config/search.rb +69 -0
- data/lib/active_scaffold/config/show.rb +35 -0
- data/lib/active_scaffold/config/subform.rb +35 -0
- data/lib/active_scaffold/config/update.rb +46 -0
- data/lib/active_scaffold/configurable.rb +29 -0
- data/lib/active_scaffold/constraints.rb +184 -0
- data/lib/active_scaffold/data_structures/action_columns.rb +137 -0
- data/lib/active_scaffold/data_structures/action_link.rb +175 -0
- data/lib/active_scaffold/data_structures/action_links.rb +185 -0
- data/lib/active_scaffold/data_structures/actions.rb +45 -0
- data/lib/active_scaffold/data_structures/column.rb +355 -0
- data/lib/active_scaffold/data_structures/columns.rb +75 -0
- data/lib/active_scaffold/data_structures/error_message.rb +24 -0
- data/lib/active_scaffold/data_structures/nested_info.rb +123 -0
- data/lib/active_scaffold/data_structures/set.rb +62 -0
- data/lib/active_scaffold/data_structures/sorting.rb +168 -0
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +20 -0
- data/lib/active_scaffold/extensions/action_view_rendering.rb +123 -0
- data/lib/active_scaffold/extensions/action_view_resolver.rb +7 -0
- data/lib/active_scaffold/extensions/active_association_reflection.rb +13 -0
- data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
- data/lib/active_scaffold/extensions/array.rb +7 -0
- data/lib/active_scaffold/extensions/localize.rb +10 -0
- data/lib/active_scaffold/extensions/name_option_for_datetime.rb +12 -0
- data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +7 -0
- data/lib/active_scaffold/extensions/paginator_extensions.rb +26 -0
- data/lib/active_scaffold/extensions/reverse_associations.rb +62 -0
- data/lib/active_scaffold/extensions/routing_mapper.rb +34 -0
- data/lib/active_scaffold/extensions/to_label.rb +8 -0
- data/lib/active_scaffold/extensions/unsaved_associated.rb +61 -0
- data/lib/active_scaffold/extensions/unsaved_record.rb +20 -0
- data/lib/active_scaffold/extensions/usa_state.rb +46 -0
- data/lib/active_scaffold/finder.rb +343 -0
- data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
- data/lib/active_scaffold/helpers/controller_helpers.rb +87 -0
- data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
- data/lib/active_scaffold/helpers/form_column_helpers.rb +350 -0
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
- data/lib/active_scaffold/helpers/id_helpers.rb +127 -0
- data/lib/active_scaffold/helpers/list_column_helpers.rb +361 -0
- data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
- data/lib/active_scaffold/helpers/search_column_helpers.rb +249 -0
- data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
- data/lib/active_scaffold/helpers/view_helpers.rb +360 -0
- data/lib/active_scaffold/locale/de.rb +120 -0
- data/lib/active_scaffold/locale/en.rb +119 -0
- data/lib/active_scaffold/locale/es.yml +115 -0
- data/lib/active_scaffold/locale/fr.rb +122 -0
- data/lib/active_scaffold/locale/hu.yml +63 -0
- data/lib/active_scaffold/locale/ja.yml +64 -0
- data/lib/active_scaffold/locale/ru.yml +119 -0
- data/lib/active_scaffold/marked_model.rb +38 -0
- data/lib/active_scaffold/paginator.rb +136 -0
- data/lib/active_scaffold/responds_to_parent.rb +70 -0
- data/lib/active_scaffold/version.rb +9 -0
- data/lib/active_scaffold_assets.rb +45 -0
- data/lib/active_scaffold_env.rb +14 -0
- data/lib/active_scaffold_vho.rb +2 -0
- data/lib/generators/active_scaffold/USAGE +29 -0
- data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
- data/lib/generators/active_scaffold_controller/USAGE +19 -0
- data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +29 -0
- data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
- data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
- data/lib/generators/active_scaffold_setup/USAGE +10 -0
- data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +61 -0
- data/public/blank.html +33 -0
- data/shoulda_macros/macros.rb +136 -0
- data/test/bridges/bridge_test.rb +47 -0
- data/test/config/base_test.rb +15 -0
- data/test/config/create_test.rb +55 -0
- data/test/config/list_test.rb +74 -0
- data/test/config/show_test.rb +43 -0
- data/test/config/update_test.rb +17 -0
- data/test/const_mocker.rb +36 -0
- data/test/data_structures/action_columns_test.rb +113 -0
- data/test/data_structures/action_link_test.rb +78 -0
- data/test/data_structures/action_links_test.rb +78 -0
- data/test/data_structures/actions_test.rb +25 -0
- data/test/data_structures/association_column_test.rb +42 -0
- data/test/data_structures/column_test.rb +185 -0
- data/test/data_structures/columns_test.rb +69 -0
- data/test/data_structures/error_message_test.rb +28 -0
- data/test/data_structures/set_test.rb +86 -0
- data/test/data_structures/sorting_test.rb +126 -0
- data/test/data_structures/standard_column_test.rb +24 -0
- data/test/data_structures/virtual_column_test.rb +23 -0
- data/test/extensions/active_record_test.rb +45 -0
- data/test/extensions/array_test.rb +12 -0
- data/test/helpers/form_column_helpers_test.rb +31 -0
- data/test/helpers/list_column_helpers_test.rb +31 -0
- data/test/helpers/pagination_helpers_test.rb +55 -0
- data/test/misc/active_record_permissions_test.rb +154 -0
- data/test/misc/attribute_params_test.rb +110 -0
- data/test/misc/configurable_test.rb +96 -0
- data/test/misc/constraints_test.rb +193 -0
- data/test/misc/finder_test.rb +93 -0
- data/test/misc/lang_test.rb +12 -0
- data/test/mock_app/.gitignore +2 -0
- data/test/mock_app/app/controllers/application_controller.rb +10 -0
- data/test/mock_app/app/helpers/application_helper.rb +3 -0
- data/test/mock_app/config/boot.rb +110 -0
- data/test/mock_app/config/database.yml +16 -0
- data/test/mock_app/config/environment.rb +43 -0
- data/test/mock_app/config/environments/development.rb +17 -0
- data/test/mock_app/config/environments/production.rb +28 -0
- data/test/mock_app/config/environments/test.rb +28 -0
- data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/mock_app/config/initializers/inflections.rb +10 -0
- data/test/mock_app/config/initializers/mime_types.rb +5 -0
- data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
- data/test/mock_app/config/initializers/session_store.rb +15 -0
- data/test/mock_app/config/locales/en.yml +5 -0
- data/test/mock_app/config/routes.rb +43 -0
- data/test/mock_app/db/test.sqlite3 +1 -0
- data/test/mock_app/public/blank.html +33 -0
- data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
- data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
- data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +842 -0
- data/test/model_stub.rb +55 -0
- data/test/run_all.rb +8 -0
- data/test/test_helper.rb +39 -0
- data/uninstall.rb +13 -0
- metadata +497 -0
@@ -0,0 +1,743 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
A jQuery edit in place plugin
|
4
|
+
|
5
|
+
Version 2.2.0
|
6
|
+
|
7
|
+
Authors:
|
8
|
+
Dave Hauenstein
|
9
|
+
Martin Häcker <spamfaenger [at] gmx [dot] de>
|
10
|
+
|
11
|
+
Project home:
|
12
|
+
http://code.google.com/p/jquery-in-place-editor/
|
13
|
+
|
14
|
+
Patches with tests welcomed! For guidance see the tests at </spec/unit/spec.js>. To submit, attach them to the bug tracker.
|
15
|
+
|
16
|
+
License:
|
17
|
+
This source file is subject to the BSD license bundled with this package.
|
18
|
+
Available online: {@link http://www.opensource.org/licenses/bsd-license.php}
|
19
|
+
If you did not receive a copy of the license, and are unable to obtain it,
|
20
|
+
learn to use a search engine.
|
21
|
+
|
22
|
+
*/
|
23
|
+
|
24
|
+
(function($){
|
25
|
+
|
26
|
+
$.fn.editInPlace = function(options) {
|
27
|
+
|
28
|
+
var settings = $.extend({}, $.fn.editInPlace.defaults, options);
|
29
|
+
|
30
|
+
assertMandatorySettingsArePresent(settings);
|
31
|
+
|
32
|
+
preloadImage(settings.saving_image);
|
33
|
+
|
34
|
+
return this.each(function() {
|
35
|
+
var dom = $(this);
|
36
|
+
// This won't work with live queries as there is no specific element to attach this
|
37
|
+
// one way to deal with this could be to store a reference to self and then compare that in click?
|
38
|
+
if (dom.data('editInPlace'))
|
39
|
+
return; // already an editor here
|
40
|
+
dom.data('editInPlace', true);
|
41
|
+
|
42
|
+
new InlineEditor(settings, dom).init();
|
43
|
+
});
|
44
|
+
};
|
45
|
+
|
46
|
+
/// Switch these through the dictionary argument to $(aSelector).editInPlace(overideOptions)
|
47
|
+
/// Required Options: Either url or callback, so the editor knows what to do with the edited values.
|
48
|
+
$.fn.editInPlace.defaults = {
|
49
|
+
url: "", // string: POST URL to send edited content
|
50
|
+
ajax_data_type: "html", // string: dataType (html|script) for ajax call to save updated value
|
51
|
+
bg_over: "#ffc", // string: background color of hover of unactivated editor
|
52
|
+
bg_out: "transparent", // string: background color on restore from hover
|
53
|
+
hover_class: "", // string: class added to root element during hover. Will override bg_over and bg_out
|
54
|
+
show_buttons: false, // boolean: will show the buttons: cancel or save; will automatically cancel out the onBlur functionality
|
55
|
+
save_button: '<button class="inplace_save">Save</button>', // string: image button tag to use as “Save” button
|
56
|
+
cancel_button: '<button class="inplace_cancel">Cancel</button>', // string: image button tag to use as “Cancel” button
|
57
|
+
params: "", // string: example: first_name=dave&last_name=hauenstein extra paramters sent via the post request to the server
|
58
|
+
field_type: "text", // string: "text", "textarea", or "select", or "remote", or "clone"; The type of form field that will appear on instantiation
|
59
|
+
default_text: "(Click here to add text)", // string: text to show up if the element that has this functionality is empty
|
60
|
+
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
|
61
|
+
textarea_rows: 10, // integer: set rows attribute of textarea, if field_type is set to textarea. Use CSS if possible though
|
62
|
+
textarea_cols: 25, // integer: set cols attribute of textarea, if field_type is set to textarea. Use CSS if possible though
|
63
|
+
select_text: "Choose new value", // string: default text to show up in select box
|
64
|
+
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)
|
65
|
+
text_size: null, // integer: set cols attribute of text input, if field_type is set to text. Use CSS if possible though
|
66
|
+
editor_url: null, // for field_type: remote url to get html_code for edit_control
|
67
|
+
loading_text: 'Loading...', // shown if inplace editor is loaded from server
|
68
|
+
// Specifying callback_skip_dom_reset will disable all saving_* options
|
69
|
+
saving_text: undefined, // string: text to be used when server is saving information. Example "Saving..."
|
70
|
+
saving_image: "", // string: uses saving text specify an image location instead of text while server is saving
|
71
|
+
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
|
72
|
+
clone_selector: null, // if field_type clone a selector to clone editor from
|
73
|
+
clone_id_suffix: null, // if field_type clone a suffix to create unique ids
|
74
|
+
|
75
|
+
value_required: false, // boolean: if set to true, the element will not be saved unless a value is entered
|
76
|
+
element_id: "element_id", // string: name of parameter holding the id or the editable
|
77
|
+
update_value: "update_value", // string: name of parameter holding the updated/edited value
|
78
|
+
original_value: 'original_value', // string: name of parameter holding the updated/edited value
|
79
|
+
original_html: "original_html", // string: name of parameter holding original_html value of the editable /* DEPRECATED in 2.2.0 */ use original_value instead.
|
80
|
+
save_if_nothing_changed: false, // boolean: submit to function or server even if the user did not change anything
|
81
|
+
on_blur: "save", // string: "save" or null; what to do on blur; will be overridden if show_buttons is true
|
82
|
+
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
|
83
|
+
|
84
|
+
// All callbacks will have this set to the DOM node of the editor that triggered the callback
|
85
|
+
|
86
|
+
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
|
87
|
+
callback_skip_dom_reset: false, // boolean: set this to true if the callback should handle replacing the editor with the new value to show
|
88
|
+
success: null, // function: this function gets called if server responds with a success. Prototype: function(newEditorContentString)
|
89
|
+
error: null, // function: this function gets called if server responds with an error. Prototype: function(request)
|
90
|
+
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
|
91
|
+
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
|
92
|
+
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
|
93
|
+
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.
|
94
|
+
};
|
95
|
+
|
96
|
+
// Lifecycle events that the delegate can implement
|
97
|
+
// this will always be fixed to the delegate
|
98
|
+
var delegateExample = {
|
99
|
+
// called while opening the editor.
|
100
|
+
// return false to prevent editor from opening
|
101
|
+
shouldOpenEditInPlace: function(aDOMNode, aSettingsDict, triggeringEvent) {},
|
102
|
+
// return content to show in inplace editor
|
103
|
+
willOpenEditInPlace: function(aDOMNode, aSettingsDict) {},
|
104
|
+
didOpenEditInPlace: function(aDOMNode, aSettingsDict) {},
|
105
|
+
|
106
|
+
// called while closing the editor
|
107
|
+
// return false to prevent the editor from closing
|
108
|
+
shouldCloseEditInPlace: function(aDOMNode, aSettingsDict, triggeringEvent) {},
|
109
|
+
// return value will be shown during saving
|
110
|
+
willCloseEditInPlace: function(aDOMNode, aSettingsDict) {},
|
111
|
+
didCloseEditInPlace: function(aDOMNode, aSettingsDict) {},
|
112
|
+
|
113
|
+
missingCommaErrorPreventer:''
|
114
|
+
};
|
115
|
+
|
116
|
+
|
117
|
+
function InlineEditor(settings, dom) {
|
118
|
+
this.settings = settings;
|
119
|
+
this.dom = dom;
|
120
|
+
this.originalValue = null;
|
121
|
+
this.didInsertDefaultText = false;
|
122
|
+
this.shouldDelayReinit = false;
|
123
|
+
};
|
124
|
+
|
125
|
+
$.extend(InlineEditor.prototype, {
|
126
|
+
|
127
|
+
init: function() {
|
128
|
+
this.setDefaultTextIfNeccessary();
|
129
|
+
this.connectOpeningEvents();
|
130
|
+
},
|
131
|
+
|
132
|
+
reinit: function() {
|
133
|
+
if (this.shouldDelayReinit)
|
134
|
+
return;
|
135
|
+
|
136
|
+
this.triggerCallback(this.settings.postclose, /* DEPRECATED in 2.1.0 */ this.dom);
|
137
|
+
this.triggerDelegateCall('didCloseEditInPlace');
|
138
|
+
|
139
|
+
this.markEditorAsInactive();
|
140
|
+
this.connectOpeningEvents();
|
141
|
+
},
|
142
|
+
|
143
|
+
setDefaultTextIfNeccessary: function() {
|
144
|
+
if('' !== this.dom.html())
|
145
|
+
return;
|
146
|
+
|
147
|
+
this.dom.html(this.settings.default_text);
|
148
|
+
this.didInsertDefaultText = true;
|
149
|
+
},
|
150
|
+
|
151
|
+
connectOpeningEvents: function() {
|
152
|
+
var that = this;
|
153
|
+
this.dom
|
154
|
+
.bind('mouseenter.editInPlace', function(){ that.addHoverEffect(); })
|
155
|
+
.bind('mouseleave.editInPlace', function(){ that.removeHoverEffect(); })
|
156
|
+
.bind('click.editInPlace', function(anEvent){ that.openEditor(anEvent); });
|
157
|
+
},
|
158
|
+
|
159
|
+
disconnectOpeningEvents: function() {
|
160
|
+
// prevent re-opening the editor when it is already open
|
161
|
+
this.dom.unbind('.editInPlace');
|
162
|
+
},
|
163
|
+
|
164
|
+
addHoverEffect: function() {
|
165
|
+
if (this.settings.hover_class)
|
166
|
+
this.dom.addClass(this.settings.hover_class);
|
167
|
+
else
|
168
|
+
this.dom.css("background-color", this.settings.bg_over);
|
169
|
+
},
|
170
|
+
|
171
|
+
removeHoverEffect: function() {
|
172
|
+
if (this.settings.hover_class)
|
173
|
+
this.dom.removeClass(this.settings.hover_class);
|
174
|
+
else
|
175
|
+
this.dom.css("background-color", this.settings.bg_out);
|
176
|
+
},
|
177
|
+
|
178
|
+
openEditor: function(anEvent) {
|
179
|
+
if ( ! this.shouldOpenEditor(anEvent))
|
180
|
+
return;
|
181
|
+
|
182
|
+
this.workAroundFirefoxBlurBug();
|
183
|
+
this.disconnectOpeningEvents();
|
184
|
+
this.removeHoverEffect();
|
185
|
+
this.removeInsertedDefaultTextIfNeccessary();
|
186
|
+
this.saveOriginalValue();
|
187
|
+
this.markEditorAsActive();
|
188
|
+
this.replaceContentWithEditor();
|
189
|
+
this.connectOpeningEventsToEditor();
|
190
|
+
this.triggerDelegateCall('didOpenEditInPlace');
|
191
|
+
},
|
192
|
+
|
193
|
+
shouldOpenEditor: function(anEvent) {
|
194
|
+
if (this.isClickedObjectCancelled(anEvent.target))
|
195
|
+
return false;
|
196
|
+
|
197
|
+
if (false === this.triggerCallback(this.settings.preinit, /* DEPRECATED in 2.1.0 */ this.dom))
|
198
|
+
return false;
|
199
|
+
|
200
|
+
if (false === this.triggerDelegateCall('shouldOpenEditInPlace', true, anEvent))
|
201
|
+
return false;
|
202
|
+
|
203
|
+
return true;
|
204
|
+
},
|
205
|
+
|
206
|
+
removeInsertedDefaultTextIfNeccessary: function() {
|
207
|
+
if ( ! this.didInsertDefaultText
|
208
|
+
|| this.dom.html() !== this.settings.default_text)
|
209
|
+
return;
|
210
|
+
|
211
|
+
this.dom.html('');
|
212
|
+
this.didInsertDefaultText = false;
|
213
|
+
},
|
214
|
+
|
215
|
+
isClickedObjectCancelled: function(eventTarget) {
|
216
|
+
if ( ! this.settings.cancel)
|
217
|
+
return false;
|
218
|
+
|
219
|
+
var eventTargetAndParents = $(eventTarget).parents().andSelf();
|
220
|
+
var elementsMatchingCancelSelector = eventTargetAndParents.filter(this.settings.cancel);
|
221
|
+
return 0 !== elementsMatchingCancelSelector.length;
|
222
|
+
},
|
223
|
+
|
224
|
+
saveOriginalValue: function() {
|
225
|
+
if (this.settings.use_html)
|
226
|
+
this.originalValue = this.dom.html();
|
227
|
+
else
|
228
|
+
this.originalValue = trim(this.dom.text());
|
229
|
+
},
|
230
|
+
|
231
|
+
restoreOriginalValue: function() {
|
232
|
+
this.setClosedEditorContent(this.originalValue);
|
233
|
+
},
|
234
|
+
|
235
|
+
setClosedEditorContent: function(aValue) {
|
236
|
+
if (this.settings.use_html)
|
237
|
+
this.dom.html(aValue);
|
238
|
+
else
|
239
|
+
this.dom.text(aValue);
|
240
|
+
},
|
241
|
+
|
242
|
+
workAroundFirefoxBlurBug: function() {
|
243
|
+
if ( ! $.browser.mozilla)
|
244
|
+
return;
|
245
|
+
|
246
|
+
// TODO: Opera seems to also have this bug....
|
247
|
+
|
248
|
+
// Firefox will forget to send a blur event to an input element when another one is
|
249
|
+
// created and selected programmatically. This means that if another inline editor is
|
250
|
+
// opened, existing inline editors will _not_ close if they are configured to submit when blurred.
|
251
|
+
// This is actually the first time I've written browser specific code for a browser different than IE! Wohoo!
|
252
|
+
|
253
|
+
// Using parents() instead document as base to workaround the fact that in the unittests
|
254
|
+
// the editor is not a child of window.document but of a document fragment
|
255
|
+
this.dom.parents(':last').find('.editInPlace-active :input').blur();
|
256
|
+
},
|
257
|
+
|
258
|
+
replaceContentWithEditor: function() {
|
259
|
+
var buttons_html = (this.settings.show_buttons) ? this.settings.save_button + ' ' + this.settings.cancel_button : '';
|
260
|
+
var editorElement = this.createEditorElement(); // needs to happen before anything is replaced
|
261
|
+
/* insert the new in place form after the element they click, then empty out the original element */
|
262
|
+
this.dom.html('<form class="inplace_form" style="display: inline; margin: 0; padding: 0;"></form>')
|
263
|
+
.find('form')
|
264
|
+
.append(editorElement)
|
265
|
+
.append(buttons_html);
|
266
|
+
},
|
267
|
+
|
268
|
+
createEditorElement: function() {
|
269
|
+
if (-1 === $.inArray(this.settings.field_type, ['text', 'textarea', 'select', 'remote', 'clone']))
|
270
|
+
throw "Unknown field_type <fnord>, supported are 'text', 'textarea', 'select' and 'remote'";
|
271
|
+
|
272
|
+
var editor = null;
|
273
|
+
if ("select" === this.settings.field_type)
|
274
|
+
editor = this.createSelectEditor();
|
275
|
+
else if ("text" === this.settings.field_type)
|
276
|
+
editor = $('<input type="text" ' + this.inputNameAndClass()
|
277
|
+
+ ' size="' + this.settings.text_size + '" />');
|
278
|
+
else if ("textarea" === this.settings.field_type)
|
279
|
+
editor = $('<textarea ' + this.inputNameAndClass()
|
280
|
+
+ ' rows="' + this.settings.textarea_rows + '" '
|
281
|
+
+ ' cols="' + this.settings.textarea_cols + '" />');
|
282
|
+
else if ("remote" === this.settings.field_type)
|
283
|
+
editor = this.createRemoteGeneratedEditor();
|
284
|
+
else if ("clone" === this.settings.field_type) {
|
285
|
+
editor = this.cloneEditor();
|
286
|
+
return editor;
|
287
|
+
}
|
288
|
+
editor.val(this.triggerDelegateCall('willOpenEditInPlace', this.originalValue));
|
289
|
+
return editor;
|
290
|
+
},
|
291
|
+
|
292
|
+
createRemoteGeneratedEditor: function () {
|
293
|
+
this.dom.html(this.settings.loading_text);
|
294
|
+
return $($.ajax({
|
295
|
+
url: this.settings.editor_url,
|
296
|
+
async: false
|
297
|
+
}).responseText);
|
298
|
+
},
|
299
|
+
|
300
|
+
cloneEditor: function() {
|
301
|
+
var patternNodes = this.getPatternNodes(this.settings.clone_selector);
|
302
|
+
if (patternNodes.editNode == null) {
|
303
|
+
alert('did not find any matching node for ' + this.settings.clone_selector);
|
304
|
+
return;
|
305
|
+
}
|
306
|
+
|
307
|
+
var editorNode = patternNodes.editNode.clone();
|
308
|
+
var clonedNodes = null;
|
309
|
+
if (editorNode.attr('id').length > 0) editorNode.attr('id', editorNode.attr('id') + this.settings.clone_id_suffix);
|
310
|
+
editorNode.attr('name', 'inplace_value');
|
311
|
+
editorNode.addClass('editor_field');
|
312
|
+
this.setValue(editorNode, this.originalValue);
|
313
|
+
clonedNodes = editorNode;
|
314
|
+
|
315
|
+
if (patternNodes.additionalNodes) {
|
316
|
+
patternNodes.additionalNodes.each(function (index, node) {
|
317
|
+
var patternNode = $(node).clone();
|
318
|
+
if (patternNode.attr('id').length > 0) {
|
319
|
+
patternNode.attr('id', patternNode.attr('id') + this.settings.clone_id_suffix);
|
320
|
+
}
|
321
|
+
clonedNodes = clonedNodes.after(patternNode);
|
322
|
+
});
|
323
|
+
}
|
324
|
+
return clonedNodes;
|
325
|
+
},
|
326
|
+
|
327
|
+
getPatternNodes: function(clone_selector) {
|
328
|
+
var nodes = {editNode: null, additionalNodes: null};
|
329
|
+
var selectedNodes = $(clone_selector);
|
330
|
+
var firstNode = selectedNodes.first();
|
331
|
+
|
332
|
+
if (typeof(firstNode) !== 'undefined') {
|
333
|
+
// AS inplace_edit_control_container -> we have to select all child nodes
|
334
|
+
// Workaround for ie which does not support css > selector
|
335
|
+
if (firstNode.hasClass('as_inplace_pattern')) {
|
336
|
+
selectedNodes = firstNode.children();
|
337
|
+
}
|
338
|
+
nodes.editNode = selectedNodes.first();
|
339
|
+
// buggy...
|
340
|
+
//nodes.additionalNodes = selectedNodes.find(':gt(0)');
|
341
|
+
}
|
342
|
+
return nodes;
|
343
|
+
},
|
344
|
+
|
345
|
+
setValue: function(editField, textValue) {
|
346
|
+
var function_name = 'setValueFor' + editField.get(0).nodeName.toLowerCase();
|
347
|
+
if (typeof(this[function_name]) == 'function') {
|
348
|
+
this[function_name](editField, textValue);
|
349
|
+
} else {
|
350
|
+
editField.val(textValue);
|
351
|
+
}
|
352
|
+
},
|
353
|
+
|
354
|
+
setValueForselect: function(editField, textValue) {
|
355
|
+
var option_value = editField.children("option:contains('" + textValue + "')").val();
|
356
|
+
|
357
|
+
if (typeof(option_value) !== 'undefined') {
|
358
|
+
editField.val(option_value);
|
359
|
+
}
|
360
|
+
},
|
361
|
+
|
362
|
+
inputNameAndClass: function() {
|
363
|
+
return ' name="inplace_value" class="inplace_field" ';
|
364
|
+
},
|
365
|
+
|
366
|
+
createSelectEditor: function() {
|
367
|
+
var editor = $('<select' + this.inputNameAndClass() + '>'
|
368
|
+
+ '<option disabled="true" value="">' + this.settings.select_text + '</option>'
|
369
|
+
+ '</select>');
|
370
|
+
|
371
|
+
var optionsArray = this.settings.select_options;
|
372
|
+
if ( ! $.isArray(optionsArray))
|
373
|
+
optionsArray = optionsArray.split(',');
|
374
|
+
|
375
|
+
for (var i=0; i<optionsArray.length; i++) {
|
376
|
+
|
377
|
+
var currentTextAndValue = optionsArray[i];
|
378
|
+
if ( ! $.isArray(currentTextAndValue))
|
379
|
+
currentTextAndValue = currentTextAndValue.split(':');
|
380
|
+
|
381
|
+
var value = trim(currentTextAndValue[1] || currentTextAndValue[0]);
|
382
|
+
var text = trim(currentTextAndValue[0]);
|
383
|
+
|
384
|
+
var selected = (value == this.originalValue) ? 'selected="selected" ' : '';
|
385
|
+
var option = $('<option ' + selected + ' ></option>').val(value).text(text);
|
386
|
+
editor.append(option);
|
387
|
+
}
|
388
|
+
return editor;
|
389
|
+
|
390
|
+
},
|
391
|
+
|
392
|
+
// REFACT: rename opening is not what it's about. Its about closing events really
|
393
|
+
connectOpeningEventsToEditor: function() {
|
394
|
+
var that = this;
|
395
|
+
function cancelEditorAction(anEvent) {
|
396
|
+
that.handleCancelEditor(anEvent);
|
397
|
+
return false; // stop event bubbling
|
398
|
+
}
|
399
|
+
function saveEditorAction(anEvent) {
|
400
|
+
that.handleSaveEditor(anEvent);
|
401
|
+
return false; // stop event bubbling
|
402
|
+
}
|
403
|
+
|
404
|
+
var form = this.dom.find("form");
|
405
|
+
|
406
|
+
form.find(".inplace_field").focus().select();
|
407
|
+
form.find(".inplace_cancel").click(cancelEditorAction);
|
408
|
+
form.find(".inplace_save").click(saveEditorAction);
|
409
|
+
|
410
|
+
if ( ! this.settings.show_buttons) {
|
411
|
+
// TODO: Firefox has a bug where blur is not reliably called when focus is lost
|
412
|
+
// (for example by another editor appearing)
|
413
|
+
if ("save" === this.settings.on_blur)
|
414
|
+
form.find(".inplace_field").blur(saveEditorAction);
|
415
|
+
else
|
416
|
+
form.find(".inplace_field").blur(cancelEditorAction);
|
417
|
+
|
418
|
+
// workaround for firefox bug where it won't submit on enter if no button is shown
|
419
|
+
if ($.browser.mozilla)
|
420
|
+
this.bindSubmitOnEnterInInput();
|
421
|
+
}
|
422
|
+
|
423
|
+
form.keyup(function(anEvent) {
|
424
|
+
// allow canceling with escape
|
425
|
+
var escape = 27;
|
426
|
+
if (escape === anEvent.which)
|
427
|
+
return cancelEditorAction();
|
428
|
+
});
|
429
|
+
|
430
|
+
// workaround for webkit nightlies where they won't submit at all on enter
|
431
|
+
// REFACT: find a way to just target the nightlies
|
432
|
+
if ($.browser.safari)
|
433
|
+
this.bindSubmitOnEnterInInput();
|
434
|
+
|
435
|
+
|
436
|
+
form.submit(saveEditorAction);
|
437
|
+
},
|
438
|
+
|
439
|
+
bindSubmitOnEnterInInput: function() {
|
440
|
+
if ('textarea' === this.settings.field_type)
|
441
|
+
return; // can't enter newlines otherwise
|
442
|
+
|
443
|
+
var that = this;
|
444
|
+
this.dom.find(':input').keyup(function(event) {
|
445
|
+
var enter = 13;
|
446
|
+
if (enter === event.which)
|
447
|
+
return that.dom.find('form').submit();
|
448
|
+
});
|
449
|
+
|
450
|
+
},
|
451
|
+
|
452
|
+
handleCancelEditor: function(anEvent) {
|
453
|
+
// REFACT: remove duplication between save and cancel
|
454
|
+
if (false === this.triggerDelegateCall('shouldCloseEditInPlace', true, anEvent))
|
455
|
+
return;
|
456
|
+
|
457
|
+
var editor = this.dom.find(':input');
|
458
|
+
|
459
|
+
var enteredText = editor.val();
|
460
|
+
enteredText = this.triggerDelegateCall('willCloseEditInPlace', enteredText);
|
461
|
+
|
462
|
+
this.restoreOriginalValue();
|
463
|
+
if (hasContent(enteredText)
|
464
|
+
&& ! this.isDisabledDefaultSelectChoice() && !editor.is('select'))
|
465
|
+
this.setClosedEditorContent(enteredText);
|
466
|
+
this.reinit();
|
467
|
+
},
|
468
|
+
|
469
|
+
handleSaveEditor: function(anEvent) {
|
470
|
+
if (false === this.triggerDelegateCall('shouldCloseEditInPlace', true, anEvent))
|
471
|
+
return;
|
472
|
+
|
473
|
+
var editor = this.dom.find(':input:not(:button)');
|
474
|
+
var enteredText = '';
|
475
|
+
if (editor.length > 1) {
|
476
|
+
enteredText = jQuery.map(editor.not('input:checkbox:not(:checked)'), function(item, index) {
|
477
|
+
return $(item).val();
|
478
|
+
});
|
479
|
+
} else {
|
480
|
+
enteredText = editor.val();
|
481
|
+
}
|
482
|
+
enteredText = this.triggerDelegateCall('willCloseEditInPlace', enteredText);
|
483
|
+
|
484
|
+
if (this.isDisabledDefaultSelectChoice()
|
485
|
+
|| this.isUnchangedInput(enteredText)) {
|
486
|
+
this.handleCancelEditor(anEvent);
|
487
|
+
return;
|
488
|
+
}
|
489
|
+
|
490
|
+
if (this.didForgetRequiredText(enteredText)) {
|
491
|
+
this.handleCancelEditor(anEvent);
|
492
|
+
this.reportError("Error: You must enter a value to save this field");
|
493
|
+
return;
|
494
|
+
}
|
495
|
+
|
496
|
+
this.showSaving(enteredText);
|
497
|
+
|
498
|
+
if (this.settings.callback)
|
499
|
+
this.handleSubmitToCallback(enteredText);
|
500
|
+
else
|
501
|
+
this.handleSubmitToServer(enteredText);
|
502
|
+
},
|
503
|
+
|
504
|
+
didForgetRequiredText: function(enteredText) {
|
505
|
+
return this.settings.value_required
|
506
|
+
&& ("" === enteredText
|
507
|
+
|| undefined === enteredText
|
508
|
+
|| null === enteredText);
|
509
|
+
},
|
510
|
+
|
511
|
+
isDisabledDefaultSelectChoice: function() {
|
512
|
+
return this.dom.find('option').eq(0).is(':selected:disabled');
|
513
|
+
},
|
514
|
+
|
515
|
+
isUnchangedInput: function(enteredText) {
|
516
|
+
return ! this.settings.save_if_nothing_changed
|
517
|
+
&& this.originalValue === enteredText;
|
518
|
+
},
|
519
|
+
|
520
|
+
showSaving: function(enteredText) {
|
521
|
+
if (this.settings.callback && this.settings.callback_skip_dom_reset)
|
522
|
+
return;
|
523
|
+
|
524
|
+
var savingMessage = enteredText;
|
525
|
+
if (hasContent(this.settings.saving_text))
|
526
|
+
savingMessage = this.settings.saving_text;
|
527
|
+
if(hasContent(this.settings.saving_image))
|
528
|
+
// REFACT: alt should be the configured saving message
|
529
|
+
savingMessage = $('<img />').attr('src', this.settings.saving_image).attr('alt', savingMessage);
|
530
|
+
this.dom.html(savingMessage);
|
531
|
+
},
|
532
|
+
|
533
|
+
handleSubmitToCallback: function(enteredText) {
|
534
|
+
// REFACT: consider to encode enteredText and originalHTML before giving it to the callback
|
535
|
+
this.enableOrDisableAnimationCallbacks(true, false);
|
536
|
+
var newHTML = this.triggerCallback(this.settings.callback, /* DEPRECATED in 2.1.0 */ this.id(), enteredText, this.originalValue,
|
537
|
+
this.settings.params, this.savingAnimationCallbacks());
|
538
|
+
|
539
|
+
if (this.settings.callback_skip_dom_reset)
|
540
|
+
; // do nothing
|
541
|
+
else if (undefined === newHTML) {
|
542
|
+
// failure; put original back
|
543
|
+
this.reportError("Error: Failed to save value: " + enteredText);
|
544
|
+
this.restoreOriginalValue();
|
545
|
+
}
|
546
|
+
else
|
547
|
+
// REFACT: use setClosedEditorContent
|
548
|
+
this.dom.html(newHTML);
|
549
|
+
|
550
|
+
if (this.didCallNoCallbacks()) {
|
551
|
+
this.enableOrDisableAnimationCallbacks(false, false);
|
552
|
+
this.reinit();
|
553
|
+
}
|
554
|
+
},
|
555
|
+
|
556
|
+
handleSubmitToServer: function(enteredText) {
|
557
|
+
var data = '';
|
558
|
+
if (typeof(enteredText) === 'string') {
|
559
|
+
data += this.settings.update_value + '=' + encodeURIComponent(enteredText) + '&';
|
560
|
+
} else {
|
561
|
+
for(var i = 0;i < enteredText.length; i++) {
|
562
|
+
data += this.settings.update_value + '[]=' + encodeURIComponent(enteredText[i]) + '&';
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
data += this.settings.element_id + '=' + this.dom.attr("id")
|
567
|
+
+ ((this.settings.params) ? '&' + this.settings.params : '')
|
568
|
+
+ '&' + this.settings.original_html + '=' + encodeURIComponent(this.originalValue) /* DEPRECATED in 2.2.0 */
|
569
|
+
+ '&' + this.settings.original_value + '=' + encodeURIComponent(this.originalValue);
|
570
|
+
|
571
|
+
this.enableOrDisableAnimationCallbacks(true, false);
|
572
|
+
this.didStartSaving();
|
573
|
+
var that = this;
|
574
|
+
$.ajax({
|
575
|
+
url: that.settings.url,
|
576
|
+
type: "POST",
|
577
|
+
data: data,
|
578
|
+
dataType: that.settings.ajax_data_type,
|
579
|
+
complete: function(request){
|
580
|
+
that.didEndSaving();
|
581
|
+
},
|
582
|
+
success: function(data){
|
583
|
+
if (that.settings.ajax_data_type == 'html') {
|
584
|
+
var new_text = data || that.settings.default_text;
|
585
|
+
|
586
|
+
/* put the newly updated info into the original element */
|
587
|
+
// FIXME: should be affected by the preferences switch
|
588
|
+
that.dom.html(new_text);
|
589
|
+
// REFACT: remove dom parameter, already in this, not documented, should be easy to remove
|
590
|
+
// REFACT: callback should be able to override what gets put into the DOM
|
591
|
+
}
|
592
|
+
that.triggerCallback(that.settings.success,data);
|
593
|
+
},
|
594
|
+
error: function(request) {
|
595
|
+
that.dom.html(that.originalHTML); // REFACT: what about a restorePreEditingContent()
|
596
|
+
if (that.settings.error)
|
597
|
+
// REFACT: remove dom parameter, already in this, not documented, can remove without deprecation
|
598
|
+
// REFACT: callback should be able to override what gets entered into the DOM
|
599
|
+
that.triggerCallback(that.settings.error, request);
|
600
|
+
else
|
601
|
+
that.reportError("Failed to save value: " + request.responseText || 'Unspecified Error');
|
602
|
+
}
|
603
|
+
});
|
604
|
+
},
|
605
|
+
|
606
|
+
// Utilities .........................................................
|
607
|
+
|
608
|
+
triggerCallback: function(aCallback /*, arguments */) {
|
609
|
+
if ( ! aCallback)
|
610
|
+
return; // callback wasn't specified after all
|
611
|
+
|
612
|
+
var callbackArguments = Array.prototype.splice.call(arguments, 1);
|
613
|
+
return aCallback.apply(this.dom[0], callbackArguments);
|
614
|
+
},
|
615
|
+
|
616
|
+
/// defaultReturnValue is only used if the delegate returns undefined
|
617
|
+
triggerDelegateCall: function(aDelegateMethodName, defaultReturnValue, optionalEvent) {
|
618
|
+
// REFACT: consider to trigger equivalent callbacks automatically via a mapping table?
|
619
|
+
if ( ! this.settings.delegate
|
620
|
+
|| ! $.isFunction(this.settings.delegate[aDelegateMethodName]))
|
621
|
+
return defaultReturnValue;
|
622
|
+
|
623
|
+
var delegateReturnValue = this.settings.delegate[aDelegateMethodName](this.dom, this.settings, optionalEvent);
|
624
|
+
return (undefined === delegateReturnValue)
|
625
|
+
? defaultReturnValue
|
626
|
+
: delegateReturnValue;
|
627
|
+
},
|
628
|
+
|
629
|
+
reportError: function(anErrorString) {
|
630
|
+
this.triggerCallback(this.settings.error_sink, /* DEPRECATED in 2.1.0 */ this.id(), anErrorString);
|
631
|
+
},
|
632
|
+
|
633
|
+
// REFACT: this method should go, callbacks should get the dom node itself as an argument
|
634
|
+
id: function() {
|
635
|
+
return this.dom.attr('id');
|
636
|
+
},
|
637
|
+
|
638
|
+
markEditorAsActive: function() {
|
639
|
+
this.dom.addClass('editInPlace-active');
|
640
|
+
},
|
641
|
+
|
642
|
+
markEditorAsInactive: function() {
|
643
|
+
this.dom.removeClass('editInPlace-active');
|
644
|
+
},
|
645
|
+
|
646
|
+
// REFACT: consider rename, doesn't deal with animation directly
|
647
|
+
savingAnimationCallbacks: function() {
|
648
|
+
var that = this;
|
649
|
+
return {
|
650
|
+
didStartSaving: function() { that.didStartSaving(); },
|
651
|
+
didEndSaving: function() { that.didEndSaving(); }
|
652
|
+
};
|
653
|
+
},
|
654
|
+
|
655
|
+
enableOrDisableAnimationCallbacks: function(shouldEnableStart, shouldEnableEnd) {
|
656
|
+
this.didStartSaving.enabled = shouldEnableStart;
|
657
|
+
this.didEndSaving.enabled = shouldEnableEnd;
|
658
|
+
},
|
659
|
+
|
660
|
+
didCallNoCallbacks: function() {
|
661
|
+
return this.didStartSaving.enabled && ! this.didEndSaving.enabled;
|
662
|
+
},
|
663
|
+
|
664
|
+
assertCanCall: function(methodName) {
|
665
|
+
if ( ! this[methodName].enabled)
|
666
|
+
throw new Error('Cannot call ' + methodName + ' now. See documentation for details.');
|
667
|
+
},
|
668
|
+
|
669
|
+
didStartSaving: function() {
|
670
|
+
this.assertCanCall('didStartSaving');
|
671
|
+
this.shouldDelayReinit = true;
|
672
|
+
this.enableOrDisableAnimationCallbacks(false, true);
|
673
|
+
|
674
|
+
this.startSavingAnimation();
|
675
|
+
},
|
676
|
+
|
677
|
+
didEndSaving: function() {
|
678
|
+
this.assertCanCall('didEndSaving');
|
679
|
+
this.shouldDelayReinit = false;
|
680
|
+
this.enableOrDisableAnimationCallbacks(false, false);
|
681
|
+
this.reinit();
|
682
|
+
|
683
|
+
this.stopSavingAnimation();
|
684
|
+
},
|
685
|
+
|
686
|
+
startSavingAnimation: function() {
|
687
|
+
var that = this;
|
688
|
+
this.dom
|
689
|
+
.animate({ backgroundColor: this.settings.saving_animation_color }, 400)
|
690
|
+
.animate({ backgroundColor: 'transparent'}, 400, 'swing', function(){
|
691
|
+
// In the tests animations are turned off - i.e they happen instantaneously.
|
692
|
+
// Hence we need to prevent this from becomming an unbounded recursion.
|
693
|
+
setTimeout(function(){ that.startSavingAnimation(); }, 10);
|
694
|
+
});
|
695
|
+
},
|
696
|
+
|
697
|
+
stopSavingAnimation: function() {
|
698
|
+
this.dom
|
699
|
+
.stop(true)
|
700
|
+
.css({backgroundColor: ''});
|
701
|
+
},
|
702
|
+
|
703
|
+
missingCommaErrorPreventer:''
|
704
|
+
});
|
705
|
+
|
706
|
+
|
707
|
+
|
708
|
+
// Private helpers .......................................................
|
709
|
+
|
710
|
+
function assertMandatorySettingsArePresent(options) {
|
711
|
+
// one of these needs to be non falsy
|
712
|
+
if (options.url || options.callback)
|
713
|
+
return;
|
714
|
+
|
715
|
+
throw new Error("Need to set either url: or callback: option for the inline editor to work.");
|
716
|
+
}
|
717
|
+
|
718
|
+
/* preload the loading icon if it is configured */
|
719
|
+
function preloadImage(anImageURL) {
|
720
|
+
if ('' === anImageURL)
|
721
|
+
return;
|
722
|
+
|
723
|
+
var loading_image = new Image();
|
724
|
+
loading_image.src = anImageURL;
|
725
|
+
}
|
726
|
+
|
727
|
+
function trim(aString) {
|
728
|
+
return aString
|
729
|
+
.replace(/^\s+/, '')
|
730
|
+
.replace(/\s+$/, '');
|
731
|
+
}
|
732
|
+
|
733
|
+
function hasContent(something) {
|
734
|
+
if (undefined === something || null === something)
|
735
|
+
return false;
|
736
|
+
|
737
|
+
if (0 === something.length)
|
738
|
+
return false;
|
739
|
+
|
740
|
+
return true;
|
741
|
+
}
|
742
|
+
|
743
|
+
})(jQuery);
|