Project

General

Profile

Statistics
| Branch: | Revision:

root / docs / www / colonyscout / internal / jeditable / js / jquery.jeditable.js @ f59acf11

History | View | Annotate | Download (16.1 KB)

1
/*
2
+-----------------------------------------------------------------------+
3
| Copyright (c) 2006-2007 Mika Tuupola, Dylan Verheul                   |
4
| All rights reserved.                                                  |  
5
|                                                                       |
6
| Redistribution and use in source and binary forms, with or without    |
7
| modification, are permitted provided that the following conditions    |
8
| are met:                                                              |
9
|                                                                       | 
10
| o Redistributions of source code must retain the above copyright      |
11
|   notice, this list of conditions and the following disclaimer.       |
12
| o Redistributions in binary form must reproduce the above copyright   |
13
|   notice, this list of conditions and the following disclaimer in the |
14
|   documentation and/or other materials provided with the distribution.|
15
|                                                                       |
16
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
17
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
18
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
20
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
22
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
25
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
27
|                                                                       |
28
+-----------------------------------------------------------------------+
29
*/
30

    
31
/* $Id: jquery.jeditable.js 235 2007-09-25 08:34:09Z tuupola $ */
32

    
33
/**
34
  * jQuery inplace editor plugin (version 1.4.2)
35
  *
36
  * Based on editable by Dylan Verheul <dylan@dyve.net>
37
  * http://www.dyve.net/jquery/?editable
38
  *
39
  * @name  jEditable
40
  * @type  jQuery
41
  * @param String  target             POST URL or function name to send edited content
42
  * @param Hash    options            additional options 
43
  * @param String  options[name]      POST parameter name of edited content
44
  * @param String  options[id]        POST parameter name of edited div id
45
  * @param Hash    options[submitdata] Extra parameters to send when submitting edited content.
46
  * @param String  options[type]      text, textarea or select
47
  * @param Integer options[rows]      number of rows if using textarea
48
  * @param Integer options[cols]      number of columns if using textarea
49
  * @param Mixed   options[height]    'auto', 'none' or height in pixels
50
  * @param Mixed   options[width]     'auto', 'none' or width in pixels 
51
  * @param String  options[loadurl]   URL to fetch external content before editing
52
  * @param String  options[loadtype]  Request type for load url. Should be GET or POST.
53
  * @param String  options[loadtext]  Text to display while loading external content.
54
  * @param Hash    options[loaddata]  Extra parameters to pass when fetching content before editing.
55
  * @param String  options[data]      Or content given as paramameter.
56
  * @param String  options[indicator] indicator html to show when saving
57
  * @param String  options[tooltip]   optional tooltip text via title attribute
58
  * @param String  options[event]     jQuery event such as 'click' of 'dblclick'
59
  * @param String  options[onblur]    'cancel', 'submit' or 'ignore'
60
  * @param String  options[submit]    submit button value, empty means no button
61
  * @param String  options[cancel]    cancel button value, empty means no button
62
  * @param String  options[cssclass]  CSS class to apply to input form. 'inherit' to copy from parent.
63
  * @param String  options[style]     Style to apply to input form 'inherit' to copy from parent.
64
  * @param String  options[select]    true or false, when true text is highlighted
65
  *             
66
  */
