var Jipe = {};
Jipe.InPlaceEditor = Class.create();
Jipe.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Jipe.InPlaceEditor.prototype = {
initialize: function(element, model, recordId, field, options) {
this.model = model;
this.recordId = recordId;
this.field = field;
this.element = $(element);
this.options = Object.extend({
paramName: "value",
okButton: true,
okText: "ok",
cancelLink: true,
cancelText: "cancel",
savingText: "Saving...",
clickToEditText: "Click to edit",
okText: "ok",
rows: 1,
onComplete: function(transport, element) {
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
},
onFailure: function(transport) {
alert("Error communicating with the server: " + transport.responseText.stripTags());
},
callback: function(form) {
return Form.serialize(form);
},
handleLineBreaks: true,
loadingText: 'Loading...',
savingClassName: 'inplaceeditor-saving',
loadingClassName: 'inplaceeditor-loading',
formClassName: 'inplaceeditor-form',
highlightcolor: Jipe.InPlaceEditor.defaultHighlightColor,
highlightendcolor: "#FFFFFF",
externalControl: null,
submitOnBlur: false,
ajaxOptions: {},
evalScripts: false,
authenticityToken: null
}, options || {});
if(!this.options.formId && this.element.id) {
this.options.formId = this.element.id + "-inplaceeditor";
if ($(this.options.formId)) {
// there's already a form with that name, don't specify an id
this.options.formId = null;
}
}
if (this.options.externalControl) {
this.options.externalControl = $(this.options.externalControl);
}
this.originalBackground = Element.getStyle(this.element, 'background-color');
if (!this.originalBackground) {
this.originalBackground = "transparent";
}
this.element.title = this.options.clickToEditText;
this.onclickListener = this.enterEditMode.bindAsEventListener(this);
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
Event.observe(this.element, 'click', this.onclickListener);
Event.observe(this.element, 'mouseover', this.mouseoverListener);
Event.observe(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.observe(this.options.externalControl, 'click', this.onclickListener);
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
},
enterEditMode: function(evt) {
if (this.saving) return;
if (this.editing) return;
this.editing = true;
this.onEnterEditMode();
if (this.options.externalControl) {
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
// stop the event to avoid a page refresh in Safari
if (evt) {
Event.stop(evt);
}
return false;
},
createForm: function() {
this.form = document.createElement("form");
this.form.id = this.options.formId;
Element.addClassName(this.form, this.options.formClassName)
this.form.onsubmit = this.onSubmit.bind(this);
this.createEditField();
if (this.options.textarea) {
var br = document.createElement("br");
this.form.appendChild(br);
}
if (this.options.okButton) {
okButton = document.createElement("input");
okButton.type = "submit";
okButton.value = this.options.okText;
okButton.className = 'editor_ok_button';
this.form.appendChild(okButton);
}
if (this.options.cancelLink) {
cancelLink = document.createElement("a");
cancelLink.href = "#";
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = 'editor_cancel';
this.form.appendChild(cancelLink);
}
},
hasHTMLLineBreaks: function(string) {
if (!this.options.handleLineBreaks) return false;
return string.match(/
/i);
},
convertHTMLLineBreaks: function(string) {
return string.replace(/
/gi, "\n").replace(/
/gi, "\n").replace(/<\/p>/gi, "\n").replace(/
/gi, ""); }, createEditField: function() { var text; text = this.options.loadingText; var obj = this; if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { this.options.textarea = false; var textField = document.createElement("input"); textField.obj = this; textField.type = "text"; textField.name = this.options.paramName; textField.value = text; textField.style.backgroundColor = this.options.highlightcolor; textField.className = 'editor_field'; var size = this.options.size || this.options.cols || 0; if (size != 0) textField.size = size; if (this.options.submitOnBlur) textField.onblur = this.onSubmit.bind(this); this.editField = textField; } else { this.options.textarea = true; var textArea = document.createElement("textarea"); textArea.obj = this; textArea.name = this.options.paramName; textArea.value = this.convertHTMLLineBreaks(text); textArea.rows = this.options.rows; textArea.cols = this.options.cols || 40; textArea.className = 'editor_field'; if (this.options.submitOnBlur) textArea.onblur = this.onSubmit.bind(this); this.editField = textArea; } this.loadExternalText(); this.form.appendChild(this.editField); }, getText: function() { return this.element.innerHTML; }, loadExternalText: function() { Element.addClassName(this.form, this.options.loadingClassName); this.editField.disabled = true; this.model.find(this.recordId, this.options.ajaxOptionsOnLoad || this.options.ajaxOptions, this.onLoadedExternalText.bind(this)); }, onLoadedExternalText: function(obj) { this.record = obj; Element.removeClassName(this.form, this.options.loadingClassName); this.editField.disabled = false; this.editField.value = obj[this.field]; Field.scrollFreeActivate(this.editField); }, onclickCancel: function() { this.onComplete(); this.leaveEditMode(); return false; }, onFailure: function(transport) { this.options.onFailure(transport); if (this.oldInnerHTML) { this.element.innerHTML = this.oldInnerHTML; this.oldInnerHTML = null; } return false; }, onSubmit: function() { // onLoading resets these so we need to save them away for the Ajax call var form = this.form; var value = this.editField.value; // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... // to be displayed indefinitely this.onLoading(); this.record[this.field] = value; extraUrlParams = {}; if (this.options.authenticityToken) { extraUrlParams.authenticity_token = this.options.authenticityToken; } this.record.save(extraUrlParams, Object.extend({ // parameters: this.options.callback(form, value), onComplete: this.onComplete.bind(this), onFailure: this.onFailure.bind(this) }, this.options.ajaxOptionsOnSubmit || this.options.ajaxOptions)); // stop the event to avoid a page refresh in Safari if (arguments.length > 1) { Event.stop(arguments[0]); } return false; }, onLoading: function() { this.saving = true; this.removeForm(); this.leaveHover(); this.showSaving(); }, showSaving: function() { this.oldInnerHTML = this.element.innerHTML; this.element.innerHTML = this.options.savingText; Element.addClassName(this.element, this.options.savingClassName); this.element.style.backgroundColor = this.originalBackground; Element.show(this.element); }, removeForm: function() { if(this.form) { if (this.form.parentNode) Element.remove(this.form); this.form = null; } }, enterHover: function() { if (this.saving) return; this.element.style.backgroundColor = this.options.highlightcolor; if (this.effect) { this.effect.cancel(); } Element.addClassName(this.element, this.options.hoverClassName) }, leaveHover: function() { if (this.options.backgroundColor) { this.element.style.backgroundColor = this.oldBackground; } Element.removeClassName(this.element, this.options.hoverClassName) if (this.saving) return; this.effect = new Effect.Highlight(this.element, { startcolor: this.options.highlightcolor, endcolor: this.options.highlightendcolor, restorecolor: this.originalBackground }); }, leaveEditMode: function() { Element.removeClassName(this.element, this.options.savingClassName); this.removeForm(); this.leaveHover(); this.element.style.backgroundColor = this.originalBackground; Element.show(this.element); if (this.options.externalControl) { Element.show(this.options.externalControl); } this.editing = false; this.saving = false; this.element.innerHTML = this.record[this.field]; this.oldInnerHTML = null; this.onLeaveEditMode(); }, onComplete: function(transport) { this.leaveEditMode(); this.options.onComplete.bind(this)(transport, this.element); }, onEnterEditMode: function() {}, onLeaveEditMode: function() {}, dispose: function() { if (this.oldInnerHTML) { this.element.innerHTML = this.oldInnerHTML; } this.leaveEditMode(); Event.stopObserving(this.element, 'click', this.onclickListener); Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); if (this.options.externalControl) { Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); } } }; Jipe.ImageToggle = Class.create(); Jipe.ImageToggle.defaultHighlightColor = "#FFFF99"; Jipe.ImageToggle.prototype = { initialize: function(trueElement, falseElement, model, recordId, field, options) { this.model = model; this.recordId = recordId; this.field = field; this.trueElement = $(trueElement); this.falseElement = $(falseElement); this.options = Object.extend({ onComplete: function(transport, element) { new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); }, onFailure: function(transport) { alert("Error communicating with the server: " + transport.responseText.stripTags()); }, savingClassName: 'imagetoggle-saving', loadingClassName: 'imagetoggle-loading', highlightcolor: Jipe.ImageToggle.defaultHighlightColor, highlightendcolor: "#FFFFFF", ajaxOptions: {}, evalScripts: false, authenticityToken: null }, options || {}); this.originalBackground = Element.getStyle(this.trueElement, 'background-color'); if (!this.originalBackground) { this.originalBackground = "transparent"; } this.trueClickListener = this.setFalse.bindAsEventListener(this); this.falseClickListener = this.setTrue.bindAsEventListener(this); Event.observe(this.trueElement, 'click', this.trueClickListener); Event.observe(this.falseElement, 'click', this.falseClickListener); //this.loadExternalState(); this.controlEnabled = true; }, loadExternalState: function() { this.model.find(this.recordId, this.options.ajaxOptionsOnLoad || this.options.ajaxOptions, this.onLoadedExternalState.bind(this)); }, onLoadedExternalState: function(obj) { this.record = obj; this.updateImage(obj[this.field]); }, updateImage: function(state) { if (state == "1" || state == "true") { this.trueElement.show(); this.falseElement.hide(); } else { this.falseElement.show(); this.trueElement.hide(); } }, onComplete: function(transport) { this.controlEnabled = true; this.options.onComplete.bind(this)(); }, setFalse: function() { if (this.controlEnabled) { this.setState(false); } }, setTrue: function() { if (this.controlEnabled) { this.setState(true); } }, setState: function(state) { this.controlEnabled = false; this.desiredState = state; this.updateImage(this.desiredState); this.model.find(this.recordId, this.options.ajaxOptionsOnLoad || this.options.ajaxOptions, this.setStateInner.bind(this)); }, setStateInner: function(record) { this.record = record; if (this.record[this.field] != this.desiredState) { this.record[this.field] = this.desiredState; extraUrlOptions = {}; if (this.options.authenticityToken) { extraUrlOptions.authenticity_token = this.options.authenticityToken; } this.record.save(extraUrlOptions, this.onComplete.bind(this)); } else { this.onComplete(); } } };