From 77e48e2d104b9016ccbf950ea8f04bc45d0d57b8 Mon Sep 17 00:00:00 2001 From: Yuki SHIDA Date: Fri, 7 Jul 2017 12:24:36 +0900 Subject: [PATCH] Compatible with file input with remotipart gem --- README.md | 15 +++- lib/assets/javascripts/best_in_place.js | 91 +++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb442c07..1ddb62cc 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ You are done! - Compatible with **select** dropdown with custom collections - Compatible with custom boolean values (same usage of **checkboxes**) - Compatible with **jQuery UI Datepickers** +- Compatible with file **input** with **remotipart gem** - Sanitize HTML and trim spaces of user's input on user's choice - Displays server-side **validation** errors - Allows external activator @@ -74,7 +75,7 @@ Params: Options: -- **:as** It can be only [:input, :textarea, :select, :checkbox, :date] or if undefined it defaults to :input. +- **:as** It can be only [:input, :textarea, :select, :checkbox, :date, :file] or if undefined it defaults to :input. - **:collection**: If you are using the :select type then you must specify the collection of values it takes as a hash where values represent the display text and keys are the option's value when selected. If you are using the :checkbox type you can specify the two values it can take, or otherwise they will default to Yes and No. - **:url**: URL to which the updating action will be sent. If not defined it defaults to the :object path. - **:place_holder**: The nil param defines the content displayed in case no value is defined for that field. It can be something like "click me to edit". @@ -181,6 +182,18 @@ prepare a `$.datepicker.setDefaults` call with the preferences of your choice. More information about datepicker and setting defaults can be found [here](http://docs.jquery.com/UI/Datepicker/$.datepicker.setDefaults) +### File + + <%= best_in_place @user, :image, :as => :file %> + +In order to upload files using Ajax you need to install "remotipart gem". + + gem 'remotipart', '~> 1.2' + +With the :file type, OK and Cancel buttons is always displayed. +If you not specify **:ok_button** option, "OK" button is displayed, +and similarly, "Cancel" button is displayed. + ## Controller response with respond_with_bip Best in place provides a utility method you should use in your controller in diff --git a/lib/assets/javascripts/best_in_place.js b/lib/assets/javascripts/best_in_place.js index a6184f16..3cb06fb8 100644 --- a/lib/assets/javascripts/best_in_place.js +++ b/lib/assets/javascripts/best_in_place.js @@ -44,6 +44,7 @@ BestInPlaceEditor.prototype = { switch (this.formType) { case 'input': case 'textarea': + case 'file': if (this.display_raw) { to_display = this.element.html().replace(/&/gi, '&'); } @@ -105,6 +106,9 @@ BestInPlaceEditor.prototype = { return true; } + if (this.formType === "file") { + return true; + } editor.ajax({ "type": this.requestMethod(), "dataType": BestInPlaceEditor.defaults.ajaxDataType, @@ -640,6 +644,93 @@ BestInPlaceEditor.forms = { event.data.editor.abortIfConfirm(); } } + }, + + "file": { + activateForm: function () { + 'use strict'; + var output = jQuery(document.createElement('form')) + .addClass('form_in_place') + .attr('action', this.url) + .attr('style', 'display:inline') + .attr('accept-charset', 'UTF-8') + .attr('data-remote', 'true') + .attr('data-type', "json") + .attr('method', 'post') + .attr('enctype', 'multipart/form-data'); + var input_elt = jQuery(document.createElement('input')) + .attr('type', 'file') + .attr('name', this.objectName + '[' + this.attributeName + ']'); + var input_method = jQuery(document.createElement('input')) + .attr('type', 'hidden') + .attr('name', "_method") + .attr('value', this.requestMethod()); + + // Add class to form input + if (this.inner_class) { + input_elt.addClass(this.inner_class); + } + + output.append(input_method); + output.append(input_elt); + if (! this.okButton) { + this.okButton = "OK" + } + if (! this.cancelButton) { + this.okButton = "Cancel" + } + this.placeButtons(output, this); + + this.element.html(output); + this.setHtmlAttributes(); + + + this.element.find("input[type='file']")[0].select(); + this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.file.submitHandler); + this.element.find("form").bind('ajax:remotipartComplete', {editor: this}, BestInPlaceEditor.forms.file.ajaxSuccessHandler); + this.element.find("form").bind('ajax:error', {editor: this}, BestInPlaceEditor.forms.file.ajaxErrorHandler); + + if (this.cancelButton) { + this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler); + } + this.blurTimer = null; + this.userClicked = false; + }, + + getValue: function () { + 'use strict'; + return this.sanitizeValue(this.element.find("input").val()); + }, + + submitHandler: function (event) { + 'use strict'; + if (event.data.editor.userClicked) { + event.data.editor.abort(); + } + event.data.editor.userClicked = true; + clearTimeout(event.data.editor.blurTimer); + event.data.editor.update(); + }, + + cancelButtonHandler: function (event) { + 'use strict'; + event.data.editor.userClicked = true; + clearTimeout(event.data.editor.blurTimer); + event.data.editor.abort(); + event.stopPropagation(); // Without this, click isn't handled + }, + + ajaxSuccessHandler: function (event, xhr) { + 'use strict'; + var data = xhr.responseText; + var status = xhr.status; + event.data.editor.loadSuccessCallback(data, status, xhr) + }, + + ajaxErrorHandler: function (event, xhr, ajaxSettings, thrownError) { + 'use strict'; + event.data.editor.loadErrorCallback(xhr, ajaxSettings); + } } };