67

    
68
jQuery.fn.editable = function(target, options, callback) {
69

    
70
    /* prevent elem has no properties error */
71
    if (this.length === 0) { 
72
        return(this); 
73
    }
74
    
75
    var settings = {
76
        target     : target,
77
        name       : 'value',
78
        id         : 'id',
79
        type       : 'text',
80
        width      : 'auto',
81
        height     : 'auto',
82
        event      : 'click',
83
        onblur     : 'cancel',
84
        loadtype   : 'GET',
85
        loadtext   : 'Loading...',
86
        loaddata   : {},
87
        submitdata : {}
88
    };
89
        
90
    if(options) {
91
        jQuery.extend(settings, options);
92
    }
93
    
94
    /* setup some functions */
95
    var plugin   = jQuery.editable.types[settings.type].plugin || function() { };
96
    var submit   = jQuery.editable.types[settings.type].submit || function() { };
97
    var buttons  = jQuery.editable.types[settings.type].buttons 
98
                || jQuery.editable.types['defaults'].buttons;
99
    var content  = jQuery.editable.types[settings.type].content 
100
                || jQuery.editable.types['defaults'].content;
101
    var element  = jQuery.editable.types[settings.type].element 
102
                || jQuery.editable.types['defaults'].element;
103

    
104
    callback = callback || function() { };
105
          
106
    jQuery(this).attr('title', settings.tooltip);
107

    
108
    /* temporary fix for auto width and height */
109
    settings.autowidth  = 'auto' == settings.width;
110
    settings.autoheight = 'auto' == settings.height;
111
                
112
    jQuery(this)[settings.event](function(e) {
113

    
114
        /* save this to self because this changes when scope changes */
115
        var self = this;
116

    
117
        /* prevent throwing an exeption if edit field is clicked again */
118
        if (self.editing) {
119
            return;
120
        }
121

    
122
        /* figure out how wide and tall we are */
123
        if (settings.width != 'none') {
124
            settings.width = 
125
               settings.autowidth ? jQuery(self).width()  : settings.width;
126
        }
127
        if (settings.height != 'none') {
128
            settings.height = 
129
                settings.autoheight ? jQuery(self).height() : settings.height;
130
        }
131
                
132
        self.editing    = true;
133
        self.revert     = jQuery(self).html();
134
        self.innerHTML  = '';
135

    
136
        /* create the form object */
137
        var f = document.createElement('form');
138
        
139
        /* apply css or style or both */
140
        if (settings.cssclass) {
141
            if ('inherit' == settings.cssclass) {
142
                jQuery(f).attr('class', jQuery(self).attr('class'));
143
            } else {
144
                jQuery(f).attr('class', settings.cssclass);
145
            }
146
        }
147
        
148
        if (settings.style) {
149
            if ('inherit' == settings.style) {
150
                jQuery(f).attr('style', jQuery(self).attr('style'));
151
                /* IE needs the second line or display wont be inherited */
152
                jQuery(f).css('display', jQuery(self).css('display'));                
153
            } else {
154
                jQuery(f).attr('style', settings.style);
155
            }
156
        }
157
        
158
        /*  Add main input element to form and store it in i. */
159
        var i = element.apply(f, [settings, self]);
160

    
161
        /* maintain bc with 1.1.1 and earlier versions */        
162
        if (settings.getload) {
163
            settings.loadurl    = settings.getload;
164
            settings.loadtype = 'GET';
165
        } else if (settings.postload) {
166
            settings.loadurl    = settings.postload;
167
            settings.loadtype = 'POST';
168
        }
169

    
170
        /* set input content via POST, GET, given data or existing value */
171
        if (settings.loadurl) {
172
            var t = setTimeout(function() {
173
                i.disabled = true;
174
                content.apply(f, [settings.loadtext, settings, self]);
175
            }, 100);
176
                
177
            var loaddata = {};
178
            loaddata[settings.id] = self.id;
179
            if (jQuery.isFunction(settings.loaddata)) {
180
                jQuery.extend(loaddata, settings.loaddata.apply(self, [self.revert, settings]));
181
            } else {
182
                jQuery.extend(loaddata, settings.loaddata);
183
            }
184
            jQuery.ajax({
185
               type : settings.loadtype,
186
               url  : settings.loadurl,
187
               data : loaddata,
188
               success: function(string) {
189
                         window.clearTimeout(t);                
190
                  content.apply(f, [string, settings, self]);
191
                  i.disabled = false;
192
               }
193
            });
194
        } else if (settings.data) {
195
            var str = settings.data;
196
            if (jQuery.isFunction(settings.data)) {
197
                var str = settings.data.apply(self, [self.revert, settings]);
198
            }
199
            content.apply(f, [str, settings, self]);
200
        } else { 
201
            content.apply(f, [self.revert, settings, self]);
202
        }
203

    
204
        i.name  = settings.name;
205
        
206
        /* add buttons to the form */
207
        buttons.apply(f, [settings, self]);
208

    
209
        /* add created form to self */
210
        self.appendChild(f);
211
        
212
        /* highlight input contents when requested */
213
        if (settings.select) {
214
            i.select();
215
        }
216
         
217
        /* attach 3rd party plugin if requested */
218
        plugin.apply(f, [settings, self]);            
219

    
220
        /* focus to first visible form element */
221
        jQuery(":input:visible:enabled:first", f).focus();
222
        
223
        /* discard changes if pressing esc */
224
        jQuery(i).keydown(function(e) {
225
            if (e.keyCode == 27) {
226
                e.preventDefault();
227
                reset();
228
            }
229
        });
230

    
231
        /* discard, submit or nothing with changes when clicking outside */
232
        /* do nothing is usable when navigating with tab */
233
        var t;
234
        if ('cancel' == settings.onblur) {
235
            jQuery(i).blur(function(e) {
236
                t = setTimeout(reset, 500);
237
            });
238
        } else if ('submit' == settings.onblur) {
239
            jQuery(i).blur(function(e) {
240
                jQuery(f).submit();
241
            });
242
        } else {
243
            jQuery(i).blur(function(e) {
244
              /* TODO: maybe something here */
245
            });
246
        }
247

    
248
        jQuery(f).submit(function(e) {
249

    
250
            if (t) { 
251
                clearTimeout(t);
252
            }
253

    
254
            /* do no submit */
255
            e.preventDefault(); 
256
            
257
            /* if this input type has a call before submit hook, call it */
258
            submit.apply(f, [settings, self]);            
259

    
260
            /* check if given target is function */
261
            if (jQuery.isFunction(settings.target)) {
262
                var str = settings.target.apply(self, [jQuery(i).val(), settings]);
263
                self.innerHTML = str;
264
                self.editing = false;
265
                callback.apply(self, [self.innerHTML, settings]);
266
            } else {
267
                /* add edited content and id of edited element to POST */
268
                var submitdata = {};
269
                submitdata[i.name] = jQuery(i).val();
270
                submitdata[settings.id] = self.id;
271
                /* add extra data to be POST:ed */
272
                if (jQuery.isFunction(settings.submitdata)) {
273
                    jQuery.extend(submitdata, settings.submitdata.apply(self, [self.revert, settings]));
274
                } else {
275
                    jQuery.extend(submitdata, settings.submitdata);
276
                }          
277

    
278
                /* show the saving indicator */
279
                jQuery(self).html(settings.indicator);
280
                jQuery.post(settings.target, submitdata, function(str) {
281
                    self.innerHTML = str;
282
                    self.editing = false;
283
                    callback.apply(self, [self.innerHTML, settings]);
284
                });
285
            }
286
                        
287
            return false;
288
        });
289

    
290
        function reset() {
291
            self.innerHTML = self.revert;
292
            self.editing   = false;
293
        }
294

    
295
    });
296
    
297
    return(this);
298
};
299

    
300
/**
301
  *
302
  */
