jipe 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,454 @@
1
+ var Jipe = {};
2
+
3
+ Jipe.InPlaceEditor = Class.create();
4
+ Jipe.InPlaceEditor.defaultHighlightColor = "#FFFF99";
5
+ Jipe.InPlaceEditor.prototype = {
6
+ initialize: function(element, model, recordId, field, options) {
7
+ this.model = model;
8
+ this.recordId = recordId;
9
+ this.field = field;
10
+ this.element = $(element);
11
+
12
+ this.options = Object.extend({
13
+ paramName: "value",
14
+ okButton: true,
15
+ okText: "ok",
16
+ cancelLink: true,
17
+ cancelText: "cancel",
18
+ savingText: "Saving...",
19
+ clickToEditText: "Click to edit",
20
+ okText: "ok",
21
+ rows: 1,
22
+ onComplete: function(transport, element) {
23
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
24
+ },
25
+ onFailure: function(transport) {
26
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
27
+ },
28
+ callback: function(form) {
29
+ return Form.serialize(form);
30
+ },
31
+ handleLineBreaks: true,
32
+ loadingText: 'Loading...',
33
+ savingClassName: 'inplaceeditor-saving',
34
+ loadingClassName: 'inplaceeditor-loading',
35
+ formClassName: 'inplaceeditor-form',
36
+ highlightcolor: Jipe.InPlaceEditor.defaultHighlightColor,
37
+ highlightendcolor: "#FFFFFF",
38
+ externalControl: null,
39
+ submitOnBlur: false,
40
+ ajaxOptions: {},
41
+ evalScripts: false
42
+ }, options || {});
43
+
44
+ if(!this.options.formId && this.element.id) {
45
+ this.options.formId = this.element.id + "-inplaceeditor";
46
+ if ($(this.options.formId)) {
47
+ // there's already a form with that name, don't specify an id
48
+ this.options.formId = null;
49
+ }
50
+ }
51
+
52
+ if (this.options.externalControl) {
53
+ this.options.externalControl = $(this.options.externalControl);
54
+ }
55
+
56
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
57
+ if (!this.originalBackground) {
58
+ this.originalBackground = "transparent";
59
+ }
60
+
61
+ this.element.title = this.options.clickToEditText;
62
+
63
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
64
+ this.mouseoverListener = this.enterHover.bindAsEventListener(this);
65
+ this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
66
+ Event.observe(this.element, 'click', this.onclickListener);
67
+ Event.observe(this.element, 'mouseover', this.mouseoverListener);
68
+ Event.observe(this.element, 'mouseout', this.mouseoutListener);
69
+ if (this.options.externalControl) {
70
+ Event.observe(this.options.externalControl, 'click', this.onclickListener);
71
+ Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
72
+ Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
73
+ }
74
+
75
+ this.element.jipeEditor = this;
76
+ },
77
+ enterEditMode: function(evt) {
78
+ if (this.saving) return;
79
+ if (this.editing) return;
80
+ this.editing = true;
81
+ this.onEnterEditMode();
82
+ if (this.options.externalControl) {
83
+ Element.hide(this.options.externalControl);
84
+ }
85
+ Element.hide(this.element);
86
+ this.createForm();
87
+ this.element.parentNode.insertBefore(this.form, this.element);
88
+ // stop the event to avoid a page refresh in Safari
89
+ if (evt) {
90
+ Event.stop(evt);
91
+ }
92
+ return false;
93
+ },
94
+ createForm: function() {
95
+ this.form = document.createElement("form");
96
+ this.form.id = this.options.formId;
97
+ Element.addClassName(this.form, this.options.formClassName)
98
+ this.form.onsubmit = this.onSubmit.bind(this);
99
+
100
+ this.createEditField();
101
+
102
+ if (this.options.textarea) {
103
+ var br = document.createElement("br");
104
+ this.form.appendChild(br);
105
+ }
106
+
107
+ if (this.options.okButton) {
108
+ okButton = document.createElement("input");
109
+ okButton.type = "submit";
110
+ okButton.value = this.options.okText;
111
+ okButton.className = 'editor_ok_button';
112
+ this.form.appendChild(okButton);
113
+ }
114
+
115
+ if (this.options.cancelLink) {
116
+ cancelLink = document.createElement("a");
117
+ cancelLink.href = "#";
118
+ cancelLink.appendChild(document.createTextNode(this.options.cancelText));
119
+ cancelLink.onclick = this.onclickCancel.bind(this);
120
+ cancelLink.className = 'editor_cancel';
121
+ this.form.appendChild(cancelLink);
122
+ }
123
+ },
124
+ hasHTMLLineBreaks: function(string) {
125
+ if (!this.options.handleLineBreaks) return false;
126
+ return string.match(/<br/i) || string.match(/<p>/i);
127
+ },
128
+ convertHTMLLineBreaks: function(string) {
129
+ return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
130
+ },
131
+ createEditField: function() {
132
+ var text;
133
+ text = this.options.loadingText;
134
+
135
+ var obj = this;
136
+
137
+ if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
138
+ this.options.textarea = false;
139
+ var textField = document.createElement("input");
140
+ textField.obj = this;
141
+ textField.type = "text";
142
+ textField.name = this.options.paramName;
143
+ textField.value = text;
144
+ textField.style.backgroundColor = this.options.highlightcolor;
145
+ textField.className = 'editor_field';
146
+ var size = this.options.size || this.options.cols || 0;
147
+ if (size != 0) textField.size = size;
148
+ if (this.options.submitOnBlur)
149
+ textField.onblur = this.onSubmit.bind(this);
150
+ this.editField = textField;
151
+ } else {
152
+ this.options.textarea = true;
153
+ var textArea = document.createElement("textarea");
154
+ textArea.obj = this;
155
+ textArea.name = this.options.paramName;
156
+ textArea.value = this.convertHTMLLineBreaks(text);
157
+ textArea.rows = this.options.rows;
158
+ textArea.cols = this.options.cols || 40;
159
+ textArea.className = 'editor_field';
160
+ if (this.options.submitOnBlur)
161
+ textArea.onblur = this.onSubmit.bind(this);
162
+ this.editField = textArea;
163
+ }
164
+
165
+ this.loadExternalText();
166
+ this.form.appendChild(this.editField);
167
+ },
168
+ getText: function() {
169
+ return this.element.innerHTML;
170
+ },
171
+ loadExternalText: function() {
172
+ Element.addClassName(this.form, this.options.loadingClassName);
173
+ this.editField.disabled = true;
174
+ this.model.find(this.recordId,
175
+ this.options.ajaxOptionsOnLoad || this.options.ajaxOptions,
176
+ this.onLoadedExternalText.bind(this));
177
+ },
178
+ onLoadedExternalText: function(obj) {
179
+ this.record = obj;
180
+ Element.removeClassName(this.form, this.options.loadingClassName);
181
+ this.editField.disabled = false;
182
+ this.editField.value = obj[this.field];
183
+ Field.scrollFreeActivate(this.editField);
184
+ },
185
+ onclickCancel: function() {
186
+ this.onComplete();
187
+ this.leaveEditMode();
188
+ return false;
189
+ },
190
+ onFailure: function(transport) {
191
+ this.options.onFailure(transport);
192
+ if (this.oldInnerHTML) {
193
+ this.element.innerHTML = this.oldInnerHTML;
194
+ this.oldInnerHTML = null;
195
+ }
196
+ return false;
197
+ },
198
+ onSubmit: function() {
199
+ // onLoading resets these so we need to save them away for the Ajax call
200
+ var form = this.form;
201
+ var value = this.editField.value;
202
+
203
+ // do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
204
+ // which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
205
+ // to be displayed indefinitely
206
+ this.onLoading();
207
+
208
+ this.record[this.field] = value;
209
+
210
+ this.record.save(Object.extend({
211
+ // parameters: this.options.callback(form, value),
212
+ onComplete: this.onComplete.bind(this),
213
+ onFailure: this.onFailure.bind(this)
214
+ }, this.options.ajaxOptionsOnSubmit || this.options.ajaxOptions));
215
+
216
+ // stop the event to avoid a page refresh in Safari
217
+ if (arguments.length > 1) {
218
+ Event.stop(arguments[0]);
219
+ }
220
+ return false;
221
+ },
222
+ onLoading: function() {
223
+ this.saving = true;
224
+ this.removeForm();
225
+ this.leaveHover();
226
+ this.showSaving();
227
+ },
228
+ showSaving: function() {
229
+ this.oldInnerHTML = this.element.innerHTML;
230
+ this.element.innerHTML = this.options.savingText;
231
+ Element.addClassName(this.element, this.options.savingClassName);
232
+ this.element.style.backgroundColor = this.originalBackground;
233
+ Element.show(this.element);
234
+ },
235
+ removeForm: function() {
236
+ if(this.form) {
237
+ if (this.form.parentNode) Element.remove(this.form);
238
+ this.form = null;
239
+ }
240
+ },
241
+ enterHover: function() {
242
+ if (this.saving) return;
243
+ this.element.style.backgroundColor = this.options.highlightcolor;
244
+ if (this.effect) {
245
+ this.effect.cancel();
246
+ }
247
+ Element.addClassName(this.element, this.options.hoverClassName)
248
+ },
249
+ leaveHover: function() {
250
+ if (this.options.backgroundColor) {
251
+ this.element.style.backgroundColor = this.oldBackground;
252
+ }
253
+ Element.removeClassName(this.element, this.options.hoverClassName)
254
+ if (this.saving) return;
255
+ this.effect = new Effect.Highlight(this.element, {
256
+ startcolor: this.options.highlightcolor,
257
+ endcolor: this.options.highlightendcolor,
258
+ restorecolor: this.originalBackground
259
+ });
260
+ },
261
+ leaveEditMode: function() {
262
+ Element.removeClassName(this.element, this.options.savingClassName);
263
+ this.removeForm();
264
+ this.leaveHover();
265
+ this.element.style.backgroundColor = this.originalBackground;
266
+ Element.show(this.element);
267
+ if (this.options.externalControl) {
268
+ Element.show(this.options.externalControl);
269
+ }
270
+ this.editing = false;
271
+ this.saving = false;
272
+ this.element.innerHTML = this.record[this.field];
273
+ this.oldInnerHTML = null;
274
+ this.onLeaveEditMode();
275
+ },
276
+ onComplete: function(transport) {
277
+ this.leaveEditMode();
278
+ this.options.onComplete.bind(this)(transport, this.element);
279
+ },
280
+ onEnterEditMode: function() {},
281
+ onLeaveEditMode: function() {},
282
+ dispose: function() {
283
+ if (this.oldInnerHTML) {
284
+ this.element.innerHTML = this.oldInnerHTML;
285
+ }
286
+ this.leaveEditMode();
287
+ Event.stopObserving(this.element, 'click', this.onclickListener);
288
+ Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
289
+ Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
290
+ if (this.options.externalControl) {
291
+ Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
292
+ Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
293
+ Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
294
+ }
295
+ }
296
+ };
297
+
298
+ Jipe.SelectField = Class.create();
299
+ Jipe.SelectField.prototype = {
300
+ initialize: function(element, model, recordId, field, options) {
301
+ this.model = model;
302
+ this.recordId = recordId;
303
+ this.field = field;
304
+ this.element = $(element);
305
+
306
+ this.options = Object.extend({
307
+ onComplete: function(transport, element) {
308
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
309
+ },
310
+ onFailure: function(transport) {
311
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
312
+ },
313
+ savingClassName: 'selectfield-saving',
314
+ loadingClassName: 'selectfield-loading',
315
+ highlightcolor: Jipe.ImageToggle.defaultHighlightColor,
316
+ highlightendcolor: "#FFFFFF",
317
+ ajaxOptions: {},
318
+ evalScripts: false
319
+ }, options || {});
320
+
321
+ this.originalBackground = Element.getStyle(this.element, 'background-color');
322
+ if (!this.originalBackground) {
323
+ this.originalBackground = "transparent";
324
+ }
325
+
326
+ this.changeListener = function (event) { this.setState(this.element.value); }.bindAsEventListener(this);
327
+ Event.observe(this.element, 'change', this.changeListener);
328
+
329
+ //this.loadExternalState();
330
+ this.element.disabled = false;
331
+ },
332
+ loadExternalState: function() {
333
+ this.model.find(this.recordId,
334
+ this.options.ajaxOptionsOnLoad || this.options.ajaxOptions,
335
+ this.onLoadedExternalState.bind(this));
336
+ },
337
+ onLoadedExternalState: function(obj) {
338
+ this.record = obj;
339
+ this.setSelectValue(obj[this.field]);
340
+ },
341
+ setSelectValue: function(value) {
342
+ this.element.value = value;
343
+ },
344
+ onComplete: function(transport) {
345
+ this.element.disabled = false;
346
+ this.options.onComplete.bind(this)();
347
+ },
348
+ setState: function(state) {
349
+ this.element.disabled = true;
350
+ this.desiredState = state;
351
+ this.setSelectValue(this.desiredState);
352
+ this.model.find(this.recordId,
353
+ this.options.ajaxOptionsOnLoad || this.options.ajaxOptions,
354
+ this.setStateInner.bind(this));
355
+ },
356
+ setStateInner: function(record) {
357
+ this.record = record;
358
+ if (this.record[this.field] != this.desiredState) {
359
+ this.record[this.field] = this.desiredState;
360
+ this.record.save(this.onComplete.bind(this));
361
+ } else {
362
+ this.onComplete();
363
+ }
364
+ }
365
+ };
366
+
367
+ Jipe.ImageToggle = Class.create();
368
+ Jipe.ImageToggle.defaultHighlightColor = "#FFFF99";
369
+ Jipe.ImageToggle.prototype = {
370
+ initialize: function(trueElement, falseElement, model, recordId, field, options) {
371
+ this.model = model;
372
+ this.recordId = recordId;
373
+ this.field = field;
374
+ this.trueElement = $(trueElement);
375
+ this.falseElement = $(falseElement);
376
+
377
+ this.options = Object.extend({
378
+ onComplete: function(transport, element) {
379
+ new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
380
+ },
381
+ onFailure: function(transport) {
382
+ alert("Error communicating with the server: " + transport.responseText.stripTags());
383
+ },
384
+ savingClassName: 'imagetoggle-saving',
385
+ loadingClassName: 'imagetoggle-loading',
386
+ highlightcolor: Jipe.ImageToggle.defaultHighlightColor,
387
+ highlightendcolor: "#FFFFFF",
388
+ ajaxOptions: {},
389
+ evalScripts: false
390
+ }, options || {});
391
+
392
+ this.originalBackground = Element.getStyle(this.trueElement, 'background-color');
393
+ if (!this.originalBackground) {
394
+ this.originalBackground = "transparent";
395
+ }
396
+
397
+ this.trueClickListener = this.setFalse.bindAsEventListener(this);
398
+ this.falseClickListener = this.setTrue.bindAsEventListener(this);
399
+ Event.observe(this.trueElement, 'click', this.trueClickListener);
400
+ Event.observe(this.falseElement, 'click', this.falseClickListener);
401
+
402
+ //this.loadExternalState();
403
+ this.controlEnabled = true;
404
+ },
405
+ loadExternalState: function() {
406
+ this.model.find(this.recordId,
407
+ this.options.ajaxOptionsOnLoad || this.options.ajaxOptions,
408
+ this.onLoadedExternalState.bind(this));
409
+ },
410
+ onLoadedExternalState: function(obj) {
411
+ this.record = obj;
412
+ this.updateImage(obj[this.field]);
413
+ },
414
+ updateImage: function(state) {
415
+ if (state == "1" || state == "true") {
416
+ this.trueElement.show();
417
+ this.falseElement.hide();
418
+ } else {
419
+ this.falseElement.show();
420
+ this.trueElement.hide();
421
+ }
422
+ },
423
+ onComplete: function(transport) {
424
+ this.controlEnabled = true;
425
+ this.options.onComplete.bind(this)();
426
+ },
427
+ setFalse: function() {
428
+ if (this.controlEnabled) {
429
+ this.setState(false);
430
+ }
431
+ },
432
+ setTrue: function() {
433
+ if (this.controlEnabled) {
434
+ this.setState(true);
435
+ }
436
+ },
437
+ setState: function(state) {
438
+ this.controlEnabled = false;
439
+ this.desiredState = state;
440
+ this.updateImage(this.desiredState);
441
+ this.model.find(this.recordId,
442
+ this.options.ajaxOptionsOnLoad || this.options.ajaxOptions,
443
+ this.setStateInner.bind(this));
444
+ },
445
+ setStateInner: function(record) {
446
+ this.record = record;
447
+ if (this.record[this.field] != this.desiredState) {
448
+ this.record[this.field] = this.desiredState;
449
+ this.record.save(this.onComplete.bind(this));
450
+ } else {
451
+ this.onComplete();
452
+ }
453
+ }
454
+ };