Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatible with file input with remotipart gem #582

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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".
Expand Down Expand Up @@ -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
Expand Down
91 changes: 91 additions & 0 deletions lib/assets/javascripts/best_in_place.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(/&amp;/gi, '&');
}
Expand Down Expand Up @@ -105,6 +106,9 @@ BestInPlaceEditor.prototype = {
return true;
}

if (this.formType === "file") {
return true;
}
editor.ajax({
"type": this.requestMethod(),
"dataType": BestInPlaceEditor.defaults.ajaxDataType,
Expand Down Expand Up @@ -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);
}
}
};

Expand Down