303
 
304
jQuery.editable = {
305
    types: {
306
        defaults: {
307
            element : function(settings, original) {
308
                var input = jQuery('<input type="hidden">');                
309
                jQuery(this).append(input);
310
                return(input);
311
            },
312
            content : function(string, settings, original) {
313
                jQuery(':input:first', this).val(string);
314
            },
315
            buttons : function(settings, original) {
316
                if (settings.submit) {
317
                    var submit = jQuery('<input type="submit">');
318
                    submit.val(settings.submit);
319
                    jQuery(this).append(submit);
320
                }
321
                if (settings.cancel) {
322
                    var cancel = jQuery('<input type="button">');
323
                    cancel.val(settings.cancel);
324
                    jQuery(this).append(cancel);
325

    
326
                    jQuery(cancel).click(function() {
327
                        jQuery(original).html(original.revert);
328
                        original.editing = false;
329
                    });
330
                }
331
            }
332
        },
333
        text: {
334
            element : function(settings, original) {
335
                var input = jQuery('<input>');
336
                if (settings.width  != 'none') { input.width(settings.width);  }
337
                if (settings.height != 'none') { input.height(settings.height); }
338
                /* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
339
                //input[0].setAttribute('autocomplete','off');
340
                input.attr('autocomplete','off');
341
                jQuery(this).append(input);
342
                return(input);
343
            }
344
        },
345
        textarea: {
346
            element : function(settings, original) {
347
                var textarea = jQuery('<textarea>');
348
                if (settings.rows) {
349
                    textarea.attr('rows', settings.rows);
350
                } else {
351
                    textarea.height(settings.height);
352
                }
353
                if (settings.cols) {
354
                    textarea.attr('cols', settings.cols);
355
                } else {
356
                    textarea.width(settings.width);
357
                }
358
                jQuery(this).append(textarea);
359
                return(textarea);
360
            }
361
        },
362
        select: {
363
            element : function(settings, original) {
364
                var select = jQuery('<select>');
365
                jQuery(this).append(select);
366
                return(select);
367
            },
368
            content : function(string, settings, original) {
369
                /* IE borks if we do not store select in separate variable. */
370
                var select = jQuery('select', this);
371
                if (String == string.constructor) {          
372
                    eval ("var json = " + string);
373
                    for (var key in json) {
374
                        if ('selected' == key) {
375
                            continue;
376
                        } 
377
                        var option = $('<option>').val(key).append(json[key]);
378
                        select.append(option);          
379
                    }
380
                    /* TODO: leave only this to content so IE works too! */
381
/*
382
                    select.children().each(function() {
383
                        if (jQuery(this).val() == json['selected']) {
384
                            jQuery(this).attr('selected', 'selected');
385
                        };
386
                            });
387
                            */
388
                            //setTimeout(function() { jQuery.editable.types.select.iefix(select, json['selected']) }, 1000);
389
                }
390
                jQuery.editable.types.select.iefix(select, json['selected']);
391
            },
392
            iefix : function(select, which) {
393
                console.log(this);
394
                console.log(select);
395
                select.children().each(function() {
396
                    if (jQuery(this).val() == which) {
397
                        jQuery(this).attr('selected', 'selected');
398
                    };                    
399
                });
400
            }
401
        }
402
    },
403
    
404
    /* Add new input type */
405
    addInputType: function(name, input) {
406
        jQuery.editable.types[name] = input;
407
    }
408
};