bootstrap-editable-rails 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +12 -6
- data/lib/bootstrap-editable-rails/version.rb +1 -1
- data/vendor/assets/images/clear.png +0 -0
- data/vendor/assets/javascripts/bootstrap-editable-rails.js.coffee +11 -4
- data/vendor/assets/javascripts/bootstrap-editable.js +2166 -483
- data/vendor/assets/javascripts/bootstrap-editable.min.js +3 -3
- data/vendor/assets/stylesheets/bootstrap-editable.css +169 -142
- metadata +5 -6
- data/vendor/assets/javascripts/bootstrap-editable-inline.js +0 -3769
- data/vendor/assets/javascripts/bootstrap-editable-inline.min.js +0 -5
    
        data/README.md
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            In-place editing with Twitter Bootstrap for Rails
         | 
| 4 4 |  | 
| 5 | 
            -
            This gem is based on X-editable (v1. | 
| 5 | 
            +
            This gem is based on X-editable (v1.4.1) which is the new version of Bootstrap Editable.
         | 
| 6 6 |  | 
| 7 7 | 
             
            https://github.com/vitalets/x-editable
         | 
| 8 8 |  | 
| @@ -35,15 +35,13 @@ Write the top of `app/assets/javascripts/application.js` like this: | |
| 35 35 | 
             
            //= require_tree .
         | 
| 36 36 | 
             
            ```
         | 
| 37 37 |  | 
| 38 | 
            -
            (You can choose `bootstrap-editable-inline`)
         | 
| 39 | 
            -
             | 
| 40 38 | 
             
            and need to load `bootstrap-editable.css` at the place where you like.
         | 
| 41 39 |  | 
| 42 40 | 
             
            ### HTML
         | 
| 43 41 |  | 
| 44 | 
            -
            Follow the documents above.
         | 
| 42 | 
            +
            Follow the documents of X-editable above.
         | 
| 45 43 |  | 
| 46 | 
            -
            Additional required attribute | 
| 44 | 
            +
            Additional required attribute is `resource`.
         | 
| 47 45 |  | 
| 48 46 | 
             
            ```html
         | 
| 49 47 | 
             
            <a href="#" id="username" data-type="text" data-resource="post" data-name="username" data-url="/posts/1" data-original-title="Enter username">superuser</a>
         | 
| @@ -55,6 +53,14 @@ then, sends `PUT /posts/1` request with the body: | |
| 55 53 | 
             
            post[username]=superuser
         | 
| 56 54 | 
             
            ```
         | 
| 57 55 |  | 
| 56 | 
            +
            When using `textarea` type, `textarea_format` helper method for formatting line breaks is available.
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            ```html
         | 
| 59 | 
            +
            <a href="#" id="body" data-type="textarea" data-resource="post" data-name="body" data-url="/posts/1" data-original-title="Enter body">
         | 
| 60 | 
            +
              <%= textarea_format(@post.body) %>
         | 
| 61 | 
            +
            </a>
         | 
| 62 | 
            +
            ```
         | 
| 63 | 
            +
             | 
| 58 64 | 
             
            ### Controller
         | 
| 59 65 |  | 
| 60 66 | 
             
            PostsController receives the parameters
         | 
| @@ -65,7 +71,7 @@ PostsController receives the parameters | |
| 65 71 |  | 
| 66 72 | 
             
            and must respond with 2xx (means _success_) status code if successful.
         | 
| 67 73 |  | 
| 68 | 
            -
            For example, scaffold  | 
| 74 | 
            +
            For example, scaffold works well by 204 because default dataType is json.
         | 
| 69 75 |  | 
| 70 76 | 
             
            ```ruby
         | 
| 71 77 | 
             
            def update
         | 
| Binary file | 
| @@ -10,14 +10,21 @@ jQuery ($) -> | |
| 10 10 | 
             
                  # TODO: should not send when create new object
         | 
| 11 11 | 
             
                  if typeof originalUrl == 'function' # user's function
         | 
| 12 12 | 
             
                    originalUrl.call(@options.scope, params)
         | 
| 13 | 
            -
                  else  | 
| 13 | 
            +
                  else if originalUrl? && @options.send != 'never'
         | 
| 14 | 
            +
                    # send ajax to server and return deferred object
         | 
| 14 15 | 
             
                    obj = {}
         | 
| 15 | 
            -
                    data = {}
         | 
| 16 16 | 
             
                    obj[params.name] = params.value
         | 
| 17 | 
            -
                     | 
| 17 | 
            +
                    # support custom inputtypes (eg address)
         | 
| 18 | 
            +
                    if resource
         | 
| 19 | 
            +
                      params[resource] = obj
         | 
| 20 | 
            +
                    else
         | 
| 21 | 
            +
                      params = obj
         | 
| 22 | 
            +
                    delete params.name
         | 
| 23 | 
            +
                    delete params.value
         | 
| 24 | 
            +
                    delete params.pk
         | 
| 18 25 | 
             
                    $.ajax($.extend({
         | 
| 19 26 | 
             
                      url     : originalUrl
         | 
| 20 | 
            -
                      data    :  | 
| 27 | 
            +
                      data    : params
         | 
| 21 28 | 
             
                      type    : 'PUT' # TODO: should be 'POST' when create new object
         | 
| 22 29 | 
             
                      dataType: 'json'
         | 
| 23 30 | 
             
                    }, @options.ajaxOptions))
         | 
| @@ -1,7 +1,7 @@ | |
| 1 | 
            -
            /*! X-editable - v1. | 
| 1 | 
            +
            /*! X-editable - v1.4.1 
         | 
| 2 2 | 
             
            * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
         | 
| 3 3 | 
             
            * http://github.com/vitalets/x-editable
         | 
| 4 | 
            -
            * Copyright (c)  | 
| 4 | 
            +
            * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
         | 
| 5 5 |  | 
| 6 6 | 
             
            /**
         | 
| 7 7 | 
             
            Form with single input element, two buttons and two states: normal/loading.
         | 
| @@ -16,28 +16,21 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 16 16 |  | 
| 17 17 | 
             
                var EditableForm = function (div, options) {
         | 
| 18 18 | 
             
                    this.options = $.extend({}, $.fn.editableform.defaults, options);
         | 
| 19 | 
            -
                    this.$div = $(div); //div, containing form. Not form tag | 
| 19 | 
            +
                    this.$div = $(div); //div, containing form. Not form tag. Not editable-element.
         | 
| 20 20 | 
             
                    if(!this.options.scope) {
         | 
| 21 21 | 
             
                        this.options.scope = this;
         | 
| 22 22 | 
             
                    }
         | 
| 23 | 
            -
                     | 
| 23 | 
            +
                    //nothing shown after init
         | 
| 24 24 | 
             
                };
         | 
| 25 25 |  | 
| 26 26 | 
             
                EditableForm.prototype = {
         | 
| 27 27 | 
             
                    constructor: EditableForm,
         | 
| 28 28 | 
             
                    initInput: function() {  //called once
         | 
| 29 | 
            -
                         | 
| 30 | 
            -
             | 
| 31 | 
            -
                         | 
| 32 | 
            -
                         | 
| 33 | 
            -
             | 
| 34 | 
            -
                            typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
         | 
| 35 | 
            -
                            this.input = new TypeConstructor(typeOptions);
         | 
| 36 | 
            -
                        } else {
         | 
| 37 | 
            -
                            $.error('Unknown type: '+ this.options.type);
         | 
| 38 | 
            -
                            return; 
         | 
| 39 | 
            -
                        }          
         | 
| 40 | 
            -
             | 
| 29 | 
            +
                        //take input from options (as it is created in editable-element)
         | 
| 30 | 
            +
                        this.input = this.options.input;
         | 
| 31 | 
            +
                        
         | 
| 32 | 
            +
                        //set initial value
         | 
| 33 | 
            +
                        //todo: may be add check: typeof str === 'string' ? 
         | 
| 41 34 | 
             
                        this.value = this.input.str2value(this.options.value); 
         | 
| 42 35 | 
             
                    },
         | 
| 43 36 | 
             
                    initTemplate: function() {
         | 
| @@ -52,47 +45,49 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 52 45 | 
             
                    @method render
         | 
| 53 46 | 
             
                    **/        
         | 
| 54 47 | 
             
                    render: function() {
         | 
| 48 | 
            +
                        //init loader
         | 
| 55 49 | 
             
                        this.$loading = $($.fn.editableform.loading);        
         | 
| 56 50 | 
             
                        this.$div.empty().append(this.$loading);
         | 
| 57 | 
            -
                        this.showLoading();
         | 
| 58 51 |  | 
| 59 52 | 
             
                        //init form template and buttons
         | 
| 60 | 
            -
                        this.initTemplate(); | 
| 53 | 
            +
                        this.initTemplate();
         | 
| 61 54 | 
             
                        if(this.options.showbuttons) {
         | 
| 62 55 | 
             
                            this.initButtons();
         | 
| 63 56 | 
             
                        } else {
         | 
| 64 57 | 
             
                            this.$form.find('.editable-buttons').remove();
         | 
| 65 58 | 
             
                        }
         | 
| 66 59 |  | 
| 60 | 
            +
                        //show loading state
         | 
| 61 | 
            +
                        this.showLoading();            
         | 
| 62 | 
            +
                        
         | 
| 67 63 | 
             
                        /**        
         | 
| 68 64 | 
             
                        Fired when rendering starts
         | 
| 69 65 | 
             
                        @event rendering 
         | 
| 70 66 | 
             
                        @param {Object} event event object
         | 
| 71 67 | 
             
                        **/            
         | 
| 72 68 | 
             
                        this.$div.triggerHandler('rendering');
         | 
| 69 | 
            +
                        
         | 
| 70 | 
            +
                        //init input
         | 
| 71 | 
            +
                        this.initInput();
         | 
| 72 | 
            +
                        
         | 
| 73 | 
            +
                        //append input to form
         | 
| 74 | 
            +
                        this.input.prerender();
         | 
| 75 | 
            +
                        this.$form.find('div.editable-input').append(this.input.$tpl);            
         | 
| 73 76 |  | 
| 77 | 
            +
                        //append form to container
         | 
| 78 | 
            +
                        this.$div.append(this.$form);
         | 
| 79 | 
            +
                        
         | 
| 74 80 | 
             
                        //render input
         | 
| 75 81 | 
             
                        $.when(this.input.render())
         | 
| 76 82 | 
             
                        .then($.proxy(function () {
         | 
| 77 | 
            -
                            //input
         | 
| 78 | 
            -
                            this.$form.find('div.editable-input').append(this.input.$input);
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                            //automatically submit inputs when no buttons shown
         | 
| 83 | 
            +
                            //setup input to submit automatically when no buttons shown
         | 
| 81 84 | 
             
                            if(!this.options.showbuttons) {
         | 
| 82 85 | 
             
                                this.input.autosubmit(); 
         | 
| 83 86 | 
             
                            }
         | 
| 84 | 
            -
                            
         | 
| 85 | 
            -
                            //"clear" link
         | 
| 86 | 
            -
                            if(this.input.$clear) {
         | 
| 87 | 
            -
                                this.$form.find('div.editable-input').append($('<div class="editable-clear">').append(this.input.$clear));  
         | 
| 88 | 
            -
                            }                
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                            //append form to container
         | 
| 91 | 
            -
                            this.$div.append(this.$form);
         | 
| 92 87 |  | 
| 93 88 | 
             
                            //attach 'cancel' handler
         | 
| 94 89 | 
             
                            this.$form.find('.editable-cancel').click($.proxy(this.cancel, this));
         | 
| 95 | 
            -
             | 
| 90 | 
            +
                            
         | 
| 96 91 | 
             
                            if(this.input.error) {
         | 
| 97 92 | 
             
                                this.error(this.input.error);
         | 
| 98 93 | 
             
                                this.$form.find('.editable-submit').attr('disabled', true);
         | 
| @@ -116,6 +111,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 116 111 | 
             
                            this.$div.triggerHandler('rendered');                
         | 
| 117 112 |  | 
| 118 113 | 
             
                            this.showForm();
         | 
| 114 | 
            +
                            
         | 
| 115 | 
            +
                            //call postrender method to perform actions required visibility of form
         | 
| 116 | 
            +
                            if(this.input.postrender) {
         | 
| 117 | 
            +
                                this.input.postrender();
         | 
| 118 | 
            +
                            }                
         | 
| 119 119 | 
             
                        }, this));
         | 
| 120 120 | 
             
                    },
         | 
| 121 121 | 
             
                    cancel: function() {   
         | 
| @@ -127,11 +127,17 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 127 127 | 
             
                        this.$div.triggerHandler('cancel');
         | 
| 128 128 | 
             
                    },
         | 
| 129 129 | 
             
                    showLoading: function() {
         | 
| 130 | 
            -
                        var w;
         | 
| 130 | 
            +
                        var w, h;
         | 
| 131 131 | 
             
                        if(this.$form) {
         | 
| 132 | 
            -
                            //set loading size equal to form | 
| 133 | 
            -
                            this.$ | 
| 134 | 
            -
                            this.$ | 
| 132 | 
            +
                            //set loading size equal to form
         | 
| 133 | 
            +
                            w = this.$form.outerWidth();
         | 
| 134 | 
            +
                            h = this.$form.outerHeight(); 
         | 
| 135 | 
            +
                            if(w) {
         | 
| 136 | 
            +
                                this.$loading.width(w);
         | 
| 137 | 
            +
                            }
         | 
| 138 | 
            +
                            if(h) {
         | 
| 139 | 
            +
                                this.$loading.height(h);
         | 
| 140 | 
            +
                            }
         | 
| 135 141 | 
             
                            this.$form.hide();
         | 
| 136 142 | 
             
                        } else {
         | 
| 137 143 | 
             
                            //stretch loading to fill container width
         | 
| @@ -159,14 +165,23 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 159 165 |  | 
| 160 166 | 
             
                    error: function(msg) {
         | 
| 161 167 | 
             
                        var $group = this.$form.find('.control-group'),
         | 
| 162 | 
            -
             | 
| 168 | 
            +
                            $block = this.$form.find('.editable-error-block'),
         | 
| 169 | 
            +
                            lines;
         | 
| 163 170 |  | 
| 164 171 | 
             
                        if(msg === false) {
         | 
| 165 172 | 
             
                            $group.removeClass($.fn.editableform.errorGroupClass);
         | 
| 166 173 | 
             
                            $block.removeClass($.fn.editableform.errorBlockClass).empty().hide(); 
         | 
| 167 174 | 
             
                        } else {
         | 
| 175 | 
            +
                            //convert newline to <br> for more pretty error display
         | 
| 176 | 
            +
                            if(msg) {
         | 
| 177 | 
            +
                                lines = msg.split("\n");
         | 
| 178 | 
            +
                                for (var i = 0; i < lines.length; i++) {
         | 
| 179 | 
            +
                                    lines[i] = $('<div>').text(lines[i]).html();
         | 
| 180 | 
            +
                                }
         | 
| 181 | 
            +
                                msg = lines.join('<br>');
         | 
| 182 | 
            +
                            }
         | 
| 168 183 | 
             
                            $group.addClass($.fn.editableform.errorGroupClass);
         | 
| 169 | 
            -
                            $block.addClass($.fn.editableform.errorBlockClass). | 
| 184 | 
            +
                            $block.addClass($.fn.editableform.errorBlockClass).html(msg).show();
         | 
| 170 185 | 
             
                        }
         | 
| 171 186 | 
             
                    },
         | 
| 172 187 |  | 
| @@ -218,6 +233,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 218 233 | 
             
                            }     
         | 
| 219 234 |  | 
| 220 235 | 
             
                            //if success callback returns object like {newValue: <something>} --> use that value instead of submitted
         | 
| 236 | 
            +
                            //it is usefull if you want to chnage value in url-function
         | 
| 221 237 | 
             
                            if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
         | 
| 222 238 | 
             
                                newValue = res.newValue;
         | 
| 223 239 | 
             
                            }                            
         | 
| @@ -299,10 +315,15 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 299 315 | 
             
                    },
         | 
| 300 316 |  | 
| 301 317 | 
             
                    option: function(key, value) {
         | 
| 302 | 
            -
                        this.options | 
| 318 | 
            +
                        if(key in this.options) {
         | 
| 319 | 
            +
                            this.options[key] = value;
         | 
| 320 | 
            +
                        }
         | 
| 321 | 
            +
                        
         | 
| 303 322 | 
             
                        if(key === 'value') {
         | 
| 304 323 | 
             
                            this.setValue(value);
         | 
| 305 324 | 
             
                        }
         | 
| 325 | 
            +
                        
         | 
| 326 | 
            +
                        //do not pass option to input as it is passed in editable-element
         | 
| 306 327 | 
             
                    },
         | 
| 307 328 |  | 
| 308 329 | 
             
                    setValue: function(value, convertStr) {
         | 
| @@ -311,6 +332,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 311 332 | 
             
                        } else {
         | 
| 312 333 | 
             
                            this.value = value;
         | 
| 313 334 | 
             
                        }
         | 
| 335 | 
            +
                        
         | 
| 336 | 
            +
                        //if form is visible, update input
         | 
| 337 | 
            +
                        if(this.$form && this.$form.is(':visible')) {
         | 
| 338 | 
            +
                            this.input.value2input(this.value);
         | 
| 339 | 
            +
                        }            
         | 
| 314 340 | 
             
                    }               
         | 
| 315 341 | 
             
                };
         | 
| 316 342 |  | 
| @@ -363,18 +389,25 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 363 389 | 
             
                    type: 'text',
         | 
| 364 390 | 
             
                    /**
         | 
| 365 391 | 
             
                    Url for submit, e.g. <code>'/post'</code>  
         | 
| 366 | 
            -
                    If function - it will be called instead of ajax. Function  | 
| 392 | 
            +
                    If function - it will be called instead of ajax. Function should return deferred object to run fail/done callbacks.
         | 
| 367 393 |  | 
| 368 394 | 
             
                    @property url 
         | 
| 369 395 | 
             
                    @type string|function
         | 
| 370 396 | 
             
                    @default null
         | 
| 371 397 | 
             
                    @example
         | 
| 372 398 | 
             
                    url: function(params) {
         | 
| 399 | 
            +
                        var d = new $.Deferred;
         | 
| 373 400 | 
             
                        if(params.value === 'abc') {
         | 
| 374 | 
            -
                             | 
| 375 | 
            -
                            return d.reject('field cannot be "abc"'); //returning error via deferred object
         | 
| 401 | 
            +
                            return d.reject('error message'); //returning error via deferred object
         | 
| 376 402 | 
             
                        } else {
         | 
| 377 | 
            -
                             | 
| 403 | 
            +
                            //async saving data in js model
         | 
| 404 | 
            +
                            someModel.asyncSaveMethod({
         | 
| 405 | 
            +
                               ..., 
         | 
| 406 | 
            +
                               success: function(){
         | 
| 407 | 
            +
                                  d.resolve();
         | 
| 408 | 
            +
                               }
         | 
| 409 | 
            +
                            }); 
         | 
| 410 | 
            +
                            return d.promise();
         | 
| 378 411 | 
             
                        }
         | 
| 379 412 | 
             
                    } 
         | 
| 380 413 | 
             
                    **/        
         | 
| @@ -463,21 +496,21 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 463 496 | 
             
                    /**
         | 
| 464 497 | 
             
                    Additional options for ajax request.
         | 
| 465 498 | 
             
                    List of values: http://api.jquery.com/jQuery.ajax
         | 
| 466 | 
            -
             | 
| 499 | 
            +
                    
         | 
| 467 500 | 
             
                    @property ajaxOptions 
         | 
| 468 501 | 
             
                    @type object
         | 
| 469 502 | 
             
                    @default null
         | 
| 470 503 | 
             
                    @since 1.1.1        
         | 
| 504 | 
            +
                    @example 
         | 
| 505 | 
            +
                    ajaxOptions: {
         | 
| 506 | 
            +
                        type: 'put',
         | 
| 507 | 
            +
                        dataType: 'json'
         | 
| 508 | 
            +
                    }        
         | 
| 471 509 | 
             
                    **/        
         | 
| 472 510 | 
             
                    ajaxOptions: null,
         | 
| 473 511 | 
             
                    /**
         | 
| 474 512 | 
             
                    Whether to show buttons or not.  
         | 
| 475 | 
            -
                    Form without buttons  | 
| 476 | 
            -
                    @example 
         | 
| 477 | 
            -
                    ajaxOptions: {
         | 
| 478 | 
            -
                        method: 'PUT',
         | 
| 479 | 
            -
                        dataType: 'xml'
         | 
| 480 | 
            -
                    }
         | 
| 513 | 
            +
                    Form without buttons is auto-submitted.
         | 
| 481 514 |  | 
| 482 515 | 
             
                    @property showbuttons 
         | 
| 483 516 | 
             
                    @type boolean
         | 
| @@ -621,19 +654,22 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 621 654 | 
             
                        return newObj;
         | 
| 622 655 | 
             
                    },
         | 
| 623 656 |  | 
| 624 | 
            -
                     | 
| 625 | 
            -
                     | 
| 657 | 
            +
                    /*
         | 
| 658 | 
            +
                    exclude complex objects from $.data() before pass to config
         | 
| 626 659 | 
             
                    */
         | 
| 627 660 | 
             
                    getConfigData: function($element) {
         | 
| 628 661 | 
             
                        var data = {};
         | 
| 629 662 | 
             
                        $.each($element.data(), function(k, v) {
         | 
| 630 | 
            -
                            if(typeof v !== 'object' || (v && typeof v === 'object' && v.constructor === Object)) {
         | 
| 663 | 
            +
                            if(typeof v !== 'object' || (v && typeof v === 'object' && (v.constructor === Object || v.constructor === Array))) {
         | 
| 631 664 | 
             
                                data[k] = v;
         | 
| 632 665 | 
             
                            }
         | 
| 633 666 | 
             
                        });
         | 
| 634 667 | 
             
                        return data;
         | 
| 635 668 | 
             
                    },
         | 
| 636 669 |  | 
| 670 | 
            +
                    /*
         | 
| 671 | 
            +
                     returns keys of object
         | 
| 672 | 
            +
                    */
         | 
| 637 673 | 
             
                    objectKeys: function(o) {
         | 
| 638 674 | 
             
                        if (Object.keys) {
         | 
| 639 675 | 
             
                            return Object.keys(o);  
         | 
| @@ -657,9 +693,95 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. | |
| 657 693 | 
             
                   **/
         | 
| 658 694 | 
             
                   escape: function(str) {
         | 
| 659 695 | 
             
                       return $('<div>').text(str).html();
         | 
| 660 | 
            -
                   } | 
| 696 | 
            +
                   },
         | 
| 697 | 
            +
                   
         | 
| 698 | 
            +
                   /*
         | 
| 699 | 
            +
                    returns array items from sourceData having value property equal or inArray of 'value'
         | 
| 700 | 
            +
                   */
         | 
| 701 | 
            +
                   itemsByValue: function(value, sourceData, valueProp) {
         | 
| 702 | 
            +
                       if(!sourceData || value === null) {
         | 
| 703 | 
            +
                           return [];
         | 
| 704 | 
            +
                       }
         | 
| 705 | 
            +
                       
         | 
| 706 | 
            +
                       valueProp = valueProp || 'value';
         | 
| 707 | 
            +
                                  
         | 
| 708 | 
            +
                       var isValArray = $.isArray(value),
         | 
| 709 | 
            +
                       result = [], 
         | 
| 710 | 
            +
                       that = this;
         | 
| 711 | 
            +
             | 
| 712 | 
            +
                       $.each(sourceData, function(i, o) {
         | 
| 713 | 
            +
                           if(o.children) {
         | 
| 714 | 
            +
                               result = result.concat(that.itemsByValue(value, o.children));
         | 
| 715 | 
            +
                           } else {
         | 
| 716 | 
            +
                               /*jslint eqeq: true*/
         | 
| 717 | 
            +
                               if(isValArray) {
         | 
| 718 | 
            +
                                   if($.grep(value, function(v){  return v == (o && typeof o === 'object' ? o[valueProp] : o); }).length) {
         | 
| 719 | 
            +
                                       result.push(o); 
         | 
| 720 | 
            +
                                   }
         | 
| 721 | 
            +
                               } else {
         | 
| 722 | 
            +
                                   if(value == (o && typeof o === 'object' ? o[valueProp] : o)) {
         | 
| 723 | 
            +
                                       result.push(o); 
         | 
| 724 | 
            +
                                   }
         | 
| 725 | 
            +
                               }
         | 
| 726 | 
            +
                               /*jslint eqeq: false*/
         | 
| 727 | 
            +
                           }
         | 
| 728 | 
            +
                       });
         | 
| 729 | 
            +
                       
         | 
| 730 | 
            +
                       return result;
         | 
| 731 | 
            +
                   },
         | 
| 732 | 
            +
                   
         | 
| 733 | 
            +
                   /*
         | 
| 734 | 
            +
                   Returns input by options: type, mode. 
         | 
| 735 | 
            +
                   */
         | 
| 736 | 
            +
                   createInput: function(options) {
         | 
| 737 | 
            +
                       var TypeConstructor, typeOptions, input,
         | 
| 738 | 
            +
                       type = options.type;
         | 
| 739 | 
            +
             | 
| 740 | 
            +
                       //`date` is some kind of virtual type that is transformed to one of exact types
         | 
| 741 | 
            +
                       //depending on mode and core lib
         | 
| 742 | 
            +
                       if(type === 'date') {
         | 
| 743 | 
            +
                           //inline
         | 
| 744 | 
            +
                           if(options.mode === 'inline') {
         | 
| 745 | 
            +
                               if($.fn.editabletypes.datefield) {
         | 
| 746 | 
            +
                                   type = 'datefield';
         | 
| 747 | 
            +
                               } else if($.fn.editabletypes.dateuifield) {
         | 
| 748 | 
            +
                                   type = 'dateuifield';
         | 
| 749 | 
            +
                               }
         | 
| 750 | 
            +
                           //popup
         | 
| 751 | 
            +
                           } else {
         | 
| 752 | 
            +
                               if($.fn.editabletypes.date) {
         | 
| 753 | 
            +
                                   type = 'date';
         | 
| 754 | 
            +
                               } else if($.fn.editabletypes.dateui) {
         | 
| 755 | 
            +
                                   type = 'dateui';
         | 
| 756 | 
            +
                               }
         | 
| 757 | 
            +
                           }
         | 
| 758 | 
            +
                           
         | 
| 759 | 
            +
                           //if type still `date` and not exist in types, replace with `combodate` that is base input
         | 
| 760 | 
            +
                           if(type === 'date' && !$.fn.editabletypes.date) {
         | 
| 761 | 
            +
                               type = 'combodate';
         | 
| 762 | 
            +
                           } 
         | 
| 763 | 
            +
                       }
         | 
| 764 | 
            +
             | 
| 765 | 
            +
                       //change wysihtml5 to textarea for jquery UI and plain versions
         | 
| 766 | 
            +
                       if(type === 'wysihtml5' && !$.fn.editabletypes[type]) {
         | 
| 767 | 
            +
                           type = 'textarea';
         | 
| 768 | 
            +
                       }
         | 
| 769 | 
            +
             | 
| 770 | 
            +
                       //create input of specified type. Input will be used for converting value, not in form
         | 
| 771 | 
            +
                       if(typeof $.fn.editabletypes[type] === 'function') {
         | 
| 772 | 
            +
                           TypeConstructor = $.fn.editabletypes[type];
         | 
| 773 | 
            +
                           typeOptions = this.sliceObj(options, this.objectKeys(TypeConstructor.defaults));
         | 
| 774 | 
            +
                           input = new TypeConstructor(typeOptions);
         | 
| 775 | 
            +
                           return input;
         | 
| 776 | 
            +
                       } else {
         | 
| 777 | 
            +
                           $.error('Unknown type: '+ type);
         | 
| 778 | 
            +
                           return false; 
         | 
| 779 | 
            +
                       }  
         | 
| 780 | 
            +
                   }            
         | 
| 781 | 
            +
                   
         | 
| 661 782 | 
             
                };      
         | 
| 662 | 
            -
            }(window.jQuery));
         | 
| 783 | 
            +
            }(window.jQuery));
         | 
| 784 | 
            +
             | 
| 663 785 | 
             
            /**
         | 
| 664 786 | 
             
            Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
         | 
| 665 787 | 
             
            This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
         | 
| @@ -671,19 +793,27 @@ Applied as jQuery method. | |
| 671 793 | 
             
            **/
         | 
| 672 794 | 
             
            (function ($) {
         | 
| 673 795 |  | 
| 674 | 
            -
                var  | 
| 796 | 
            +
                var Popup = function (element, options) {
         | 
| 675 797 | 
             
                    this.init(element, options);
         | 
| 676 798 | 
             
                };
         | 
| 799 | 
            +
                
         | 
| 800 | 
            +
                var Inline = function (element, options) {
         | 
| 801 | 
            +
                    this.init(element, options);
         | 
| 802 | 
            +
                };    
         | 
| 677 803 |  | 
| 678 804 | 
             
                //methods
         | 
| 679 | 
            -
                 | 
| 805 | 
            +
                Popup.prototype = {
         | 
| 680 806 | 
             
                    containerName: null, //tbd in child class
         | 
| 681 807 | 
             
                    innerCss: null, //tbd in child class
         | 
| 682 808 | 
             
                    init: function(element, options) {
         | 
| 683 809 | 
             
                        this.$element = $(element);
         | 
| 684 | 
            -
                        // | 
| 685 | 
            -
                        this.options = $.extend({}, $.fn.editableContainer.defaults,  | 
| 810 | 
            +
                        //since 1.4.1 container do not use data-* directly as they already merged into options.
         | 
| 811 | 
            +
                        this.options = $.extend({}, $.fn.editableContainer.defaults, options);         
         | 
| 686 812 | 
             
                        this.splitOptions();
         | 
| 813 | 
            +
                        
         | 
| 814 | 
            +
                        //set scope of form callbacks to element
         | 
| 815 | 
            +
                        this.formOptions.scope = this.$element[0]; 
         | 
| 816 | 
            +
                        
         | 
| 687 817 | 
             
                        this.initContainer();
         | 
| 688 818 |  | 
| 689 819 | 
             
                        //bind 'destroyed' listener to destroy container when element is removed from dom
         | 
| @@ -691,7 +821,7 @@ Applied as jQuery method. | |
| 691 821 | 
             
                            this.destroy();
         | 
| 692 822 | 
             
                        }, this)); 
         | 
| 693 823 |  | 
| 694 | 
            -
                        //attach document  | 
| 824 | 
            +
                        //attach document handler to close containers on click / escape
         | 
| 695 825 | 
             
                        if(!$(document).data('editable-handlers-attached')) {
         | 
| 696 826 | 
             
                            //close all on escape
         | 
| 697 827 | 
             
                            $(document).on('keyup.editable', function (e) {
         | 
| @@ -703,15 +833,22 @@ Applied as jQuery method. | |
| 703 833 |  | 
| 704 834 | 
             
                            //close containers when click outside
         | 
| 705 835 | 
             
                            $(document).on('click.editable', function(e) {
         | 
| 706 | 
            -
                                var $target = $(e.target) | 
| 836 | 
            +
                                var $target = $(e.target), i,
         | 
| 837 | 
            +
                                    exclude_classes = ['.editable-container', 
         | 
| 838 | 
            +
                                                       '.ui-datepicker-header', 
         | 
| 839 | 
            +
                                                       '.modal-backdrop', 
         | 
| 840 | 
            +
                                                       '.bootstrap-wysihtml5-insert-image-modal', 
         | 
| 841 | 
            +
                                                       '.bootstrap-wysihtml5-insert-link-modal'];
         | 
| 707 842 |  | 
| 708 | 
            -
                                //if click inside  | 
| 709 | 
            -
                                 | 
| 710 | 
            -
             | 
| 711 | 
            -
             | 
| 712 | 
            -
             | 
| 713 | 
            -
                                    EditableContainer.prototype.closeOthers(e.target);
         | 
| 843 | 
            +
                                //if click inside one of exclude classes --> no nothing
         | 
| 844 | 
            +
                                for(i=0; i<exclude_classes.length; i++) {
         | 
| 845 | 
            +
                                     if($target.is(exclude_classes[i]) || $target.parents(exclude_classes[i]).length) {
         | 
| 846 | 
            +
                                         return;
         | 
| 847 | 
            +
                                     }
         | 
| 714 848 | 
             
                                }
         | 
| 849 | 
            +
                                  
         | 
| 850 | 
            +
                                //close all open containers (except one - target)
         | 
| 851 | 
            +
                                Popup.prototype.closeOthers(e.target);
         | 
| 715 852 | 
             
                            });
         | 
| 716 853 |  | 
| 717 854 | 
             
                            $(document).data('editable-handlers-attached', true);
         | 
| @@ -723,6 +860,7 @@ Applied as jQuery method. | |
| 723 860 | 
             
                        this.containerOptions = {};
         | 
| 724 861 | 
             
                        this.formOptions = {};
         | 
| 725 862 | 
             
                        var cDef = $.fn[this.containerName].defaults;
         | 
| 863 | 
            +
                        //keys defined in container defaults go to container, others go to form
         | 
| 726 864 | 
             
                        for(var k in this.options) {
         | 
| 727 865 | 
             
                          if(k in cDef) {
         | 
| 728 866 | 
             
                             this.containerOptions[k] = this.options[k];
         | 
| @@ -732,20 +870,37 @@ Applied as jQuery method. | |
| 732 870 | 
             
                        }
         | 
| 733 871 | 
             
                    },
         | 
| 734 872 |  | 
| 873 | 
            +
                    /*
         | 
| 874 | 
            +
                    Returns jquery object of container
         | 
| 875 | 
            +
                    @method tip()
         | 
| 876 | 
            +
                    */         
         | 
| 877 | 
            +
                    tip: function() {
         | 
| 878 | 
            +
                        return this.container() ? this.container().$tip : null;
         | 
| 879 | 
            +
                    },
         | 
| 880 | 
            +
             | 
| 881 | 
            +
                    /* returns container object */
         | 
| 882 | 
            +
                    container: function() {
         | 
| 883 | 
            +
                        return this.$element.data(this.containerName); 
         | 
| 884 | 
            +
                    },
         | 
| 885 | 
            +
             | 
| 886 | 
            +
                    call: function() {
         | 
| 887 | 
            +
                        this.$element[this.containerName].apply(this.$element, arguments); 
         | 
| 888 | 
            +
                    },        
         | 
| 889 | 
            +
                    
         | 
| 735 890 | 
             
                    initContainer: function(){
         | 
| 736 891 | 
             
                        this.call(this.containerOptions);
         | 
| 737 892 | 
             
                    },
         | 
| 738 893 |  | 
| 739 | 
            -
                     | 
| 740 | 
            -
                        this | 
| 741 | 
            -
                        this.$form = $('<div>')
         | 
| 894 | 
            +
                    renderForm: function() {
         | 
| 895 | 
            +
                        this.$form
         | 
| 742 896 | 
             
                        .editableform(this.formOptions)
         | 
| 743 897 | 
             
                        .on({
         | 
| 744 | 
            -
                            save: $.proxy(this.save, this),
         | 
| 745 | 
            -
                             | 
| 746 | 
            -
                             | 
| 898 | 
            +
                            save: $.proxy(this.save, this), //click on submit button (value changed)
         | 
| 899 | 
            +
                            nochange: $.proxy(function(){ this.hide('nochange'); }, this), //click on submit button (value NOT changed)                
         | 
| 900 | 
            +
                            cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
         | 
| 747 901 | 
             
                            show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
         | 
| 748 902 | 
             
                            rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
         | 
| 903 | 
            +
                            resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed 
         | 
| 749 904 | 
             
                            rendered: $.proxy(function(){
         | 
| 750 905 | 
             
                                /**        
         | 
| 751 906 | 
             
                                Fired when container is shown and form is rendered (for select will wait for loading dropdown options)
         | 
| @@ -760,31 +915,16 @@ Applied as jQuery method. | |
| 760 915 | 
             
                                **/                      
         | 
| 761 916 | 
             
                                this.$element.triggerHandler('shown');
         | 
| 762 917 | 
             
                            }, this) 
         | 
| 763 | 
            -
                        }) | 
| 764 | 
            -
                         | 
| 918 | 
            +
                        })
         | 
| 919 | 
            +
                        .editableform('render');
         | 
| 765 920 | 
             
                    },        
         | 
| 766 921 |  | 
| 767 | 
            -
                    /*
         | 
| 768 | 
            -
                    Returns jquery object of container
         | 
| 769 | 
            -
                    @method tip()
         | 
| 770 | 
            -
                    */         
         | 
| 771 | 
            -
                    tip: function() {
         | 
| 772 | 
            -
                        return this.container().$tip;
         | 
| 773 | 
            -
                    },
         | 
| 774 | 
            -
             | 
| 775 | 
            -
                    container: function() {
         | 
| 776 | 
            -
                        return this.$element.data(this.containerName); 
         | 
| 777 | 
            -
                    },
         | 
| 778 | 
            -
             | 
| 779 | 
            -
                    call: function() {
         | 
| 780 | 
            -
                        this.$element[this.containerName].apply(this.$element, arguments); 
         | 
| 781 | 
            -
                    },
         | 
| 782 | 
            -
             | 
| 783 922 | 
             
                    /**
         | 
| 784 923 | 
             
                    Shows container with form
         | 
| 785 924 | 
             
                    @method show()
         | 
| 786 925 | 
             
                    @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
         | 
| 787 | 
            -
                    **/ | 
| 926 | 
            +
                    **/
         | 
| 927 | 
            +
                    /* Note: poshytip owerwrites this method totally! */          
         | 
| 788 928 | 
             
                    show: function (closeAll) {
         | 
| 789 929 | 
             
                        this.$element.addClass('editable-open');
         | 
| 790 930 | 
             
                        if(closeAll !== false) {
         | 
| @@ -792,16 +932,37 @@ Applied as jQuery method. | |
| 792 932 | 
             
                            this.closeOthers(this.$element[0]);  
         | 
| 793 933 | 
             
                        }
         | 
| 794 934 |  | 
| 935 | 
            +
                        //show container itself
         | 
| 795 936 | 
             
                        this.innerShow();
         | 
| 796 | 
            -
                    },
         | 
| 797 | 
            -
                    
         | 
| 798 | 
            -
                    /* internal show method. To be overwritten in child classes */
         | 
| 799 | 
            -
                    innerShow: function () {
         | 
| 800 | 
            -
                        this.call('show');                
         | 
| 801 937 | 
             
                        this.tip().addClass('editable-container');
         | 
| 802 | 
            -
             | 
| 803 | 
            -
                         | 
| 804 | 
            -
                         | 
| 938 | 
            +
             | 
| 939 | 
            +
                        /*
         | 
| 940 | 
            +
                        Currently, form is re-rendered on every show. 
         | 
| 941 | 
            +
                        The main reason is that we dont know, what container will do with content when closed:
         | 
| 942 | 
            +
                        remove(), detach() or just hide().
         | 
| 943 | 
            +
                        
         | 
| 944 | 
            +
                        Detaching form itself before hide and re-insert before show is good solution, 
         | 
| 945 | 
            +
                        but visually it looks ugly, as container changes size before hide.  
         | 
| 946 | 
            +
                        */             
         | 
| 947 | 
            +
                        
         | 
| 948 | 
            +
                        //if form already exist - delete previous data 
         | 
| 949 | 
            +
                        if(this.$form) {
         | 
| 950 | 
            +
                            //todo: destroy prev data!
         | 
| 951 | 
            +
                            //this.$form.destroy();
         | 
| 952 | 
            +
                        }
         | 
| 953 | 
            +
             | 
| 954 | 
            +
                        this.$form = $('<div>');
         | 
| 955 | 
            +
                        
         | 
| 956 | 
            +
                        //insert form into container body
         | 
| 957 | 
            +
                        if(this.tip().is(this.innerCss)) {
         | 
| 958 | 
            +
                            //for inline container
         | 
| 959 | 
            +
                            this.tip().append(this.$form); 
         | 
| 960 | 
            +
                        } else {
         | 
| 961 | 
            +
                            this.tip().find(this.innerCss).append(this.$form);
         | 
| 962 | 
            +
                        } 
         | 
| 963 | 
            +
                        
         | 
| 964 | 
            +
                        //render form
         | 
| 965 | 
            +
                        this.renderForm();
         | 
| 805 966 | 
             
                    },
         | 
| 806 967 |  | 
| 807 968 | 
             
                    /**
         | 
| @@ -813,8 +974,10 @@ Applied as jQuery method. | |
| 813 974 | 
             
                        if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
         | 
| 814 975 | 
             
                            return;
         | 
| 815 976 | 
             
                        }
         | 
| 977 | 
            +
                        
         | 
| 816 978 | 
             
                        this.$element.removeClass('editable-open');   
         | 
| 817 979 | 
             
                        this.innerHide();
         | 
| 980 | 
            +
                        
         | 
| 818 981 | 
             
                        /**        
         | 
| 819 982 | 
             
                        Fired when container was hidden. It occurs on both save or cancel.
         | 
| 820 983 |  | 
| @@ -832,9 +995,14 @@ Applied as jQuery method. | |
| 832 995 | 
             
                        this.$element.triggerHandler('hidden', reason);   
         | 
| 833 996 | 
             
                    },
         | 
| 834 997 |  | 
| 998 | 
            +
                    /* internal show method. To be overwritten in child classes */
         | 
| 999 | 
            +
                    innerShow: function () {
         | 
| 1000 | 
            +
                         
         | 
| 1001 | 
            +
                    },        
         | 
| 1002 | 
            +
                    
         | 
| 835 1003 | 
             
                    /* internal hide method. To be overwritten in child classes */
         | 
| 836 1004 | 
             
                    innerHide: function () {
         | 
| 837 | 
            -
             | 
| 1005 | 
            +
                
         | 
| 838 1006 | 
             
                    },        
         | 
| 839 1007 |  | 
| 840 1008 | 
             
                    /**
         | 
| @@ -843,7 +1011,7 @@ Applied as jQuery method. | |
| 843 1011 | 
             
                    @param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
         | 
| 844 1012 | 
             
                    **/          
         | 
| 845 1013 | 
             
                    toggle: function(closeAll) {
         | 
| 846 | 
            -
                        if(this.tip && this.tip().is(':visible')) {
         | 
| 1014 | 
            +
                        if(this.container() && this.tip() && this.tip().is(':visible')) {
         | 
| 847 1015 | 
             
                            this.hide();
         | 
| 848 1016 | 
             
                        } else {
         | 
| 849 1017 | 
             
                            this.show(closeAll);
         | 
| @@ -859,7 +1027,6 @@ Applied as jQuery method. | |
| 859 1027 | 
             
                    },
         | 
| 860 1028 |  | 
| 861 1029 | 
             
                    save: function(e, params) {
         | 
| 862 | 
            -
                        this.hide('save');
         | 
| 863 1030 | 
             
                        /**        
         | 
| 864 1031 | 
             
                        Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
         | 
| 865 1032 |  | 
| @@ -880,6 +1047,9 @@ Applied as jQuery method. | |
| 880 1047 | 
             
                        });
         | 
| 881 1048 | 
             
                        **/             
         | 
| 882 1049 | 
             
                        this.$element.triggerHandler('save', params);
         | 
| 1050 | 
            +
                        
         | 
| 1051 | 
            +
                        //hide must be after trigger, as saving value may require methods od plugin, applied to input
         | 
| 1052 | 
            +
                        this.hide('save');
         | 
| 883 1053 | 
             
                    },
         | 
| 884 1054 |  | 
| 885 1055 | 
             
                    /**
         | 
| @@ -911,9 +1081,17 @@ Applied as jQuery method. | |
| 911 1081 | 
             
                    @method destroy()
         | 
| 912 1082 | 
             
                    **/        
         | 
| 913 1083 | 
             
                    destroy: function() {
         | 
| 914 | 
            -
                        this. | 
| 1084 | 
            +
                        this.hide();
         | 
| 1085 | 
            +
                        this.innerDestroy();
         | 
| 1086 | 
            +
                        this.$element.off('destroyed');
         | 
| 1087 | 
            +
                        this.$element.removeData('editableContainer');
         | 
| 915 1088 | 
             
                    },
         | 
| 916 1089 |  | 
| 1090 | 
            +
                    /* to be overwritten in child classes */
         | 
| 1091 | 
            +
                    innerDestroy: function() {
         | 
| 1092 | 
            +
                        
         | 
| 1093 | 
            +
                    }, 
         | 
| 1094 | 
            +
                    
         | 
| 917 1095 | 
             
                    /*
         | 
| 918 1096 | 
             
                    Closes other containers except one related to passed element. 
         | 
| 919 1097 | 
             
                    Other containers can be cancelled or submitted (depends on onblur option)
         | 
| @@ -972,11 +1150,12 @@ Applied as jQuery method. | |
| 972 1150 | 
             
                    return this.each(function () {
         | 
| 973 1151 | 
             
                        var $this = $(this),
         | 
| 974 1152 | 
             
                        dataKey = 'editableContainer', 
         | 
| 975 | 
            -
                        data = $this.data(dataKey), | 
| 976 | 
            -
                        options = typeof option === 'object' && option | 
| 1153 | 
            +
                        data = $this.data(dataKey),
         | 
| 1154 | 
            +
                        options = typeof option === 'object' && option,
         | 
| 1155 | 
            +
                        Constructor = (options.mode === 'inline') ? Inline : Popup;             
         | 
| 977 1156 |  | 
| 978 1157 | 
             
                        if (!data) {
         | 
| 979 | 
            -
                            $this.data(dataKey, (data = new  | 
| 1158 | 
            +
                            $this.data(dataKey, (data = new Constructor(this, options)));
         | 
| 980 1159 | 
             
                        }
         | 
| 981 1160 |  | 
| 982 1161 | 
             
                        if (typeof option === 'string') { //call method 
         | 
| @@ -985,8 +1164,9 @@ Applied as jQuery method. | |
| 985 1164 | 
             
                    });
         | 
| 986 1165 | 
             
                };     
         | 
| 987 1166 |  | 
| 988 | 
            -
                //store  | 
| 989 | 
            -
                $.fn.editableContainer. | 
| 1167 | 
            +
                //store constructors
         | 
| 1168 | 
            +
                $.fn.editableContainer.Popup = Popup;
         | 
| 1169 | 
            +
                $.fn.editableContainer.Inline = Inline;
         | 
| 990 1170 |  | 
| 991 1171 | 
             
                //defaults
         | 
| 992 1172 | 
             
                $.fn.editableContainer.defaults = {
         | 
| @@ -1025,7 +1205,25 @@ Applied as jQuery method. | |
| 1025 1205 | 
             
                    @default 'cancel'
         | 
| 1026 1206 | 
             
                    @since 1.1.1
         | 
| 1027 1207 | 
             
                    **/        
         | 
| 1028 | 
            -
                    onblur: 'cancel'
         | 
| 1208 | 
            +
                    onblur: 'cancel',
         | 
| 1209 | 
            +
                    
         | 
| 1210 | 
            +
                    /**
         | 
| 1211 | 
            +
                    Animation speed (inline mode)
         | 
| 1212 | 
            +
                    @property anim 
         | 
| 1213 | 
            +
                    @type string
         | 
| 1214 | 
            +
                    @default 'fast'
         | 
| 1215 | 
            +
                    **/        
         | 
| 1216 | 
            +
                    anim: 'fast',
         | 
| 1217 | 
            +
                    
         | 
| 1218 | 
            +
                    /**
         | 
| 1219 | 
            +
                    Mode of editable, can be `popup` or `inline` 
         | 
| 1220 | 
            +
                    
         | 
| 1221 | 
            +
                    @property mode 
         | 
| 1222 | 
            +
                    @type string         
         | 
| 1223 | 
            +
                    @default 'popup'
         | 
| 1224 | 
            +
                    @since 1.4.0        
         | 
| 1225 | 
            +
                    **/        
         | 
| 1226 | 
            +
                    mode: 'popup'        
         | 
| 1029 1227 | 
             
                };
         | 
| 1030 1228 |  | 
| 1031 1229 | 
             
                /* 
         | 
| @@ -1042,6 +1240,58 @@ Applied as jQuery method. | |
| 1042 1240 |  | 
| 1043 1241 | 
             
            }(window.jQuery));
         | 
| 1044 1242 |  | 
| 1243 | 
            +
            /**
         | 
| 1244 | 
            +
            * Editable Inline 
         | 
| 1245 | 
            +
            * ---------------------
         | 
| 1246 | 
            +
            */
         | 
| 1247 | 
            +
            (function ($) {
         | 
| 1248 | 
            +
                
         | 
| 1249 | 
            +
                //copy prototype from EditableContainer
         | 
| 1250 | 
            +
                //extend methods
         | 
| 1251 | 
            +
                $.extend($.fn.editableContainer.Inline.prototype, $.fn.editableContainer.Popup.prototype, {
         | 
| 1252 | 
            +
                    containerName: 'editableform',
         | 
| 1253 | 
            +
                    innerCss: '.editable-inline',
         | 
| 1254 | 
            +
                             
         | 
| 1255 | 
            +
                    initContainer: function(){
         | 
| 1256 | 
            +
                        //container is <span> element
         | 
| 1257 | 
            +
                        this.$tip = $('<span></span>').addClass('editable-inline');
         | 
| 1258 | 
            +
                        
         | 
| 1259 | 
            +
                        //convert anim to miliseconds (int)
         | 
| 1260 | 
            +
                        if(!this.options.anim) {
         | 
| 1261 | 
            +
                            this.options.anim = 0;
         | 
| 1262 | 
            +
                        }         
         | 
| 1263 | 
            +
                    },
         | 
| 1264 | 
            +
                    
         | 
| 1265 | 
            +
                    splitOptions: function() {
         | 
| 1266 | 
            +
                        //all options are passed to form
         | 
| 1267 | 
            +
                        this.containerOptions = {};
         | 
| 1268 | 
            +
                        this.formOptions = this.options;
         | 
| 1269 | 
            +
                    },
         | 
| 1270 | 
            +
                    
         | 
| 1271 | 
            +
                    tip: function() {
         | 
| 1272 | 
            +
                       return this.$tip; 
         | 
| 1273 | 
            +
                    },
         | 
| 1274 | 
            +
                    
         | 
| 1275 | 
            +
                    innerShow: function () {
         | 
| 1276 | 
            +
                        this.$element.hide();
         | 
| 1277 | 
            +
                        this.tip().insertAfter(this.$element).show();
         | 
| 1278 | 
            +
                    }, 
         | 
| 1279 | 
            +
                    
         | 
| 1280 | 
            +
                    innerHide: function () {
         | 
| 1281 | 
            +
                        this.$tip.hide(this.options.anim, $.proxy(function() {
         | 
| 1282 | 
            +
                            this.$element.show();
         | 
| 1283 | 
            +
                            this.innerDestroy();
         | 
| 1284 | 
            +
                        }, this)); 
         | 
| 1285 | 
            +
                    },
         | 
| 1286 | 
            +
                    
         | 
| 1287 | 
            +
                    innerDestroy: function() {
         | 
| 1288 | 
            +
                        if(this.tip()) {
         | 
| 1289 | 
            +
                            this.tip().empty().remove();
         | 
| 1290 | 
            +
                        }
         | 
| 1291 | 
            +
                    } 
         | 
| 1292 | 
            +
                });
         | 
| 1293 | 
            +
             | 
| 1294 | 
            +
            }(window.jQuery));
         | 
| 1045 1295 | 
             
            /**
         | 
| 1046 1296 | 
             
            Makes editable any HTML element on the page. Applied as jQuery method.
         | 
| 1047 1297 |  | 
| @@ -1052,34 +1302,27 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1052 1302 |  | 
| 1053 1303 | 
             
                var Editable = function (element, options) {
         | 
| 1054 1304 | 
             
                    this.$element = $(element);
         | 
| 1055 | 
            -
                     | 
| 1056 | 
            -
                    this. | 
| 1305 | 
            +
                    //data-* has more priority over js options: because dynamically created elements may change data-* 
         | 
| 1306 | 
            +
                    this.options = $.extend({}, $.fn.editable.defaults, options, $.fn.editableutils.getConfigData(this.$element));  
         | 
| 1307 | 
            +
                    if(this.options.selector) {
         | 
| 1308 | 
            +
                        this.initLive();
         | 
| 1309 | 
            +
                    } else {
         | 
| 1310 | 
            +
                        this.init();
         | 
| 1311 | 
            +
                    }
         | 
| 1057 1312 | 
             
                };
         | 
| 1058 1313 |  | 
| 1059 1314 | 
             
                Editable.prototype = {
         | 
| 1060 1315 | 
             
                    constructor: Editable, 
         | 
| 1061 1316 | 
             
                    init: function () {
         | 
| 1062 | 
            -
                        var  | 
| 1063 | 
            -
                             | 
| 1064 | 
            -
             | 
| 1065 | 
            -
                            finalize;
         | 
| 1066 | 
            -
             | 
| 1067 | 
            -
                        //editableContainer must be defined
         | 
| 1068 | 
            -
                        if(!$.fn.editableContainer) {
         | 
| 1069 | 
            -
                            $.error('You must define $.fn.editableContainer via including corresponding file (e.g. editable-popover.js)');
         | 
| 1070 | 
            -
                            return;
         | 
| 1071 | 
            -
                        }    
         | 
| 1072 | 
            -
                            
         | 
| 1317 | 
            +
                        var isValueByText = false, 
         | 
| 1318 | 
            +
                            doAutotext, finalize;
         | 
| 1319 | 
            +
             | 
| 1073 1320 | 
             
                        //name
         | 
| 1074 1321 | 
             
                        this.options.name = this.options.name || this.$element.attr('id');
         | 
| 1075 1322 |  | 
| 1076 1323 | 
             
                        //create input of specified type. Input will be used for converting value, not in form
         | 
| 1077 | 
            -
                         | 
| 1078 | 
            -
             | 
| 1079 | 
            -
                            this.typeOptions = $.fn.editableutils.sliceObj(this.options, $.fn.editableutils.objectKeys(TypeConstructor.defaults));
         | 
| 1080 | 
            -
                            this.input = new TypeConstructor(this.typeOptions);
         | 
| 1081 | 
            -
                        } else {
         | 
| 1082 | 
            -
                            $.error('Unknown type: '+ this.options.type);
         | 
| 1324 | 
            +
                        this.input = $.fn.editableutils.createInput(this.options);
         | 
| 1325 | 
            +
                        if(!this.input) {
         | 
| 1083 1326 | 
             
                            return; 
         | 
| 1084 1327 | 
             
                        }            
         | 
| 1085 1328 |  | 
| @@ -1108,8 +1351,10 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1108 1351 | 
             
                        if(this.options.toggle !== 'manual') {
         | 
| 1109 1352 | 
             
                            this.$element.addClass('editable-click');
         | 
| 1110 1353 | 
             
                            this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
         | 
| 1354 | 
            +
                                //prevent following link
         | 
| 1111 1355 | 
             
                                e.preventDefault();
         | 
| 1112 | 
            -
                                 | 
| 1356 | 
            +
                                
         | 
| 1357 | 
            +
                                //stop propagation not required because in document click handler it checks event target
         | 
| 1113 1358 | 
             
                                //e.stopPropagation();
         | 
| 1114 1359 |  | 
| 1115 1360 | 
             
                                if(this.options.toggle === 'mouseenter') {
         | 
| @@ -1140,30 +1385,54 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1140 1385 |  | 
| 1141 1386 | 
             
                           @event init 
         | 
| 1142 1387 | 
             
                           @param {Object} event event object
         | 
| 1143 | 
            -
                           @param {Object} editable editable instance
         | 
| 1388 | 
            +
                           @param {Object} editable editable instance (as here it cannot accessed via data('editable'))
         | 
| 1144 1389 | 
             
                           @since 1.2.0
         | 
| 1390 | 
            +
                           @example
         | 
| 1391 | 
            +
                           $('#username').on('init', function(e, editable) {
         | 
| 1392 | 
            +
                               alert('initialized ' + editable.options.name);
         | 
| 1393 | 
            +
                           });
         | 
| 1145 1394 | 
             
                           **/                  
         | 
| 1146 1395 | 
             
                            this.$element.triggerHandler('init', this);
         | 
| 1147 1396 | 
             
                        }, this));
         | 
| 1148 1397 | 
             
                    },
         | 
| 1149 1398 |  | 
| 1399 | 
            +
                    /*
         | 
| 1400 | 
            +
                     Initializes parent element for live editables 
         | 
| 1401 | 
            +
                    */
         | 
| 1402 | 
            +
                    initLive: function() {
         | 
| 1403 | 
            +
                       //store selector 
         | 
| 1404 | 
            +
                       var selector = this.options.selector;
         | 
| 1405 | 
            +
                       //modify options for child elements
         | 
| 1406 | 
            +
                       this.options.selector = false; 
         | 
| 1407 | 
            +
                       this.options.autotext = 'never';
         | 
| 1408 | 
            +
                       //listen toggle events
         | 
| 1409 | 
            +
                       this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){
         | 
| 1410 | 
            +
                           var $target = $(e.target);
         | 
| 1411 | 
            +
                           if(!$target.data('editable')) {
         | 
| 1412 | 
            +
                               $target.editable(this.options).trigger(e);
         | 
| 1413 | 
            +
                           }
         | 
| 1414 | 
            +
                       }, this)); 
         | 
| 1415 | 
            +
                    },
         | 
| 1416 | 
            +
                    
         | 
| 1150 1417 | 
             
                    /*
         | 
| 1151 1418 | 
             
                    Renders value into element's text.
         | 
| 1152 1419 | 
             
                    Can call custom display method from options.
         | 
| 1153 1420 | 
             
                    Can return deferred object.
         | 
| 1154 1421 | 
             
                    @method render()
         | 
| 1422 | 
            +
                    @param {mixed} response server response (if exist) to pass into display function
         | 
| 1155 1423 | 
             
                    */          
         | 
| 1156 | 
            -
                    render: function() {
         | 
| 1424 | 
            +
                    render: function(response) {
         | 
| 1157 1425 | 
             
                        //do not display anything
         | 
| 1158 1426 | 
             
                        if(this.options.display === false) {
         | 
| 1159 1427 | 
             
                            return;
         | 
| 1160 1428 | 
             
                        }
         | 
| 1161 | 
            -
                         | 
| 1162 | 
            -
                        if | 
| 1163 | 
            -
             | 
| 1429 | 
            +
                        
         | 
| 1430 | 
            +
                        //if input has `value2htmlFinal` method, we pass callback in third param to be called when source is loaded
         | 
| 1431 | 
            +
                        if(this.input.value2htmlFinal) {
         | 
| 1432 | 
            +
                            return this.input.value2html(this.value, this.$element[0], this.options.display, response); 
         | 
| 1164 1433 | 
             
                        //if display method defined --> use it    
         | 
| 1165 1434 | 
             
                        } else if(typeof this.options.display === 'function') {
         | 
| 1166 | 
            -
                            return this.options.display.call(this.$element[0], this.value);
         | 
| 1435 | 
            +
                            return this.options.display.call(this.$element[0], this.value, response);
         | 
| 1167 1436 | 
             
                        //else use input's original value2html() method    
         | 
| 1168 1437 | 
             
                        } else {
         | 
| 1169 1438 | 
             
                            return this.input.value2html(this.value, this.$element[0]); 
         | 
| @@ -1177,7 +1446,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1177 1446 | 
             
                    enable: function() {
         | 
| 1178 1447 | 
             
                        this.options.disabled = false;
         | 
| 1179 1448 | 
             
                        this.$element.removeClass('editable-disabled');
         | 
| 1180 | 
            -
                        this.handleEmpty();
         | 
| 1449 | 
            +
                        this.handleEmpty(this.isEmpty);
         | 
| 1181 1450 | 
             
                        if(this.options.toggle !== 'manual') {
         | 
| 1182 1451 | 
             
                            if(this.$element.attr('tabindex') === '-1') {    
         | 
| 1183 1452 | 
             
                                this.$element.removeAttr('tabindex');                                
         | 
| @@ -1193,7 +1462,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1193 1462 | 
             
                        this.options.disabled = true; 
         | 
| 1194 1463 | 
             
                        this.hide();           
         | 
| 1195 1464 | 
             
                        this.$element.addClass('editable-disabled');
         | 
| 1196 | 
            -
                        this.handleEmpty();
         | 
| 1465 | 
            +
                        this.handleEmpty(this.isEmpty);
         | 
| 1197 1466 | 
             
                        //do not stop focus on this element
         | 
| 1198 1467 | 
             
                        this.$element.attr('tabindex', -1);                
         | 
| 1199 1468 | 
             
                    },
         | 
| @@ -1233,12 +1502,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1233 1502 |  | 
| 1234 1503 | 
             
                        //disabled
         | 
| 1235 1504 | 
             
                        if(key === 'disabled') {
         | 
| 1236 | 
            -
             | 
| 1237 | 
            -
                                this.disable();
         | 
| 1238 | 
            -
                            } else {
         | 
| 1239 | 
            -
                                this.enable();
         | 
| 1240 | 
            -
                            }
         | 
| 1241 | 
            -
                            return;
         | 
| 1505 | 
            +
                           return value ? this.disable() : this.enable();
         | 
| 1242 1506 | 
             
                        } 
         | 
| 1243 1507 |  | 
| 1244 1508 | 
             
                        //value
         | 
| @@ -1250,30 +1514,42 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1250 1514 | 
             
                        if(this.container) {
         | 
| 1251 1515 | 
             
                            this.container.option(key, value);  
         | 
| 1252 1516 | 
             
                        }
         | 
| 1517 | 
            +
                         
         | 
| 1518 | 
            +
                        //pass option to input directly (as it points to the same in form)
         | 
| 1519 | 
            +
                        if(this.input.option) {
         | 
| 1520 | 
            +
                            this.input.option(key, value);
         | 
| 1521 | 
            +
                        }
         | 
| 1522 | 
            +
                        
         | 
| 1253 1523 | 
             
                    },              
         | 
| 1254 1524 |  | 
| 1255 1525 | 
             
                    /*
         | 
| 1256 | 
            -
                    * set emptytext if element is empty | 
| 1526 | 
            +
                    * set emptytext if element is empty
         | 
| 1257 1527 | 
             
                    */
         | 
| 1258 | 
            -
                    handleEmpty: function () {
         | 
| 1528 | 
            +
                    handleEmpty: function (isEmpty) {
         | 
| 1259 1529 | 
             
                        //do not handle empty if we do not display anything
         | 
| 1260 1530 | 
             
                        if(this.options.display === false) {
         | 
| 1261 1531 | 
             
                            return;
         | 
| 1262 1532 | 
             
                        }
         | 
| 1263 1533 |  | 
| 1264 | 
            -
                         | 
| 1534 | 
            +
                        this.isEmpty = isEmpty !== undefined ? isEmpty : $.trim(this.$element.text()) === '';           
         | 
| 1535 | 
            +
                        
         | 
| 1265 1536 | 
             
                        //emptytext shown only for enabled
         | 
| 1266 1537 | 
             
                        if(!this.options.disabled) {
         | 
| 1267 | 
            -
                            if ( | 
| 1268 | 
            -
                                this.$element. | 
| 1269 | 
            -
             | 
| 1270 | 
            -
             | 
| 1538 | 
            +
                            if (this.isEmpty) {
         | 
| 1539 | 
            +
                                this.$element.text(this.options.emptytext);
         | 
| 1540 | 
            +
                                if(this.options.emptyclass) {
         | 
| 1541 | 
            +
                                    this.$element.addClass(this.options.emptyclass);
         | 
| 1542 | 
            +
                                }
         | 
| 1543 | 
            +
                            } else if(this.options.emptyclass) {
         | 
| 1544 | 
            +
                                this.$element.removeClass(this.options.emptyclass);
         | 
| 1271 1545 | 
             
                            }
         | 
| 1272 1546 | 
             
                        } else {
         | 
| 1273 1547 | 
             
                            //below required if element disable property was changed
         | 
| 1274 | 
            -
                            if(this | 
| 1548 | 
            +
                            if(this.isEmpty) {
         | 
| 1275 1549 | 
             
                                this.$element.empty();
         | 
| 1276 | 
            -
                                this | 
| 1550 | 
            +
                                if(this.options.emptyclass) {
         | 
| 1551 | 
            +
                                    this.$element.removeClass(this.options.emptyclass);
         | 
| 1552 | 
            +
                                }
         | 
| 1277 1553 | 
             
                            }
         | 
| 1278 1554 | 
             
                        }
         | 
| 1279 1555 | 
             
                    },        
         | 
| @@ -1291,9 +1567,11 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1291 1567 | 
             
                        //init editableContainer: popover, tooltip, inline, etc..
         | 
| 1292 1568 | 
             
                        if(!this.container) {
         | 
| 1293 1569 | 
             
                            var containerOptions = $.extend({}, this.options, {
         | 
| 1294 | 
            -
                                value: this.value
         | 
| 1570 | 
            +
                                value: this.value,
         | 
| 1571 | 
            +
                                input: this.input //pass input to form (as it is already created)
         | 
| 1295 1572 | 
             
                            });
         | 
| 1296 1573 | 
             
                            this.$element.editableContainer(containerOptions);
         | 
| 1574 | 
            +
                            //listen `save` event 
         | 
| 1297 1575 | 
             
                            this.$element.on("save.internal", $.proxy(this.save, this));
         | 
| 1298 1576 | 
             
                            this.container = this.$element.data('editableContainer'); 
         | 
| 1299 1577 | 
             
                        } else if(this.container.tip().is(':visible')) {
         | 
| @@ -1331,15 +1609,30 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1331 1609 | 
             
                    * called when form was submitted
         | 
| 1332 1610 | 
             
                    */          
         | 
| 1333 1611 | 
             
                    save: function(e, params) {
         | 
| 1334 | 
            -
                        // | 
| 1335 | 
            -
                        if( | 
| 1336 | 
            -
                             | 
| 1337 | 
            -
             | 
| 1338 | 
            -
             | 
| 1612 | 
            +
                        //mark element with unsaved class if needed
         | 
| 1613 | 
            +
                        if(this.options.unsavedclass) {
         | 
| 1614 | 
            +
                            /*
         | 
| 1615 | 
            +
                             Add unsaved css to element if:
         | 
| 1616 | 
            +
                              - url is not user's function 
         | 
| 1617 | 
            +
                              - value was not sent to server
         | 
| 1618 | 
            +
                              - params.response === undefined, that means data was not sent
         | 
| 1619 | 
            +
                              - value changed 
         | 
| 1620 | 
            +
                            */
         | 
| 1621 | 
            +
                            var sent = false;
         | 
| 1622 | 
            +
                            sent = sent || typeof this.options.url === 'function';
         | 
| 1623 | 
            +
                            sent = sent || this.options.display === false; 
         | 
| 1624 | 
            +
                            sent = sent || params.response !== undefined; 
         | 
| 1625 | 
            +
                            sent = sent || (this.options.savenochange && this.input.value2str(this.value) !== this.input.value2str(params.newValue)); 
         | 
| 1626 | 
            +
                            
         | 
| 1627 | 
            +
                            if(sent) {
         | 
| 1628 | 
            +
                                this.$element.removeClass(this.options.unsavedclass); 
         | 
| 1629 | 
            +
                            } else {
         | 
| 1630 | 
            +
                                this.$element.addClass(this.options.unsavedclass);                    
         | 
| 1631 | 
            +
                            }
         | 
| 1339 1632 | 
             
                        }
         | 
| 1340 1633 |  | 
| 1341 | 
            -
             | 
| 1342 | 
            -
                        this.setValue(params.newValue);
         | 
| 1634 | 
            +
                        //set new value
         | 
| 1635 | 
            +
                        this.setValue(params.newValue, false, params.response);
         | 
| 1343 1636 |  | 
| 1344 1637 | 
             
                        /**        
         | 
| 1345 1638 | 
             
                        Fired when new value was submitted. You can use <code>$(this).data('editable')</code> to access to editable instance
         | 
| @@ -1351,13 +1644,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1351 1644 | 
             
                        @param {Object} params.response ajax response
         | 
| 1352 1645 | 
             
                        @example
         | 
| 1353 1646 | 
             
                        $('#username').on('save', function(e, params) {
         | 
| 1354 | 
            -
                             | 
| 1355 | 
            -
                            var pk = $(this).data('editable').options.pk;
         | 
| 1356 | 
            -
                            if(params.response && params.response.success) {
         | 
| 1357 | 
            -
                                alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
         | 
| 1358 | 
            -
                            } else {
         | 
| 1359 | 
            -
                                alert('error!'); 
         | 
| 1360 | 
            -
                            } 
         | 
| 1647 | 
            +
                            alert('Saved value: ' + params.newValue);
         | 
| 1361 1648 | 
             
                        });
         | 
| 1362 1649 | 
             
                        **/
         | 
| 1363 1650 | 
             
                        //event itself is triggered by editableContainer. Description here is only for documentation              
         | 
| @@ -1375,7 +1662,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1375 1662 | 
             
                    @param {mixed} value new value 
         | 
| 1376 1663 | 
             
                    @param {boolean} convertStr whether to convert value from string to internal format
         | 
| 1377 1664 | 
             
                    **/         
         | 
| 1378 | 
            -
                    setValue: function(value, convertStr) {
         | 
| 1665 | 
            +
                    setValue: function(value, convertStr, response) {
         | 
| 1379 1666 | 
             
                        if(convertStr) {
         | 
| 1380 1667 | 
             
                            this.value = this.input.str2value(value);
         | 
| 1381 1668 | 
             
                        } else {
         | 
| @@ -1384,7 +1671,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1384 1671 | 
             
                        if(this.container) {
         | 
| 1385 1672 | 
             
                            this.container.option('value', this.value);
         | 
| 1386 1673 | 
             
                        }
         | 
| 1387 | 
            -
                        $.when(this.render())
         | 
| 1674 | 
            +
                        $.when(this.render(response))
         | 
| 1388 1675 | 
             
                        .then($.proxy(function() {
         | 
| 1389 1676 | 
             
                            this.handleEmpty();
         | 
| 1390 1677 | 
             
                        }, this));
         | 
| @@ -1398,7 +1685,28 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1398 1685 | 
             
                        if(this.container) {
         | 
| 1399 1686 | 
             
                           this.container.activate(); 
         | 
| 1400 1687 | 
             
                        }
         | 
| 1401 | 
            -
                    }
         | 
| 1688 | 
            +
                    },
         | 
| 1689 | 
            +
                    
         | 
| 1690 | 
            +
                    /**
         | 
| 1691 | 
            +
                    Removes editable feature from element
         | 
| 1692 | 
            +
                    @method destroy()
         | 
| 1693 | 
            +
                    **/        
         | 
| 1694 | 
            +
                    destroy: function() {
         | 
| 1695 | 
            +
                        if(this.container) {
         | 
| 1696 | 
            +
                           this.container.destroy(); 
         | 
| 1697 | 
            +
                        }
         | 
| 1698 | 
            +
             | 
| 1699 | 
            +
                        if(this.options.toggle !== 'manual') {
         | 
| 1700 | 
            +
                            this.$element.removeClass('editable-click');
         | 
| 1701 | 
            +
                            this.$element.off(this.options.toggle + '.editable');
         | 
| 1702 | 
            +
                        } 
         | 
| 1703 | 
            +
                        
         | 
| 1704 | 
            +
                        this.$element.off("save.internal");
         | 
| 1705 | 
            +
                        
         | 
| 1706 | 
            +
                        this.$element.removeClass('editable');
         | 
| 1707 | 
            +
                        this.$element.removeClass('editable-open');
         | 
| 1708 | 
            +
                        this.$element.removeData('editable');
         | 
| 1709 | 
            +
                    }        
         | 
| 1402 1710 | 
             
                };
         | 
| 1403 1711 |  | 
| 1404 1712 | 
             
                /* EDITABLE PLUGIN DEFINITION
         | 
| @@ -1415,7 +1723,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1415 1723 | 
             
                    url: '/post',
         | 
| 1416 1724 | 
             
                    pk: 1
         | 
| 1417 1725 | 
             
                });
         | 
| 1418 | 
            -
                **/ | 
| 1726 | 
            +
                **/
         | 
| 1419 1727 | 
             
                $.fn.editable = function (option) {
         | 
| 1420 1728 | 
             
                    //special API methods returning non-jquery object
         | 
| 1421 1729 | 
             
                    var result = {}, args = arguments, datakey = 'editable';
         | 
| @@ -1432,7 +1740,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1432 1740 | 
             
                          username: "username is required",
         | 
| 1433 1741 | 
             
                          fullname: "fullname should be minimum 3 letters length"
         | 
| 1434 1742 | 
             
                        }
         | 
| 1435 | 
            -
                        **/ | 
| 1743 | 
            +
                        **/
         | 
| 1436 1744 | 
             
                        case 'validate':
         | 
| 1437 1745 | 
             
                            this.each(function () {
         | 
| 1438 1746 | 
             
                                var $this = $(this), data = $this.data(datakey), error;
         | 
| @@ -1453,7 +1761,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1453 1761 | 
             
                        username: "superuser",
         | 
| 1454 1762 | 
             
                        fullname: "John"
         | 
| 1455 1763 | 
             
                        }
         | 
| 1456 | 
            -
                        **/ | 
| 1764 | 
            +
                        **/
         | 
| 1457 1765 | 
             
                        case 'getValue':
         | 
| 1458 1766 | 
             
                            this.each(function () {
         | 
| 1459 1767 | 
             
                                var $this = $(this), data = $this.data(datakey);
         | 
| @@ -1472,11 +1780,11 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1472 1780 | 
             
                        @param {object} options 
         | 
| 1473 1781 | 
             
                        @param {object} options.url url to submit data 
         | 
| 1474 1782 | 
             
                        @param {object} options.data additional data to submit
         | 
| 1475 | 
            -
                        @param {object} options.ajaxOptions additional ajax options | 
| 1783 | 
            +
                        @param {object} options.ajaxOptions additional ajax options
         | 
| 1476 1784 | 
             
                        @param {function} options.error(obj) error handler 
         | 
| 1477 1785 | 
             
                        @param {function} options.success(obj,config) success handler
         | 
| 1478 1786 | 
             
                        @returns {Object} jQuery object
         | 
| 1479 | 
            -
                        **/ | 
| 1787 | 
            +
                        **/
         | 
| 1480 1788 | 
             
                        case 'submit':  //collects value, validate and submit to server for creating new record
         | 
| 1481 1789 | 
             
                            var config = arguments[1] || {},
         | 
| 1482 1790 | 
             
                            $elems = this,
         | 
| @@ -1584,7 +1892,7 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1584 1892 | 
             
                    **/          
         | 
| 1585 1893 | 
             
                    autotext: 'auto', 
         | 
| 1586 1894 | 
             
                    /**
         | 
| 1587 | 
            -
                    Initial value of input.  | 
| 1895 | 
            +
                    Initial value of input. If not set, taken from element's text.
         | 
| 1588 1896 |  | 
| 1589 1897 | 
             
                    @property value 
         | 
| 1590 1898 | 
             
                    @type mixed
         | 
| @@ -1593,10 +1901,21 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1593 1901 | 
             
                    value: null,
         | 
| 1594 1902 | 
             
                    /**
         | 
| 1595 1903 | 
             
                    Callback to perform custom displaying of value in element's text.  
         | 
| 1596 | 
            -
                    If  | 
| 1597 | 
            -
                    If  | 
| 1904 | 
            +
                    If `null`, default input's display used.  
         | 
| 1905 | 
            +
                    If `false`, no displaying methods will be called, element's text will never change.  
         | 
| 1598 1906 | 
             
                    Runs under element's scope.  
         | 
| 1599 | 
            -
                     | 
| 1907 | 
            +
                    _Parameters:_  
         | 
| 1908 | 
            +
                    
         | 
| 1909 | 
            +
                    * `value` current value to be displayed
         | 
| 1910 | 
            +
                    * `response` server response (if display called after ajax submit), since 1.4.0
         | 
| 1911 | 
            +
                     
         | 
| 1912 | 
            +
                    For **inputs with source** (select, checklist) parameters are different:  
         | 
| 1913 | 
            +
                      
         | 
| 1914 | 
            +
                    * `value` current value to be displayed
         | 
| 1915 | 
            +
                    * `sourceData` array of items for current input (e.g. dropdown items) 
         | 
| 1916 | 
            +
                    * `response` server response (if display called after ajax submit), since 1.4.0
         | 
| 1917 | 
            +
                              
         | 
| 1918 | 
            +
                    To get currently selected items use `$.fn.editableutils.itemsByValue(value, sourceData)`.
         | 
| 1600 1919 |  | 
| 1601 1920 | 
             
                    @property display 
         | 
| 1602 1921 | 
             
                    @type function|boolean
         | 
| @@ -1604,11 +1923,63 @@ Makes editable any HTML element on the page. Applied as jQuery method. | |
| 1604 1923 | 
             
                    @since 1.2.0
         | 
| 1605 1924 | 
             
                    @example
         | 
| 1606 1925 | 
             
                    display: function(value, sourceData) {
         | 
| 1607 | 
            -
             | 
| 1608 | 
            -
             | 
| 1926 | 
            +
                       //display checklist as comma-separated values
         | 
| 1927 | 
            +
                       var html = [],
         | 
| 1928 | 
            +
                           checked = $.fn.editableutils.itemsByValue(value, sourceData);
         | 
| 1929 | 
            +
                           
         | 
| 1930 | 
            +
                       if(checked.length) {
         | 
| 1931 | 
            +
                           $.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
         | 
| 1932 | 
            +
                           $(this).html(html.join(', '));
         | 
| 1933 | 
            +
                       } else {
         | 
| 1934 | 
            +
                           $(this).empty(); 
         | 
| 1935 | 
            +
                       }
         | 
| 1609 1936 | 
             
                    }
         | 
| 1610 1937 | 
             
                    **/          
         | 
| 1611 | 
            -
                    display: null
         | 
| 1938 | 
            +
                    display: null,
         | 
| 1939 | 
            +
                    /**
         | 
| 1940 | 
            +
                    Css class applied when editable text is empty.
         | 
| 1941 | 
            +
             | 
| 1942 | 
            +
                    @property emptyclass 
         | 
| 1943 | 
            +
                    @type string
         | 
| 1944 | 
            +
                    @since 1.4.1        
         | 
| 1945 | 
            +
                    @default editable-empty
         | 
| 1946 | 
            +
                    **/        
         | 
| 1947 | 
            +
                    emptyclass: 'editable-empty',
         | 
| 1948 | 
            +
                    /**
         | 
| 1949 | 
            +
                    Css class applied when value was stored but not sent to server (`pk` is empty or `send = 'never'`).  
         | 
| 1950 | 
            +
                    You may set it to `null` if you work with editables locally and submit them together.  
         | 
| 1951 | 
            +
             | 
| 1952 | 
            +
                    @property unsavedclass 
         | 
| 1953 | 
            +
                    @type string
         | 
| 1954 | 
            +
                    @since 1.4.1        
         | 
| 1955 | 
            +
                    @default editable-unsaved
         | 
| 1956 | 
            +
                    **/        
         | 
| 1957 | 
            +
                    unsavedclass: 'editable-unsaved',
         | 
| 1958 | 
            +
                    /**
         | 
| 1959 | 
            +
                    If a css selector is provided, editable will be delegated to the specified targets.  
         | 
| 1960 | 
            +
                    Usefull for dynamically generated DOM elements.  
         | 
| 1961 | 
            +
                    **Please note**, that delegated targets can't use `emptytext` and `autotext` options, 
         | 
| 1962 | 
            +
                    as they are initialized after first click.    
         | 
| 1963 | 
            +
             | 
| 1964 | 
            +
                    @property selector 
         | 
| 1965 | 
            +
                    @type string
         | 
| 1966 | 
            +
                    @since 1.4.1        
         | 
| 1967 | 
            +
                    @default null
         | 
| 1968 | 
            +
                    @example
         | 
| 1969 | 
            +
                    <div id="user">
         | 
| 1970 | 
            +
                      <a href="#" data-name="username" data-type="text" title="Username">awesome</a>
         | 
| 1971 | 
            +
                      <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a>
         | 
| 1972 | 
            +
                    </div>     
         | 
| 1973 | 
            +
                    
         | 
| 1974 | 
            +
                    <script>
         | 
| 1975 | 
            +
                    $('#user').editable({
         | 
| 1976 | 
            +
                        selector: 'a',
         | 
| 1977 | 
            +
                        url: '/post',
         | 
| 1978 | 
            +
                        pk: 1
         | 
| 1979 | 
            +
                    });
         | 
| 1980 | 
            +
                    </script>
         | 
| 1981 | 
            +
                    **/         
         | 
| 1982 | 
            +
                    selector: null        
         | 
| 1612 1983 | 
             
                };
         | 
| 1613 1984 |  | 
| 1614 1985 | 
             
            }(window.jQuery));
         | 
| @@ -1635,26 +2006,27 @@ To create your own input you can inherit from this class. | |
| 1635 2006 | 
             
                    **/
         | 
| 1636 2007 | 
             
                   init: function(type, options, defaults) {
         | 
| 1637 2008 | 
             
                       this.type = type;
         | 
| 1638 | 
            -
                       this.options = $.extend({}, defaults, options); | 
| 1639 | 
            -
             | 
| 1640 | 
            -
             | 
| 1641 | 
            -
             | 
| 2009 | 
            +
                       this.options = $.extend({}, defaults, options);
         | 
| 2010 | 
            +
                   },
         | 
| 2011 | 
            +
                   
         | 
| 2012 | 
            +
                   /*
         | 
| 2013 | 
            +
                   this method called before render to init $tpl that is inserted in DOM
         | 
| 2014 | 
            +
                   */
         | 
| 2015 | 
            +
                   prerender: function() {
         | 
| 2016 | 
            +
                       this.$tpl = $(this.options.tpl); //whole tpl as jquery object    
         | 
| 2017 | 
            +
                       this.$input = this.$tpl;         //control itself, can be changed in render method
         | 
| 2018 | 
            +
                       this.$clear = null;              //clear button
         | 
| 2019 | 
            +
                       this.error = null;               //error message, if input cannot be rendered           
         | 
| 1642 2020 | 
             
                   },
         | 
| 1643 2021 |  | 
| 1644 2022 | 
             
                   /**
         | 
| 1645 2023 | 
             
                    Renders input from tpl. Can return jQuery deferred object.
         | 
| 2024 | 
            +
                    Can be overwritten in child objects
         | 
| 1646 2025 |  | 
| 1647 2026 | 
             
                    @method render() 
         | 
| 1648 2027 | 
             
                   **/       
         | 
| 1649 2028 | 
             
                   render: function() {
         | 
| 1650 | 
            -
             | 
| 1651 | 
            -
                        if(this.options.inputclass) {
         | 
| 1652 | 
            -
                            this.$input.addClass(this.options.inputclass); 
         | 
| 1653 | 
            -
                        }
         | 
| 1654 | 
            -
                        
         | 
| 1655 | 
            -
                        if (this.options.placeholder) {
         | 
| 1656 | 
            -
                            this.$input.attr('placeholder', this.options.placeholder);
         | 
| 1657 | 
            -
                        }   
         | 
| 2029 | 
            +
             | 
| 1658 2030 | 
             
                   }, 
         | 
| 1659 2031 |  | 
| 1660 2032 | 
             
                   /**
         | 
| @@ -1691,7 +2063,7 @@ To create your own input you can inherit from this class. | |
| 1691 2063 | 
             
                   }, 
         | 
| 1692 2064 |  | 
| 1693 2065 | 
             
                   /**
         | 
| 1694 | 
            -
                    Converts string received from server into value.
         | 
| 2066 | 
            +
                    Converts string received from server into value. Usually from `data-value` attribute.
         | 
| 1695 2067 |  | 
| 1696 2068 | 
             
                    @method str2value(str) 
         | 
| 1697 2069 | 
             
                    @param {string} str
         | 
| @@ -1702,7 +2074,7 @@ To create your own input you can inherit from this class. | |
| 1702 2074 | 
             
                   }, 
         | 
| 1703 2075 |  | 
| 1704 2076 | 
             
                   /**
         | 
| 1705 | 
            -
                    Converts value for submitting to server
         | 
| 2077 | 
            +
                    Converts value for submitting to server. Result can be string or object.
         | 
| 1706 2078 |  | 
| 1707 2079 | 
             
                    @method value2submit(value) 
         | 
| 1708 2080 | 
             
                    @param {mixed} value
         | 
| @@ -1763,7 +2135,25 @@ To create your own input you can inherit from this class. | |
| 1763 2135 | 
             
                   **/       
         | 
| 1764 2136 | 
             
                   autosubmit: function() {
         | 
| 1765 2137 |  | 
| 2138 | 
            +
                   },
         | 
| 2139 | 
            +
                   
         | 
| 2140 | 
            +
                   // -------- helper functions --------
         | 
| 2141 | 
            +
                   setClass: function() {
         | 
| 2142 | 
            +
                       if(this.options.inputclass) {
         | 
| 2143 | 
            +
                           this.$input.addClass(this.options.inputclass); 
         | 
| 2144 | 
            +
                       } 
         | 
| 2145 | 
            +
                   },
         | 
| 2146 | 
            +
                   
         | 
| 2147 | 
            +
                   setAttr: function(attr) {
         | 
| 2148 | 
            +
                       if (this.options[attr]) {
         | 
| 2149 | 
            +
                           this.$input.attr(attr, this.options[attr]);
         | 
| 2150 | 
            +
                       } 
         | 
| 2151 | 
            +
                   },
         | 
| 2152 | 
            +
                   
         | 
| 2153 | 
            +
                   option: function(key, value) {
         | 
| 2154 | 
            +
                        this.options[key] = value;
         | 
| 1766 2155 | 
             
                   }
         | 
| 2156 | 
            +
                   
         | 
| 1767 2157 | 
             
                };
         | 
| 1768 2158 |  | 
| 1769 2159 | 
             
                AbstractInput.defaults = {  
         | 
| @@ -1782,15 +2172,7 @@ To create your own input you can inherit from this class. | |
| 1782 2172 | 
             
                    @type string
         | 
| 1783 2173 | 
             
                    @default input-medium
         | 
| 1784 2174 | 
             
                    **/         
         | 
| 1785 | 
            -
                    inputclass: 'input-medium' | 
| 1786 | 
            -
                    /**
         | 
| 1787 | 
            -
                    Name attribute of input
         | 
| 1788 | 
            -
             | 
| 1789 | 
            -
                    @property name 
         | 
| 1790 | 
            -
                    @type string
         | 
| 1791 | 
            -
                    @default null
         | 
| 1792 | 
            -
                    **/         
         | 
| 1793 | 
            -
                    name: null
         | 
| 2175 | 
            +
                    inputclass: 'input-medium'
         | 
| 1794 2176 | 
             
                };
         | 
| 1795 2177 |  | 
| 1796 2178 | 
             
                $.extend($.fn.editabletypes, {abstractinput: AbstractInput});
         | 
| @@ -1813,11 +2195,9 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1813 2195 |  | 
| 1814 2196 | 
             
                $.extend(List.prototype, {
         | 
| 1815 2197 | 
             
                    render: function () {
         | 
| 1816 | 
            -
                        List.superclass.render.call(this);
         | 
| 1817 2198 | 
             
                        var deferred = $.Deferred();
         | 
| 2199 | 
            +
             | 
| 1818 2200 | 
             
                        this.error = null;
         | 
| 1819 | 
            -
                        this.sourceData = null;
         | 
| 1820 | 
            -
                        this.prependData = null;
         | 
| 1821 2201 | 
             
                        this.onSourceReady(function () {
         | 
| 1822 2202 | 
             
                            this.renderList();
         | 
| 1823 2203 | 
             
                            deferred.resolve();
         | 
| @@ -1833,20 +2213,24 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1833 2213 | 
             
                        return null; //can't set value by text
         | 
| 1834 2214 | 
             
                    },
         | 
| 1835 2215 |  | 
| 1836 | 
            -
                    value2html: function (value, element, display) {
         | 
| 1837 | 
            -
                        var deferred = $.Deferred() | 
| 1838 | 
            -
             | 
| 1839 | 
            -
             | 
| 1840 | 
            -
             | 
| 1841 | 
            -
             | 
| 1842 | 
            -
             | 
| 1843 | 
            -
             | 
| 1844 | 
            -
             | 
| 1845 | 
            -
             | 
| 1846 | 
            -
             | 
| 1847 | 
            -
             | 
| 1848 | 
            -
             | 
| 1849 | 
            -
                         | 
| 2216 | 
            +
                    value2html: function (value, element, display, response) {
         | 
| 2217 | 
            +
                        var deferred = $.Deferred(),
         | 
| 2218 | 
            +
                            success = function () {
         | 
| 2219 | 
            +
                                if(typeof display === 'function') {
         | 
| 2220 | 
            +
                                    //custom display method
         | 
| 2221 | 
            +
                                    display.call(element, value, this.sourceData, response); 
         | 
| 2222 | 
            +
                                } else {
         | 
| 2223 | 
            +
                                    this.value2htmlFinal(value, element);
         | 
| 2224 | 
            +
                                }
         | 
| 2225 | 
            +
                                deferred.resolve();
         | 
| 2226 | 
            +
                           };
         | 
| 2227 | 
            +
                        
         | 
| 2228 | 
            +
                        //for null value just call success without loading source
         | 
| 2229 | 
            +
                        if(value === null) {
         | 
| 2230 | 
            +
                           success.call(this);   
         | 
| 2231 | 
            +
                        } else {
         | 
| 2232 | 
            +
                           this.onSourceReady(success, function () { deferred.resolve(); });
         | 
| 2233 | 
            +
                        }
         | 
| 1850 2234 |  | 
| 1851 2235 | 
             
                        return deferred.promise();
         | 
| 1852 2236 | 
             
                    },  
         | 
| @@ -1872,7 +2256,7 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1872 2256 | 
             
                        if (typeof this.options.source === 'string') {
         | 
| 1873 2257 | 
             
                            //try to get from cache
         | 
| 1874 2258 | 
             
                            if(this.options.sourceCache) {
         | 
| 1875 | 
            -
                                var cacheID = this.options.source | 
| 2259 | 
            +
                                var cacheID = this.options.source,
         | 
| 1876 2260 | 
             
                                cache;
         | 
| 1877 2261 |  | 
| 1878 2262 | 
             
                                if (!$(document).data(cacheID)) {
         | 
| @@ -1883,11 +2267,13 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1883 2267 | 
             
                                //check for cached data
         | 
| 1884 2268 | 
             
                                if (cache.loading === false && cache.sourceData) { //take source from cache
         | 
| 1885 2269 | 
             
                                    this.sourceData = cache.sourceData;
         | 
| 2270 | 
            +
                                    this.doPrepend();
         | 
| 1886 2271 | 
             
                                    success.call(this);
         | 
| 1887 2272 | 
             
                                    return;
         | 
| 1888 2273 | 
             
                                } else if (cache.loading === true) { //cache is loading, put callback in stack to be called later
         | 
| 1889 2274 | 
             
                                    cache.callbacks.push($.proxy(function () {
         | 
| 1890 2275 | 
             
                                        this.sourceData = cache.sourceData;
         | 
| 2276 | 
            +
                                        this.doPrepend();
         | 
| 1891 2277 | 
             
                                        success.call(this);
         | 
| 1892 2278 | 
             
                                    }, this));
         | 
| 1893 2279 |  | 
| @@ -1906,7 +2292,6 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1906 2292 | 
             
                                url: this.options.source,
         | 
| 1907 2293 | 
             
                                type: 'get',
         | 
| 1908 2294 | 
             
                                cache: false,
         | 
| 1909 | 
            -
                                data: this.options.name ? {name: this.options.name} : {},
         | 
| 1910 2295 | 
             
                                dataType: 'json',
         | 
| 1911 2296 | 
             
                                success: $.proxy(function (data) {
         | 
| 1912 2297 | 
             
                                    if(cache) {
         | 
| @@ -1914,17 +2299,19 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1914 2299 | 
             
                                    }
         | 
| 1915 2300 | 
             
                                    this.sourceData = this.makeArray(data);
         | 
| 1916 2301 | 
             
                                    if($.isArray(this.sourceData)) {
         | 
| 1917 | 
            -
                                        this.doPrepend();
         | 
| 1918 | 
            -
                                        success.call(this);
         | 
| 1919 2302 | 
             
                                        if(cache) {
         | 
| 1920 2303 | 
             
                                            //store result in cache
         | 
| 1921 2304 | 
             
                                            cache.sourceData = this.sourceData;
         | 
| 1922 | 
            -
                                             | 
| 2305 | 
            +
                                            //run success callbacks for other fields waiting for this source
         | 
| 2306 | 
            +
                                            $.each(cache.callbacks, function () { this.call(); }); 
         | 
| 1923 2307 | 
             
                                        }
         | 
| 2308 | 
            +
                                        this.doPrepend();
         | 
| 2309 | 
            +
                                        success.call(this);
         | 
| 1924 2310 | 
             
                                    } else {
         | 
| 1925 2311 | 
             
                                        error.call(this);
         | 
| 1926 2312 | 
             
                                        if(cache) {
         | 
| 1927 | 
            -
                                             | 
| 2313 | 
            +
                                            //run error callbacks for other fields waiting for this source
         | 
| 2314 | 
            +
                                            $.each(cache.err_callbacks, function () { this.call(); }); 
         | 
| 1928 2315 | 
             
                                        }
         | 
| 1929 2316 | 
             
                                    }
         | 
| 1930 2317 | 
             
                                }, this),
         | 
| @@ -1937,8 +2324,13 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1937 2324 | 
             
                                    }
         | 
| 1938 2325 | 
             
                                }, this)
         | 
| 1939 2326 | 
             
                            });
         | 
| 1940 | 
            -
                        } else { //options as json/array
         | 
| 1941 | 
            -
                             | 
| 2327 | 
            +
                        } else { //options as json/array/function
         | 
| 2328 | 
            +
                            if ($.isFunction(this.options.source)) {
         | 
| 2329 | 
            +
                               this.sourceData = this.makeArray(this.options.source());
         | 
| 2330 | 
            +
                            } else {
         | 
| 2331 | 
            +
                               this.sourceData = this.makeArray(this.options.source);
         | 
| 2332 | 
            +
                            }
         | 
| 2333 | 
            +
                                
         | 
| 1942 2334 | 
             
                            if($.isArray(this.sourceData)) {
         | 
| 1943 2335 | 
             
                                this.doPrepend();
         | 
| 1944 2336 | 
             
                                success.call(this);   
         | 
| @@ -1959,7 +2351,11 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1959 2351 | 
             
                            if (typeof this.options.prepend === 'string') {
         | 
| 1960 2352 | 
             
                                this.options.prepend = {'': this.options.prepend};
         | 
| 1961 2353 | 
             
                            }              
         | 
| 1962 | 
            -
                             | 
| 2354 | 
            +
                            if (typeof this.options.prepend === 'function') {
         | 
| 2355 | 
            +
                                this.prependData = this.makeArray(this.options.prepend());
         | 
| 2356 | 
            +
                            } else {
         | 
| 2357 | 
            +
                                this.prependData = this.makeArray(this.options.prepend);
         | 
| 2358 | 
            +
                            }
         | 
| 1963 2359 | 
             
                        }
         | 
| 1964 2360 |  | 
| 1965 2361 | 
             
                        if($.isArray(this.prependData) && $.isArray(this.sourceData)) {
         | 
| @@ -1985,35 +2381,45 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 1985 2381 | 
             
                    * convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}]
         | 
| 1986 2382 | 
             
                    */
         | 
| 1987 2383 | 
             
                    makeArray: function(data) {
         | 
| 1988 | 
            -
                        var count, obj, result = [],  | 
| 2384 | 
            +
                        var count, obj, result = [], item, iterateItem;
         | 
| 1989 2385 | 
             
                        if(!data || typeof data === 'string') {
         | 
| 1990 2386 | 
             
                            return null; 
         | 
| 1991 2387 | 
             
                        }
         | 
| 1992 2388 |  | 
| 1993 2389 | 
             
                        if($.isArray(data)) { //array
         | 
| 1994 | 
            -
                             | 
| 2390 | 
            +
                            /* 
         | 
| 2391 | 
            +
                               function to iterate inside item of array if item is object.
         | 
| 2392 | 
            +
                               Caclulates count of keys in item and store in obj. 
         | 
| 2393 | 
            +
                            */
         | 
| 2394 | 
            +
                            iterateItem = function (k, v) {
         | 
| 1995 2395 | 
             
                                obj = {value: k, text: v};
         | 
| 1996 2396 | 
             
                                if(count++ >= 2) {
         | 
| 1997 | 
            -
                                    return false;// exit each if  | 
| 2397 | 
            +
                                    return false;// exit from `each` if item has more than one key.
         | 
| 1998 2398 | 
             
                                }
         | 
| 1999 2399 | 
             
                            };
         | 
| 2000 2400 |  | 
| 2001 2401 | 
             
                            for(var i = 0; i < data.length; i++) {
         | 
| 2002 | 
            -
                                 | 
| 2003 | 
            -
             | 
| 2004 | 
            -
                                     | 
| 2005 | 
            -
                                     | 
| 2402 | 
            +
                                item = data[i]; 
         | 
| 2403 | 
            +
                                if(typeof item === 'object') {
         | 
| 2404 | 
            +
                                    count = 0; //count of keys inside item
         | 
| 2405 | 
            +
                                    $.each(item, iterateItem);
         | 
| 2406 | 
            +
                                    //case: [{val1: 'text1'}, {val2: 'text2} ...]
         | 
| 2407 | 
            +
                                    if(count === 1) { 
         | 
| 2006 2408 | 
             
                                        result.push(obj); 
         | 
| 2007 | 
            -
             | 
| 2008 | 
            -
             | 
| 2009 | 
            -
             | 
| 2010 | 
            -
                                         | 
| 2409 | 
            +
                                        //case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
         | 
| 2410 | 
            +
                                    } else if(count > 1) {
         | 
| 2411 | 
            +
                                        //removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
         | 
| 2412 | 
            +
                                        if(item.children) {
         | 
| 2413 | 
            +
                                            item.children = this.makeArray(item.children);   
         | 
| 2414 | 
            +
                                        }
         | 
| 2415 | 
            +
                                        result.push(item);
         | 
| 2011 2416 | 
             
                                    }
         | 
| 2012 2417 | 
             
                                } else {
         | 
| 2013 | 
            -
                                     | 
| 2418 | 
            +
                                    //case: ['text1', 'text2' ...]
         | 
| 2419 | 
            +
                                    result.push({value: item, text: item}); 
         | 
| 2014 2420 | 
             
                                }
         | 
| 2015 2421 | 
             
                            }
         | 
| 2016 | 
            -
                        } else {  // | 
| 2422 | 
            +
                        } else {  //case: {val1: 'text1', val2: 'text2, ...}
         | 
| 2017 2423 | 
             
                            $.each(data, function (k, v) {
         | 
| 2018 2424 | 
             
                                result.push({value: k, text: v});
         | 
| 2019 2425 | 
             
                            });  
         | 
| @@ -2021,41 +2427,45 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 2021 2427 | 
             
                        return result;
         | 
| 2022 2428 | 
             
                    },
         | 
| 2023 2429 |  | 
| 2024 | 
            -
                     | 
| 2025 | 
            -
             | 
| 2026 | 
            -
                        if( | 
| 2027 | 
            -
                             | 
| 2028 | 
            -
                                /*jshint eqeqeq: false*/
         | 
| 2029 | 
            -
                                if(this.sourceData[i].value == val) {
         | 
| 2030 | 
            -
                                /*jshint eqeqeq: true*/                            
         | 
| 2031 | 
            -
                                    return this.sourceData[i];
         | 
| 2032 | 
            -
                                }
         | 
| 2033 | 
            -
                            }
         | 
| 2430 | 
            +
                    option: function(key, value) {
         | 
| 2431 | 
            +
                        this.options[key] = value;
         | 
| 2432 | 
            +
                        if(key === 'source') {
         | 
| 2433 | 
            +
                            this.sourceData = null;
         | 
| 2034 2434 | 
             
                        }
         | 
| 2435 | 
            +
                        if(key === 'prepend') {
         | 
| 2436 | 
            +
                            this.prependData = null;
         | 
| 2437 | 
            +
                        }            
         | 
| 2035 2438 | 
             
                    }        
         | 
| 2036 2439 |  | 
| 2037 2440 | 
             
                });      
         | 
| 2038 2441 |  | 
| 2039 2442 | 
             
                List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
         | 
| 2040 2443 | 
             
                    /**
         | 
| 2041 | 
            -
                    Source data for list. | 
| 2042 | 
            -
                     | 
| 2043 | 
            -
                    For compability  | 
| 2044 | 
            -
                     | 
| 2444 | 
            +
                    Source data for list.  
         | 
| 2445 | 
            +
                    If **array** - it should be in format: `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`  
         | 
| 2446 | 
            +
                    For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
         | 
| 2447 | 
            +
                    
         | 
| 2448 | 
            +
                    If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option.
         | 
| 2449 | 
            +
                      
         | 
| 2450 | 
            +
                    If **function**, it should return data in format above (since 1.4.0).
         | 
| 2045 2451 |  | 
| 2452 | 
            +
                    Since 1.4.1 key `children` supported to render OPTGROUP (for **select** input only).  
         | 
| 2453 | 
            +
                    `[{text: "group1", children: [{value: 1, text: "text1"}, {value: 2, text: "text2"}]}, ...]` 
         | 
| 2454 | 
            +
             | 
| 2455 | 
            +
            		
         | 
| 2046 2456 | 
             
                    @property source 
         | 
| 2047 | 
            -
                    @type string|array|object
         | 
| 2457 | 
            +
                    @type string | array | object | function
         | 
| 2048 2458 | 
             
                    @default null
         | 
| 2049 2459 | 
             
                    **/         
         | 
| 2050 | 
            -
                    source:null, 
         | 
| 2460 | 
            +
                    source: null, 
         | 
| 2051 2461 | 
             
                    /**
         | 
| 2052 2462 | 
             
                    Data automatically prepended to the beginning of dropdown list.
         | 
| 2053 2463 |  | 
| 2054 2464 | 
             
                    @property prepend 
         | 
| 2055 | 
            -
                    @type string|array|object
         | 
| 2465 | 
            +
                    @type string | array | object | function
         | 
| 2056 2466 | 
             
                    @default false
         | 
| 2057 2467 | 
             
                    **/         
         | 
| 2058 | 
            -
                    prepend:false,
         | 
| 2468 | 
            +
                    prepend: false,
         | 
| 2059 2469 | 
             
                    /**
         | 
| 2060 2470 | 
             
                    Error message when list cannot be loaded (e.g. ajax error)
         | 
| 2061 2471 |  | 
| @@ -2065,8 +2475,8 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 2065 2475 | 
             
                    **/          
         | 
| 2066 2476 | 
             
                    sourceError: 'Error when loading list',
         | 
| 2067 2477 | 
             
                    /**
         | 
| 2068 | 
            -
                    if <code>true</code> and source is **string url** - results will be cached for fields with the same source | 
| 2069 | 
            -
                    Usefull for editable  | 
| 2478 | 
            +
                    if <code>true</code> and source is **string url** - results will be cached for fields with the same source.    
         | 
| 2479 | 
            +
                    Usefull for editable column in grid to prevent extra requests.
         | 
| 2070 2480 |  | 
| 2071 2481 | 
             
                    @property sourceCache 
         | 
| 2072 2482 | 
             
                    @type boolean
         | 
| @@ -2078,7 +2488,8 @@ List - abstract class for inputs that have source option loaded from js array or | |
| 2078 2488 |  | 
| 2079 2489 | 
             
                $.fn.editabletypes.list = List;      
         | 
| 2080 2490 |  | 
| 2081 | 
            -
            }(window.jQuery));
         | 
| 2491 | 
            +
            }(window.jQuery));
         | 
| 2492 | 
            +
             | 
| 2082 2493 | 
             
            /**
         | 
| 2083 2494 | 
             
            Text input
         | 
| 2084 2495 |  | 
| @@ -2104,12 +2515,67 @@ $(function(){ | |
| 2104 2515 | 
             
                $.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);
         | 
| 2105 2516 |  | 
| 2106 2517 | 
             
                $.extend(Text.prototype, {
         | 
| 2518 | 
            +
                    render: function() {
         | 
| 2519 | 
            +
                       this.renderClear();
         | 
| 2520 | 
            +
                       this.setClass();
         | 
| 2521 | 
            +
                       this.setAttr('placeholder');
         | 
| 2522 | 
            +
                    },
         | 
| 2523 | 
            +
                    
         | 
| 2107 2524 | 
             
                    activate: function() {
         | 
| 2108 2525 | 
             
                        if(this.$input.is(':visible')) {
         | 
| 2109 2526 | 
             
                            this.$input.focus();
         | 
| 2110 2527 | 
             
                            $.fn.editableutils.setCursorPosition(this.$input.get(0), this.$input.val().length);
         | 
| 2528 | 
            +
                            if(this.toggleClear) {
         | 
| 2529 | 
            +
                                this.toggleClear();
         | 
| 2530 | 
            +
                            }
         | 
| 2111 2531 | 
             
                        }
         | 
| 2112 | 
            -
                    } | 
| 2532 | 
            +
                    },
         | 
| 2533 | 
            +
                    
         | 
| 2534 | 
            +
                    //render clear button
         | 
| 2535 | 
            +
                    renderClear:  function() {
         | 
| 2536 | 
            +
                       if (this.options.clear) {
         | 
| 2537 | 
            +
                           this.$clear = $('<span class="editable-clear-x"></span>');
         | 
| 2538 | 
            +
                           this.$input.after(this.$clear)
         | 
| 2539 | 
            +
                                      .css('padding-right', 20)
         | 
| 2540 | 
            +
                                      .keyup($.proxy(this.toggleClear, this))
         | 
| 2541 | 
            +
                                      .parent().css('position', 'relative');
         | 
| 2542 | 
            +
                                      
         | 
| 2543 | 
            +
                           this.$clear.click($.proxy(this.clear, this));                       
         | 
| 2544 | 
            +
                       }            
         | 
| 2545 | 
            +
                    },
         | 
| 2546 | 
            +
                    
         | 
| 2547 | 
            +
                    postrender: function() {
         | 
| 2548 | 
            +
                        if(this.$clear) {
         | 
| 2549 | 
            +
                            //can position clear button only here, when form is shown and height can be calculated
         | 
| 2550 | 
            +
                            var h = this.$input.outerHeight() || 20,
         | 
| 2551 | 
            +
                                delta = (h - this.$clear.height()) / 2;
         | 
| 2552 | 
            +
                            
         | 
| 2553 | 
            +
                            //workaround for plain-popup  
         | 
| 2554 | 
            +
                            if(delta < 3) {
         | 
| 2555 | 
            +
                               delta = 3; 
         | 
| 2556 | 
            +
                            }
         | 
| 2557 | 
            +
                                
         | 
| 2558 | 
            +
                            this.$clear.css({top: delta, right: delta});
         | 
| 2559 | 
            +
                        } 
         | 
| 2560 | 
            +
                    },
         | 
| 2561 | 
            +
                    
         | 
| 2562 | 
            +
                    //show / hide clear button
         | 
| 2563 | 
            +
                    toggleClear: function() {
         | 
| 2564 | 
            +
                        if(!this.$clear) {
         | 
| 2565 | 
            +
                            return;
         | 
| 2566 | 
            +
                        }
         | 
| 2567 | 
            +
                        
         | 
| 2568 | 
            +
                        if(this.$input.val().length) {
         | 
| 2569 | 
            +
                            this.$clear.show();
         | 
| 2570 | 
            +
                        } else {
         | 
| 2571 | 
            +
                            this.$clear.hide();
         | 
| 2572 | 
            +
                        } 
         | 
| 2573 | 
            +
                    },
         | 
| 2574 | 
            +
                    
         | 
| 2575 | 
            +
                    clear: function() {
         | 
| 2576 | 
            +
                       this.$clear.hide();
         | 
| 2577 | 
            +
                       this.$input.val('').focus();
         | 
| 2578 | 
            +
                    }          
         | 
| 2113 2579 | 
             
                });
         | 
| 2114 2580 |  | 
| 2115 2581 | 
             
                Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
         | 
| @@ -2125,7 +2591,16 @@ $(function(){ | |
| 2125 2591 | 
             
                    @type string
         | 
| 2126 2592 | 
             
                    @default null
         | 
| 2127 2593 | 
             
                    **/             
         | 
| 2128 | 
            -
                    placeholder: null
         | 
| 2594 | 
            +
                    placeholder: null,
         | 
| 2595 | 
            +
                    
         | 
| 2596 | 
            +
                    /**
         | 
| 2597 | 
            +
                    Whether to show `clear` button 
         | 
| 2598 | 
            +
                    
         | 
| 2599 | 
            +
                    @property clear 
         | 
| 2600 | 
            +
                    @type boolean
         | 
| 2601 | 
            +
                    @default true        
         | 
| 2602 | 
            +
                    **/
         | 
| 2603 | 
            +
                    clear: true
         | 
| 2129 2604 | 
             
                });
         | 
| 2130 2605 |  | 
| 2131 2606 | 
             
                $.fn.editabletypes.text = Text;
         | 
| @@ -2144,7 +2619,8 @@ Textarea input | |
| 2144 2619 | 
             
            $(function(){
         | 
| 2145 2620 | 
             
                $('#comments').editable({
         | 
| 2146 2621 | 
             
                    url: '/post',
         | 
| 2147 | 
            -
                    title: 'Enter comments'
         | 
| 2622 | 
            +
                    title: 'Enter comments',
         | 
| 2623 | 
            +
                    rows: 10
         | 
| 2148 2624 | 
             
                });
         | 
| 2149 2625 | 
             
            });
         | 
| 2150 2626 | 
             
            </script>
         | 
| @@ -2159,8 +2635,10 @@ $(function(){ | |
| 2159 2635 |  | 
| 2160 2636 | 
             
                $.extend(Textarea.prototype, {
         | 
| 2161 2637 | 
             
                    render: function () {
         | 
| 2162 | 
            -
                         | 
| 2163 | 
            -
             | 
| 2638 | 
            +
                        this.setClass();
         | 
| 2639 | 
            +
                        this.setAttr('placeholder');
         | 
| 2640 | 
            +
                        this.setAttr('rows');                        
         | 
| 2641 | 
            +
                        
         | 
| 2164 2642 | 
             
                        //ctrl + enter
         | 
| 2165 2643 | 
             
                        this.$input.keydown(function (e) {
         | 
| 2166 2644 | 
             
                            if (e.ctrlKey && e.which === 13) {
         | 
| @@ -2185,43 +2663,56 @@ $(function(){ | |
| 2185 2663 | 
             
                        if(!html) {
         | 
| 2186 2664 | 
             
                            return '';
         | 
| 2187 2665 | 
             
                        }
         | 
| 2666 | 
            +
             | 
| 2667 | 
            +
                        var regex = new RegExp(String.fromCharCode(10), 'g');
         | 
| 2188 2668 | 
             
                        var lines = html.split(/<br\s*\/?>/i);
         | 
| 2189 2669 | 
             
                        for (var i = 0; i < lines.length; i++) {
         | 
| 2190 | 
            -
                             | 
| 2670 | 
            +
                            var text = $('<div>').html(lines[i]).text();
         | 
| 2671 | 
            +
             | 
| 2672 | 
            +
                            // Remove newline characters (\n) to avoid them being converted by value2html() method
         | 
| 2673 | 
            +
                            // thus adding extra <br> tags
         | 
| 2674 | 
            +
                            text = text.replace(regex, '');
         | 
| 2675 | 
            +
             | 
| 2676 | 
            +
                            lines[i] = text;
         | 
| 2191 2677 | 
             
                        }
         | 
| 2192 | 
            -
                        return lines.join("\n"); | 
| 2193 | 
            -
                    }, | 
| 2678 | 
            +
                        return lines.join("\n");
         | 
| 2679 | 
            +
                    },
         | 
| 2194 2680 |  | 
| 2195 2681 | 
             
                    activate: function() {
         | 
| 2196 | 
            -
                         | 
| 2197 | 
            -
             | 
| 2198 | 
            -
                            this.$input.focus();
         | 
| 2199 | 
            -
                        }
         | 
| 2200 | 
            -
                    }         
         | 
| 2682 | 
            +
                        $.fn.editabletypes.text.prototype.activate.call(this);
         | 
| 2683 | 
            +
                    }
         | 
| 2201 2684 | 
             
                });
         | 
| 2202 2685 |  | 
| 2203 2686 | 
             
                Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
         | 
| 2204 2687 | 
             
                    /**
         | 
| 2205 | 
            -
                    @property tpl | 
| 2688 | 
            +
                    @property tpl
         | 
| 2206 2689 | 
             
                    @default <textarea></textarea>
         | 
| 2207 | 
            -
                    **/ | 
| 2690 | 
            +
                    **/
         | 
| 2208 2691 | 
             
                    tpl:'<textarea></textarea>',
         | 
| 2209 2692 | 
             
                    /**
         | 
| 2210 | 
            -
                    @property inputclass | 
| 2693 | 
            +
                    @property inputclass
         | 
| 2211 2694 | 
             
                    @default input-large
         | 
| 2212 | 
            -
                    **/ | 
| 2695 | 
            +
                    **/
         | 
| 2213 2696 | 
             
                    inputclass: 'input-large',
         | 
| 2214 2697 | 
             
                    /**
         | 
| 2215 2698 | 
             
                    Placeholder attribute of input. Shown when input is empty.
         | 
| 2216 2699 |  | 
| 2217 | 
            -
                    @property placeholder | 
| 2700 | 
            +
                    @property placeholder
         | 
| 2218 2701 | 
             
                    @type string
         | 
| 2219 2702 | 
             
                    @default null
         | 
| 2220 | 
            -
                    **/ | 
| 2221 | 
            -
                    placeholder: null | 
| 2703 | 
            +
                    **/
         | 
| 2704 | 
            +
                    placeholder: null,
         | 
| 2705 | 
            +
                    /**
         | 
| 2706 | 
            +
                    Number of rows in textarea
         | 
| 2707 | 
            +
             | 
| 2708 | 
            +
                    @property rows
         | 
| 2709 | 
            +
                    @type integer
         | 
| 2710 | 
            +
                    @default 7
         | 
| 2711 | 
            +
                    **/        
         | 
| 2712 | 
            +
                    rows: 7        
         | 
| 2222 2713 | 
             
                });
         | 
| 2223 2714 |  | 
| 2224 | 
            -
                $.fn.editabletypes.textarea = Textarea; | 
| 2715 | 
            +
                $.fn.editabletypes.textarea = Textarea;
         | 
| 2225 2716 |  | 
| 2226 2717 | 
             
            }(window.jQuery));
         | 
| 2227 2718 |  | 
| @@ -2257,13 +2748,24 @@ $(function(){ | |
| 2257 2748 |  | 
| 2258 2749 | 
             
                $.extend(Select.prototype, {
         | 
| 2259 2750 | 
             
                    renderList: function() {
         | 
| 2260 | 
            -
                         | 
| 2261 | 
            -
                            return;
         | 
| 2262 | 
            -
                        }
         | 
| 2751 | 
            +
                        this.$input.empty();
         | 
| 2263 2752 |  | 
| 2264 | 
            -
                         | 
| 2265 | 
            -
                             | 
| 2266 | 
            -
             | 
| 2753 | 
            +
                        var fillItems = function($el, data) {
         | 
| 2754 | 
            +
                            if($.isArray(data)) {
         | 
| 2755 | 
            +
                                for(var i=0; i<data.length; i++) {
         | 
| 2756 | 
            +
                                    if(data[i].children) {
         | 
| 2757 | 
            +
                                       $el.append(fillItems($('<optgroup>', {label: data[i].text}), data[i].children)); 
         | 
| 2758 | 
            +
                                    } else {
         | 
| 2759 | 
            +
                                       $el.append($('<option>', {value: data[i].value}).text(data[i].text)); 
         | 
| 2760 | 
            +
                                    }
         | 
| 2761 | 
            +
                                }
         | 
| 2762 | 
            +
                            }
         | 
| 2763 | 
            +
                            return $el;
         | 
| 2764 | 
            +
                        };        
         | 
| 2765 | 
            +
             | 
| 2766 | 
            +
                        fillItems(this.$input, this.sourceData);
         | 
| 2767 | 
            +
                        
         | 
| 2768 | 
            +
                        this.setClass();
         | 
| 2267 2769 |  | 
| 2268 2770 | 
             
                        //enter submit
         | 
| 2269 2771 | 
             
                        this.$input.on('keydown.editable', function (e) {
         | 
| @@ -2274,11 +2776,14 @@ $(function(){ | |
| 2274 2776 | 
             
                    },
         | 
| 2275 2777 |  | 
| 2276 2778 | 
             
                    value2htmlFinal: function(value, element) {
         | 
| 2277 | 
            -
                        var text = '',  | 
| 2278 | 
            -
             | 
| 2279 | 
            -
                             | 
| 2779 | 
            +
                        var text = '', 
         | 
| 2780 | 
            +
                            items = $.fn.editableutils.itemsByValue(value, this.sourceData);
         | 
| 2781 | 
            +
                            
         | 
| 2782 | 
            +
                        if(items.length) {
         | 
| 2783 | 
            +
                            text = items[0].text;
         | 
| 2280 2784 | 
             
                        }
         | 
| 2281 | 
            -
                         | 
| 2785 | 
            +
                        
         | 
| 2786 | 
            +
                        $(element).text(text);
         | 
| 2282 2787 | 
             
                    },
         | 
| 2283 2788 |  | 
| 2284 2789 | 
             
                    autosubmit: function() {
         | 
| @@ -2333,6 +2838,9 @@ $(function(){ | |
| 2333 2838 | 
             
                $.extend(Checklist.prototype, {
         | 
| 2334 2839 | 
             
                    renderList: function() {
         | 
| 2335 2840 | 
             
                        var $label, $div;
         | 
| 2841 | 
            +
                        
         | 
| 2842 | 
            +
                        this.$tpl.empty();
         | 
| 2843 | 
            +
                        
         | 
| 2336 2844 | 
             
                        if(!$.isArray(this.sourceData)) {
         | 
| 2337 2845 | 
             
                            return;
         | 
| 2338 2846 | 
             
                        }
         | 
| @@ -2340,13 +2848,15 @@ $(function(){ | |
| 2340 2848 | 
             
                        for(var i=0; i<this.sourceData.length; i++) {
         | 
| 2341 2849 | 
             
                            $label = $('<label>').append($('<input>', {
         | 
| 2342 2850 | 
             
                                                       type: 'checkbox',
         | 
| 2343 | 
            -
                                                       value: this.sourceData[i].value | 
| 2344 | 
            -
                                                       name: this.options.name
         | 
| 2851 | 
            +
                                                       value: this.sourceData[i].value 
         | 
| 2345 2852 | 
             
                                                 }))
         | 
| 2346 2853 | 
             
                                                 .append($('<span>').text(' '+this.sourceData[i].text));
         | 
| 2347 2854 |  | 
| 2348 | 
            -
                            $('<div>').append($label).appendTo(this.$ | 
| 2855 | 
            +
                            $('<div>').append($label).appendTo(this.$tpl);
         | 
| 2349 2856 | 
             
                        }
         | 
| 2857 | 
            +
                        
         | 
| 2858 | 
            +
                        this.$input = this.$tpl.find('input[type="checkbox"]');
         | 
| 2859 | 
            +
                        this.setClass();
         | 
| 2350 2860 | 
             
                    },
         | 
| 2351 2861 |  | 
| 2352 2862 | 
             
                   value2str: function(value) {
         | 
| @@ -2367,17 +2877,16 @@ $(function(){ | |
| 2367 2877 |  | 
| 2368 2878 | 
             
                   //set checked on required checkboxes
         | 
| 2369 2879 | 
             
                   value2input: function(value) {
         | 
| 2370 | 
            -
                         | 
| 2371 | 
            -
                        $checks.removeAttr('checked');
         | 
| 2880 | 
            +
                        this.$input.prop('checked', false);
         | 
| 2372 2881 | 
             
                        if($.isArray(value) && value.length) {
         | 
| 2373 | 
            -
                            | 
| 2882 | 
            +
                           this.$input.each(function(i, el) {
         | 
| 2374 2883 | 
             
                               var $el = $(el);
         | 
| 2375 2884 | 
             
                               // cannot use $.inArray as it performs strict comparison
         | 
| 2376 2885 | 
             
                               $.each(value, function(j, val){
         | 
| 2377 2886 | 
             
                                   /*jslint eqeq: true*/
         | 
| 2378 2887 | 
             
                                   if($el.val() == val) {
         | 
| 2379 2888 | 
             
                                   /*jslint eqeq: false*/                           
         | 
| 2380 | 
            -
                                       $el. | 
| 2889 | 
            +
                                       $el.prop('checked', true);
         | 
| 2381 2890 | 
             
                                   }
         | 
| 2382 2891 | 
             
                               });
         | 
| 2383 2892 | 
             
                           }); 
         | 
| @@ -2386,7 +2895,7 @@ $(function(){ | |
| 2386 2895 |  | 
| 2387 2896 | 
             
                   input2value: function() { 
         | 
| 2388 2897 | 
             
                       var checked = [];
         | 
| 2389 | 
            -
                       this.$input. | 
| 2898 | 
            +
                       this.$input.filter(':checked').each(function(i, el) {
         | 
| 2390 2899 | 
             
                           checked.push($(el).val());
         | 
| 2391 2900 | 
             
                       });
         | 
| 2392 2901 | 
             
                       return checked;
         | 
| @@ -2395,11 +2904,8 @@ $(function(){ | |
| 2395 2904 | 
             
                   //collect text of checked boxes
         | 
| 2396 2905 | 
             
                    value2htmlFinal: function(value, element) {
         | 
| 2397 2906 | 
             
                       var html = [],
         | 
| 2398 | 
            -
                            | 
| 2399 | 
            -
                            | 
| 2400 | 
            -
                               return $.grep(value, function(v){ return v == o.value; }).length;
         | 
| 2401 | 
            -
                           });
         | 
| 2402 | 
            -
                           /*jslint eqeq: false*/
         | 
| 2907 | 
            +
                           checked = $.fn.editableutils.itemsByValue(value, this.sourceData);
         | 
| 2908 | 
            +
                           
         | 
| 2403 2909 | 
             
                       if(checked.length) {
         | 
| 2404 2910 | 
             
                           $.each(checked, function(i, v) { html.push($.fn.editableutils.escape(v.text)); });
         | 
| 2405 2911 | 
             
                           $(element).html(html.join('<br>'));
         | 
| @@ -2409,11 +2915,11 @@ $(function(){ | |
| 2409 2915 | 
             
                    },
         | 
| 2410 2916 |  | 
| 2411 2917 | 
             
                   activate: function() {
         | 
| 2412 | 
            -
                       this.$input. | 
| 2918 | 
            +
                       this.$input.first().focus();
         | 
| 2413 2919 | 
             
                   },
         | 
| 2414 2920 |  | 
| 2415 2921 | 
             
                   autosubmit: function() {
         | 
| 2416 | 
            -
                       this.$input. | 
| 2922 | 
            +
                       this.$input.on('keydown', function(e){
         | 
| 2417 2923 | 
             
                           if (e.which === 13) {
         | 
| 2418 2924 | 
             
                               $(this).closest('form').submit();
         | 
| 2419 2925 | 
             
                           }
         | 
| @@ -2426,21 +2932,21 @@ $(function(){ | |
| 2426 2932 | 
             
                    @property tpl 
         | 
| 2427 2933 | 
             
                    @default <div></div>
         | 
| 2428 2934 | 
             
                    **/         
         | 
| 2429 | 
            -
                    tpl:'<div></div>',
         | 
| 2935 | 
            +
                    tpl:'<div class="editable-checklist"></div>',
         | 
| 2430 2936 |  | 
| 2431 2937 | 
             
                    /**
         | 
| 2432 2938 | 
             
                    @property inputclass 
         | 
| 2433 2939 | 
             
                    @type string
         | 
| 2434 | 
            -
                    @default  | 
| 2940 | 
            +
                    @default null
         | 
| 2435 2941 | 
             
                    **/         
         | 
| 2436 | 
            -
                    inputclass:  | 
| 2942 | 
            +
                    inputclass: null,        
         | 
| 2437 2943 |  | 
| 2438 2944 | 
             
                    /**
         | 
| 2439 | 
            -
                    Separator of values when reading from  | 
| 2945 | 
            +
                    Separator of values when reading from `data-value` attribute
         | 
| 2440 2946 |  | 
| 2441 2947 | 
             
                    @property separator 
         | 
| 2442 2948 | 
             
                    @type string
         | 
| 2443 | 
            -
                    @default ', | 
| 2949 | 
            +
                    @default ','
         | 
| 2444 2950 | 
             
                    **/         
         | 
| 2445 2951 | 
             
                    separator: ','
         | 
| 2446 2952 | 
             
                });
         | 
| @@ -2571,18 +3077,9 @@ Number | |
| 2571 3077 | 
             
                $.extend(NumberInput.prototype, {
         | 
| 2572 3078 | 
             
                     render: function () {
         | 
| 2573 3079 | 
             
                        NumberInput.superclass.render.call(this);
         | 
| 2574 | 
            -
             | 
| 2575 | 
            -
                         | 
| 2576 | 
            -
             | 
| 2577 | 
            -
                        } 
         | 
| 2578 | 
            -
                        
         | 
| 2579 | 
            -
                        if (this.options.max !== null) {
         | 
| 2580 | 
            -
                            this.$input.attr('max', this.options.max);
         | 
| 2581 | 
            -
                        } 
         | 
| 2582 | 
            -
                        
         | 
| 2583 | 
            -
                        if (this.options.step !== null) {
         | 
| 2584 | 
            -
                            this.$input.attr('step', this.options.step);
         | 
| 2585 | 
            -
                        }                         
         | 
| 3080 | 
            +
                        this.setAttr('min');
         | 
| 3081 | 
            +
                        this.setAttr('max');
         | 
| 3082 | 
            +
                        this.setAttr('step');
         | 
| 2586 3083 | 
             
                    }
         | 
| 2587 3084 | 
             
                });     
         | 
| 2588 3085 | 
             
                NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
         | 
| @@ -2606,29 +3103,19 @@ Range (inherit from number) | |
| 2606 3103 | 
             
                $.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
         | 
| 2607 3104 | 
             
                $.extend(Range.prototype, {
         | 
| 2608 3105 | 
             
                    render: function () {
         | 
| 2609 | 
            -
                        this.$input =  | 
| 2610 | 
            -
                        var $slider = this.$input.filter('input');
         | 
| 2611 | 
            -
                        if(this.options.inputclass) {
         | 
| 2612 | 
            -
                            $slider.addClass(this.options.inputclass); 
         | 
| 2613 | 
            -
                        }
         | 
| 2614 | 
            -
                        if (this.options.min !== null) {
         | 
| 2615 | 
            -
                            $slider.attr('min', this.options.min);
         | 
| 2616 | 
            -
                        } 
         | 
| 2617 | 
            -
                        
         | 
| 2618 | 
            -
                        if (this.options.max !== null) {
         | 
| 2619 | 
            -
                            $slider.attr('max', this.options.max);
         | 
| 2620 | 
            -
                        } 
         | 
| 3106 | 
            +
                        this.$input = this.$tpl.filter('input');
         | 
| 2621 3107 |  | 
| 2622 | 
            -
                         | 
| 2623 | 
            -
             | 
| 2624 | 
            -
                         | 
| 3108 | 
            +
                        this.setClass();
         | 
| 3109 | 
            +
                        this.setAttr('min');
         | 
| 3110 | 
            +
                        this.setAttr('max');
         | 
| 3111 | 
            +
                        this.setAttr('step');           
         | 
| 2625 3112 |  | 
| 2626 | 
            -
                         | 
| 3113 | 
            +
                        this.$input.on('input', function(){
         | 
| 2627 3114 | 
             
                            $(this).siblings('output').text($(this).val()); 
         | 
| 2628 3115 | 
             
                        });  
         | 
| 2629 3116 | 
             
                    },
         | 
| 2630 3117 | 
             
                    activate: function() {
         | 
| 2631 | 
            -
                        this.$input. | 
| 3118 | 
            +
                        this.$input.focus();
         | 
| 2632 3119 | 
             
                    }         
         | 
| 2633 3120 | 
             
                });
         | 
| 2634 3121 | 
             
                Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
         | 
| @@ -2637,6 +3124,783 @@ Range (inherit from number) | |
| 2637 3124 | 
             
                });
         | 
| 2638 3125 | 
             
                $.fn.editabletypes.range = Range;
         | 
| 2639 3126 | 
             
            }(window.jQuery));
         | 
| 3127 | 
            +
            /**
         | 
| 3128 | 
            +
            Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.  
         | 
| 3129 | 
            +
            Please see [original docs](http://ivaynberg.github.com/select2) for detailed description and options.  
         | 
| 3130 | 
            +
            You should manually include select2 distributive:  
         | 
| 3131 | 
            +
             | 
| 3132 | 
            +
                <link href="select2/select2.css" rel="stylesheet" type="text/css"></link>  
         | 
| 3133 | 
            +
                <script src="select2/select2.js"></script>  
         | 
| 3134 | 
            +
                
         | 
| 3135 | 
            +
            @class select2
         | 
| 3136 | 
            +
            @extends abstractinput
         | 
| 3137 | 
            +
            @since 1.4.1
         | 
| 3138 | 
            +
            @final
         | 
| 3139 | 
            +
            @example
         | 
| 3140 | 
            +
            <a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-original-title="Select country"></a>
         | 
| 3141 | 
            +
            <script>
         | 
| 3142 | 
            +
            $(function(){
         | 
| 3143 | 
            +
                $('#country').editable({
         | 
| 3144 | 
            +
                    source: [
         | 
| 3145 | 
            +
                          {id: 'gb', text: 'Great Britain'},
         | 
| 3146 | 
            +
                          {id: 'us', text: 'United States'},
         | 
| 3147 | 
            +
                          {id: 'ru', text: 'Russia'}
         | 
| 3148 | 
            +
                       ],
         | 
| 3149 | 
            +
                    select2: {
         | 
| 3150 | 
            +
                       multiple: true
         | 
| 3151 | 
            +
                    }
         | 
| 3152 | 
            +
                });
         | 
| 3153 | 
            +
            });
         | 
| 3154 | 
            +
            </script>
         | 
| 3155 | 
            +
            **/
         | 
| 3156 | 
            +
            (function ($) {
         | 
| 3157 | 
            +
             | 
| 3158 | 
            +
                var Constructor = function (options) {
         | 
| 3159 | 
            +
                    this.init('select2', options, Constructor.defaults);
         | 
| 3160 | 
            +
                   
         | 
| 3161 | 
            +
                    options.select2 = options.select2 || {};
         | 
| 3162 | 
            +
                    
         | 
| 3163 | 
            +
                    var that = this, 
         | 
| 3164 | 
            +
                        mixin = {
         | 
| 3165 | 
            +
                           placeholder:  options.placeholder
         | 
| 3166 | 
            +
                        };
         | 
| 3167 | 
            +
                   
         | 
| 3168 | 
            +
                   //detect whether it is multi-valued
         | 
| 3169 | 
            +
                   this.isMultiple = options.select2.tags || options.select2.multiple;
         | 
| 3170 | 
            +
                   
         | 
| 3171 | 
            +
                   //if not `tags` mode, we need define init set data from source
         | 
| 3172 | 
            +
                   if(!options.select2.tags) {
         | 
| 3173 | 
            +
                        if(options.source) {
         | 
| 3174 | 
            +
                            mixin.data = options.source;
         | 
| 3175 | 
            +
                        } 
         | 
| 3176 | 
            +
             | 
| 3177 | 
            +
                        //this function can be defaulted in seletc2. See https://github.com/ivaynberg/select2/issues/710
         | 
| 3178 | 
            +
                        mixin.initSelection = function (element, callback) {
         | 
| 3179 | 
            +
                            var val = that.str2value(element.val()),
         | 
| 3180 | 
            +
                                data = $.fn.editableutils.itemsByValue(val, mixin.data, 'id');
         | 
| 3181 | 
            +
                            
         | 
| 3182 | 
            +
                            //for single-valued mode should not use array. Take first element instead.
         | 
| 3183 | 
            +
                            if($.isArray(data) && data.length && !that.isMultiple) {
         | 
| 3184 | 
            +
                               data = data[0]; 
         | 
| 3185 | 
            +
                            }
         | 
| 3186 | 
            +
                                                
         | 
| 3187 | 
            +
                            callback(data);
         | 
| 3188 | 
            +
                        }; 
         | 
| 3189 | 
            +
                    }
         | 
| 3190 | 
            +
                       
         | 
| 3191 | 
            +
                    //overriding objects in config (as by default jQuery extend() is not recursive)
         | 
| 3192 | 
            +
                    this.options.select2 = $.extend({}, Constructor.defaults.select2, mixin, options.select2);
         | 
| 3193 | 
            +
                };
         | 
| 3194 | 
            +
             | 
| 3195 | 
            +
                $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
         | 
| 3196 | 
            +
             | 
| 3197 | 
            +
                $.extend(Constructor.prototype, {
         | 
| 3198 | 
            +
                    render: function() {
         | 
| 3199 | 
            +
                        this.setClass();
         | 
| 3200 | 
            +
                        //apply select2
         | 
| 3201 | 
            +
                        this.$input.select2(this.options.select2);
         | 
| 3202 | 
            +
             | 
| 3203 | 
            +
                        //trigger resize of editableform to re-position container in multi-valued mode           
         | 
| 3204 | 
            +
                        if(this.isMultiple) {
         | 
| 3205 | 
            +
                           this.$input.on('change', function() {
         | 
| 3206 | 
            +
                               $(this).closest('form').parent().triggerHandler('resize');
         | 
| 3207 | 
            +
                           }); 
         | 
| 3208 | 
            +
                        }            
         | 
| 3209 | 
            +
                        
         | 
| 3210 | 
            +
                    },
         | 
| 3211 | 
            +
                   
         | 
| 3212 | 
            +
                   value2html: function(value, element) {
         | 
| 3213 | 
            +
                       var text = '', data;
         | 
| 3214 | 
            +
                       if(this.$input) { //when submitting form 
         | 
| 3215 | 
            +
                           data = this.$input.select2('data');
         | 
| 3216 | 
            +
                       } else { //on init (autotext)
         | 
| 3217 | 
            +
                           //here select2 instance not created yet and data may be even not loaded.
         | 
| 3218 | 
            +
                           //we can check data/tags property of select config and if exist lookup text
         | 
| 3219 | 
            +
                           if(this.options.select2.tags) {
         | 
| 3220 | 
            +
                               data = value;
         | 
| 3221 | 
            +
                           } else if(this.options.select2.data) {
         | 
| 3222 | 
            +
                               data = $.fn.editableutils.itemsByValue(value, this.options.select2.data, 'id');   
         | 
| 3223 | 
            +
                           }
         | 
| 3224 | 
            +
                       }
         | 
| 3225 | 
            +
                       
         | 
| 3226 | 
            +
                       if($.isArray(data)) {
         | 
| 3227 | 
            +
                           //collect selected data and show with separator
         | 
| 3228 | 
            +
                           text = [];
         | 
| 3229 | 
            +
                           $.each(data, function(k, v){
         | 
| 3230 | 
            +
                               text.push(v && typeof v === 'object' ? v.text : v); 
         | 
| 3231 | 
            +
                           });                   
         | 
| 3232 | 
            +
                       } else if(data) {
         | 
| 3233 | 
            +
                           text = data.text;  
         | 
| 3234 | 
            +
                       }
         | 
| 3235 | 
            +
             | 
| 3236 | 
            +
                       text = $.isArray(text) ? text.join(this.options.viewseparator) : text;
         | 
| 3237 | 
            +
             | 
| 3238 | 
            +
                       $(element).text(text);
         | 
| 3239 | 
            +
                   },       
         | 
| 3240 | 
            +
                    
         | 
| 3241 | 
            +
                   html2value: function(html) {
         | 
| 3242 | 
            +
                       return this.options.select2.tags ? this.str2value(html, this.options.viewseparator) : null;
         | 
| 3243 | 
            +
                   }, 
         | 
| 3244 | 
            +
                   
         | 
| 3245 | 
            +
                   value2input: function(value) {
         | 
| 3246 | 
            +
                       this.$input.val(value).trigger('change');
         | 
| 3247 | 
            +
                   },
         | 
| 3248 | 
            +
                   
         | 
| 3249 | 
            +
                   input2value: function() { 
         | 
| 3250 | 
            +
                       return this.$input.select2('val');
         | 
| 3251 | 
            +
                   },
         | 
| 3252 | 
            +
             | 
| 3253 | 
            +
                   str2value: function(str, separator) {
         | 
| 3254 | 
            +
                        if(typeof str !== 'string' || !this.isMultiple) {
         | 
| 3255 | 
            +
                            return str;
         | 
| 3256 | 
            +
                        }
         | 
| 3257 | 
            +
                        
         | 
| 3258 | 
            +
                        separator = separator || this.options.select2.separator || $.fn.select2.defaults.separator;
         | 
| 3259 | 
            +
                        
         | 
| 3260 | 
            +
                        var val, i, l;
         | 
| 3261 | 
            +
                            
         | 
| 3262 | 
            +
                        if (str === null || str.length < 1) {
         | 
| 3263 | 
            +
                            return null;
         | 
| 3264 | 
            +
                        }
         | 
| 3265 | 
            +
                        val = str.split(separator);
         | 
| 3266 | 
            +
                        for (i = 0, l = val.length; i < l; i = i + 1) {
         | 
| 3267 | 
            +
                            val[i] = $.trim(val[i]);
         | 
| 3268 | 
            +
                        }
         | 
| 3269 | 
            +
                        
         | 
| 3270 | 
            +
                        return val;
         | 
| 3271 | 
            +
                   }        
         | 
| 3272 | 
            +
                    
         | 
| 3273 | 
            +
                });      
         | 
| 3274 | 
            +
             | 
| 3275 | 
            +
                Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
         | 
| 3276 | 
            +
                    /**
         | 
| 3277 | 
            +
                    @property tpl 
         | 
| 3278 | 
            +
                    @default <input type="hidden">
         | 
| 3279 | 
            +
                    **/         
         | 
| 3280 | 
            +
                    tpl:'<input type="hidden">',
         | 
| 3281 | 
            +
                    /**
         | 
| 3282 | 
            +
                    Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
         | 
| 3283 | 
            +
                    
         | 
| 3284 | 
            +
                    @property select2 
         | 
| 3285 | 
            +
                    @type object
         | 
| 3286 | 
            +
                    @default null
         | 
| 3287 | 
            +
                    **/
         | 
| 3288 | 
            +
                    select2: null,
         | 
| 3289 | 
            +
                    /**
         | 
| 3290 | 
            +
                    Placeholder attribute of select
         | 
| 3291 | 
            +
             | 
| 3292 | 
            +
                    @property placeholder 
         | 
| 3293 | 
            +
                    @type string
         | 
| 3294 | 
            +
                    @default null
         | 
| 3295 | 
            +
                    **/             
         | 
| 3296 | 
            +
                    placeholder: null,
         | 
| 3297 | 
            +
                    /**
         | 
| 3298 | 
            +
                    Source data for select. It will be assigned to select2 `data` property and kept here just for convenience.
         | 
| 3299 | 
            +
                    Please note, that format is different from simple `select` input: use 'id' instead of 'value'.
         | 
| 3300 | 
            +
                    E.g. `[{id: 1, text: "text1"}, {id: 2, text: "text2"}, ...]`.  
         | 
| 3301 | 
            +
                    
         | 
| 3302 | 
            +
                    @property source 
         | 
| 3303 | 
            +
                    @type array
         | 
| 3304 | 
            +
                    @default null        
         | 
| 3305 | 
            +
                    **/
         | 
| 3306 | 
            +
                    source: null,
         | 
| 3307 | 
            +
                    /**
         | 
| 3308 | 
            +
                    Separator used to display tags. 
         | 
| 3309 | 
            +
                    
         | 
| 3310 | 
            +
                    @property viewseparator 
         | 
| 3311 | 
            +
                    @type string
         | 
| 3312 | 
            +
                    @default ', '        
         | 
| 3313 | 
            +
                    **/
         | 
| 3314 | 
            +
                    viewseparator: ', '        
         | 
| 3315 | 
            +
                });
         | 
| 3316 | 
            +
             | 
| 3317 | 
            +
                $.fn.editabletypes.select2 = Constructor;      
         | 
| 3318 | 
            +
                
         | 
| 3319 | 
            +
            }(window.jQuery));
         | 
| 3320 | 
            +
            /**
         | 
| 3321 | 
            +
            * Combodate - 1.0.1
         | 
| 3322 | 
            +
            * Dropdown date and time picker.
         | 
| 3323 | 
            +
            * Converts text input into dropdowns to pick day, month, year, hour, minute and second.
         | 
| 3324 | 
            +
            * Uses momentjs as datetime library http://momentjs.com.
         | 
| 3325 | 
            +
            * For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang 
         | 
| 3326 | 
            +
            *
         | 
| 3327 | 
            +
            * Author: Vitaliy Potapov
         | 
| 3328 | 
            +
            * Project page: http://github.com/vitalets/combodate
         | 
| 3329 | 
            +
            * Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
         | 
| 3330 | 
            +
            **/
         | 
| 3331 | 
            +
            (function ($) {
         | 
| 3332 | 
            +
             | 
| 3333 | 
            +
                var Combodate = function (element, options) {
         | 
| 3334 | 
            +
                    this.$element = $(element);
         | 
| 3335 | 
            +
                    if(!this.$element.is('input')) {
         | 
| 3336 | 
            +
                        $.error('Combodate should be applied to INPUT element');
         | 
| 3337 | 
            +
                        return;
         | 
| 3338 | 
            +
                    }
         | 
| 3339 | 
            +
                    this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
         | 
| 3340 | 
            +
                    this.init();  
         | 
| 3341 | 
            +
                 };
         | 
| 3342 | 
            +
             | 
| 3343 | 
            +
                Combodate.prototype = {
         | 
| 3344 | 
            +
                    constructor: Combodate, 
         | 
| 3345 | 
            +
                    init: function () {
         | 
| 3346 | 
            +
                        this.map = {
         | 
| 3347 | 
            +
                            //key   regexp    moment.method
         | 
| 3348 | 
            +
                            day:    ['D',    'date'], 
         | 
| 3349 | 
            +
                            month:  ['M',    'month'], 
         | 
| 3350 | 
            +
                            year:   ['Y',    'year'], 
         | 
| 3351 | 
            +
                            hour:   ['[Hh]', 'hours'],
         | 
| 3352 | 
            +
                            minute: ['m',    'minutes'], 
         | 
| 3353 | 
            +
                            second: ['s',    'seconds'],
         | 
| 3354 | 
            +
                            ampm:   ['[Aa]', ''] 
         | 
| 3355 | 
            +
                        };
         | 
| 3356 | 
            +
                        
         | 
| 3357 | 
            +
                        this.$widget = $('<span class="combodate"></span>').html(this.getTemplate());
         | 
| 3358 | 
            +
                                  
         | 
| 3359 | 
            +
                        this.initCombos();
         | 
| 3360 | 
            +
                        
         | 
| 3361 | 
            +
                        //update original input on change 
         | 
| 3362 | 
            +
                        this.$widget.on('change', 'select', $.proxy(function(){
         | 
| 3363 | 
            +
                            this.$element.val(this.getValue());
         | 
| 3364 | 
            +
                        }, this));
         | 
| 3365 | 
            +
                        
         | 
| 3366 | 
            +
                        this.$widget.find('select').css('width', 'auto');
         | 
| 3367 | 
            +
                                                   
         | 
| 3368 | 
            +
                        //hide original input and insert widget                                       
         | 
| 3369 | 
            +
                        this.$element.hide().after(this.$widget);
         | 
| 3370 | 
            +
                        
         | 
| 3371 | 
            +
                        //set initial value
         | 
| 3372 | 
            +
                        this.setValue(this.$element.val() || this.options.value);
         | 
| 3373 | 
            +
                    },
         | 
| 3374 | 
            +
                    
         | 
| 3375 | 
            +
                    /*
         | 
| 3376 | 
            +
                     Replace tokens in template with <select> elements 
         | 
| 3377 | 
            +
                    */         
         | 
| 3378 | 
            +
                    getTemplate: function() {
         | 
| 3379 | 
            +
                        var tpl = this.options.template;
         | 
| 3380 | 
            +
             | 
| 3381 | 
            +
                        //first pass
         | 
| 3382 | 
            +
                        $.each(this.map, function(k, v) {
         | 
| 3383 | 
            +
                            v = v[0]; 
         | 
| 3384 | 
            +
                            var r = new RegExp(v+'+'),
         | 
| 3385 | 
            +
                                token = v.length > 1 ? v.substring(1, 2) : v;
         | 
| 3386 | 
            +
                                
         | 
| 3387 | 
            +
                            tpl = tpl.replace(r, '{'+token+'}');
         | 
| 3388 | 
            +
                        });
         | 
| 3389 | 
            +
             | 
| 3390 | 
            +
                        //replace spaces with  
         | 
| 3391 | 
            +
                        tpl = tpl.replace(/ /g, ' ');
         | 
| 3392 | 
            +
             | 
| 3393 | 
            +
                        //second pass
         | 
| 3394 | 
            +
                        $.each(this.map, function(k, v) {
         | 
| 3395 | 
            +
                            v = v[0];
         | 
| 3396 | 
            +
                            var token = v.length > 1 ? v.substring(1, 2) : v;
         | 
| 3397 | 
            +
                                
         | 
| 3398 | 
            +
                            tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
         | 
| 3399 | 
            +
                        });   
         | 
| 3400 | 
            +
             | 
| 3401 | 
            +
                        return tpl;
         | 
| 3402 | 
            +
                    },
         | 
| 3403 | 
            +
                    
         | 
| 3404 | 
            +
                    /*
         | 
| 3405 | 
            +
                     Initialize combos that presents in template 
         | 
| 3406 | 
            +
                    */        
         | 
| 3407 | 
            +
                    initCombos: function() {
         | 
| 3408 | 
            +
                        var that = this;
         | 
| 3409 | 
            +
                        $.each(this.map, function(k, v) {
         | 
| 3410 | 
            +
                           var $c = that.$widget.find('.'+k), f, items;
         | 
| 3411 | 
            +
                           if($c.length) {
         | 
| 3412 | 
            +
                               that['$'+k] = $c; //set properties like this.$day, this.$month etc.
         | 
| 3413 | 
            +
                               f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); //define method name to fill items, e.g `fillDays`
         | 
| 3414 | 
            +
                               items = that[f](); 
         | 
| 3415 | 
            +
                               that['$'+k].html(that.renderItems(items));
         | 
| 3416 | 
            +
                           }
         | 
| 3417 | 
            +
                        }); 
         | 
| 3418 | 
            +
                    },
         | 
| 3419 | 
            +
                    
         | 
| 3420 | 
            +
                    /*
         | 
| 3421 | 
            +
                     Initialize items of combos. Handles `firstItem` option 
         | 
| 3422 | 
            +
                    */
         | 
| 3423 | 
            +
                    initItems: function(key) {
         | 
| 3424 | 
            +
                        var values = [];
         | 
| 3425 | 
            +
                        if(this.options.firstItem === 'name') {
         | 
| 3426 | 
            +
                            var header = typeof moment.relativeTime[key] === 'function' ? moment.relativeTime[key](1, true, key, false) : moment.relativeTime[key];
         | 
| 3427 | 
            +
                            //take last entry (see momentjs lang files structure) 
         | 
| 3428 | 
            +
                            header = header.split(' ').reverse()[0];                
         | 
| 3429 | 
            +
                            values.push(['', header]);
         | 
| 3430 | 
            +
                        } else if(this.options.firstItem === 'empty') {
         | 
| 3431 | 
            +
                            values.push(['', '']);
         | 
| 3432 | 
            +
                        }
         | 
| 3433 | 
            +
                        return values;
         | 
| 3434 | 
            +
                    },        
         | 
| 3435 | 
            +
                    
         | 
| 3436 | 
            +
                    /*
         | 
| 3437 | 
            +
                    render items to string of <option> tags
         | 
| 3438 | 
            +
                    */
         | 
| 3439 | 
            +
                    renderItems: function(items) {
         | 
| 3440 | 
            +
                        var str = [];
         | 
| 3441 | 
            +
                        for(var i=0; i<items.length; i++) {
         | 
| 3442 | 
            +
                            str.push('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');                
         | 
| 3443 | 
            +
                        }
         | 
| 3444 | 
            +
                        return str.join("\n");
         | 
| 3445 | 
            +
                    },        
         | 
| 3446 | 
            +
             | 
| 3447 | 
            +
                    /*
         | 
| 3448 | 
            +
                    fill day
         | 
| 3449 | 
            +
                    */
         | 
| 3450 | 
            +
                    fillDay: function() {
         | 
| 3451 | 
            +
                        var items = this.initItems('d'), name, i,
         | 
| 3452 | 
            +
                            twoDigit = this.options.template.indexOf('DD') !== -1;
         | 
| 3453 | 
            +
                            
         | 
| 3454 | 
            +
                        for(i=1; i<=31; i++) {
         | 
| 3455 | 
            +
                            name = twoDigit ? this.leadZero(i) : i;
         | 
| 3456 | 
            +
                            items.push([i, name]);
         | 
| 3457 | 
            +
                        }
         | 
| 3458 | 
            +
                        return items;        
         | 
| 3459 | 
            +
                    },
         | 
| 3460 | 
            +
                    
         | 
| 3461 | 
            +
                    /*
         | 
| 3462 | 
            +
                    fill month
         | 
| 3463 | 
            +
                    */
         | 
| 3464 | 
            +
                    fillMonth: function() {
         | 
| 3465 | 
            +
                        var items = this.initItems('M'), name, i, 
         | 
| 3466 | 
            +
                            longNames = this.options.template.indexOf('MMMM') !== -1,
         | 
| 3467 | 
            +
                            shortNames = this.options.template.indexOf('MMM') !== -1,
         | 
| 3468 | 
            +
                            twoDigit = this.options.template.indexOf('MM') !== -1;
         | 
| 3469 | 
            +
                            
         | 
| 3470 | 
            +
                        for(i=0; i<=11; i++) {
         | 
| 3471 | 
            +
                            if(longNames) {
         | 
| 3472 | 
            +
                                name = moment.months[i];
         | 
| 3473 | 
            +
                            } else if(shortNames) {
         | 
| 3474 | 
            +
                                name = moment.monthsShort[i];
         | 
| 3475 | 
            +
                            } else if(twoDigit) {
         | 
| 3476 | 
            +
                                name = this.leadZero(i+1);
         | 
| 3477 | 
            +
                            } else {
         | 
| 3478 | 
            +
                                name = i+1;
         | 
| 3479 | 
            +
                            }
         | 
| 3480 | 
            +
                            items.push([i, name]);
         | 
| 3481 | 
            +
                        } 
         | 
| 3482 | 
            +
                        return items;
         | 
| 3483 | 
            +
                    },  
         | 
| 3484 | 
            +
                    
         | 
| 3485 | 
            +
                    /*
         | 
| 3486 | 
            +
                    fill year
         | 
| 3487 | 
            +
                    */
         | 
| 3488 | 
            +
                    fillYear: function() {
         | 
| 3489 | 
            +
                        var items = this.initItems('y'), name, i, 
         | 
| 3490 | 
            +
                            longNames = this.options.template.indexOf('YYYY') !== -1;
         | 
| 3491 | 
            +
             | 
| 3492 | 
            +
                        for(i=this.options.maxYear; i>=this.options.minYear; i--) {
         | 
| 3493 | 
            +
                            name = longNames ? i : (i+'').substring(2);
         | 
| 3494 | 
            +
                            items.push([i, name]);
         | 
| 3495 | 
            +
                        }    
         | 
| 3496 | 
            +
                        return items;              
         | 
| 3497 | 
            +
                    },    
         | 
| 3498 | 
            +
                    
         | 
| 3499 | 
            +
                    /*
         | 
| 3500 | 
            +
                    fill hour
         | 
| 3501 | 
            +
                    */
         | 
| 3502 | 
            +
                    fillHour: function() {
         | 
| 3503 | 
            +
                        var items = this.initItems('h'), name, i,
         | 
| 3504 | 
            +
                            h12 = this.options.template.indexOf('h') !== -1,
         | 
| 3505 | 
            +
                            h24 = this.options.template.indexOf('H') !== -1,
         | 
| 3506 | 
            +
                            twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
         | 
| 3507 | 
            +
                            max = h12 ? 12 : 23;
         | 
| 3508 | 
            +
                            
         | 
| 3509 | 
            +
                        for(i=0; i<=max; i++) {
         | 
| 3510 | 
            +
                            name = twoDigit ? this.leadZero(i) : i;
         | 
| 3511 | 
            +
                            items.push([i, name]);
         | 
| 3512 | 
            +
                        } 
         | 
| 3513 | 
            +
                        return items;                 
         | 
| 3514 | 
            +
                    },    
         | 
| 3515 | 
            +
                    
         | 
| 3516 | 
            +
                    /*
         | 
| 3517 | 
            +
                    fill minute
         | 
| 3518 | 
            +
                    */
         | 
| 3519 | 
            +
                    fillMinute: function() {
         | 
| 3520 | 
            +
                        var items = this.initItems('m'), name, i,
         | 
| 3521 | 
            +
                            twoDigit = this.options.template.indexOf('mm') !== -1;
         | 
| 3522 | 
            +
             | 
| 3523 | 
            +
                        for(i=0; i<=59; i+= this.options.minuteStep) {
         | 
| 3524 | 
            +
                            name = twoDigit ? this.leadZero(i) : i;
         | 
| 3525 | 
            +
                            items.push([i, name]);
         | 
| 3526 | 
            +
                        }    
         | 
| 3527 | 
            +
                        return items;              
         | 
| 3528 | 
            +
                    },  
         | 
| 3529 | 
            +
                    
         | 
| 3530 | 
            +
                    /*
         | 
| 3531 | 
            +
                    fill second
         | 
| 3532 | 
            +
                    */
         | 
| 3533 | 
            +
                    fillSecond: function() {
         | 
| 3534 | 
            +
                        var items = this.initItems('s'), name, i,
         | 
| 3535 | 
            +
                            twoDigit = this.options.template.indexOf('ss') !== -1;
         | 
| 3536 | 
            +
             | 
| 3537 | 
            +
                        for(i=0; i<=59; i+= this.options.secondStep) {
         | 
| 3538 | 
            +
                            name = twoDigit ? this.leadZero(i) : i;
         | 
| 3539 | 
            +
                            items.push([i, name]);
         | 
| 3540 | 
            +
                        }    
         | 
| 3541 | 
            +
                        return items;              
         | 
| 3542 | 
            +
                    },  
         | 
| 3543 | 
            +
                    
         | 
| 3544 | 
            +
                    /*
         | 
| 3545 | 
            +
                    fill ampm
         | 
| 3546 | 
            +
                    */
         | 
| 3547 | 
            +
                    fillAmpm: function() {
         | 
| 3548 | 
            +
                        var ampmL = this.options.template.indexOf('a') !== -1,
         | 
| 3549 | 
            +
                            ampmU = this.options.template.indexOf('A') !== -1,            
         | 
| 3550 | 
            +
                            items = [
         | 
| 3551 | 
            +
                                ['am', ampmL ? 'am' : 'AM'],
         | 
| 3552 | 
            +
                                ['pm', ampmL ? 'pm' : 'PM']
         | 
| 3553 | 
            +
                            ];
         | 
| 3554 | 
            +
                        return items;                              
         | 
| 3555 | 
            +
                    },                                       
         | 
| 3556 | 
            +
                    
         | 
| 3557 | 
            +
                    /*
         | 
| 3558 | 
            +
                     Returns current date value. 
         | 
| 3559 | 
            +
                     If format not specified - `options.format` used.
         | 
| 3560 | 
            +
                     If format = `null` - Moment object returned.
         | 
| 3561 | 
            +
                    */
         | 
| 3562 | 
            +
                    getValue: function(format) {
         | 
| 3563 | 
            +
                        var dt, values = {}, 
         | 
| 3564 | 
            +
                            that = this,
         | 
| 3565 | 
            +
                            notSelected = false;
         | 
| 3566 | 
            +
                            
         | 
| 3567 | 
            +
                        //getting selected values    
         | 
| 3568 | 
            +
                        $.each(this.map, function(k, v) {
         | 
| 3569 | 
            +
                            if(k === 'ampm') {
         | 
| 3570 | 
            +
                                return;
         | 
| 3571 | 
            +
                            }
         | 
| 3572 | 
            +
                            var def = k === 'day' ? 1 : 0;
         | 
| 3573 | 
            +
                              
         | 
| 3574 | 
            +
                            values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def; 
         | 
| 3575 | 
            +
                            
         | 
| 3576 | 
            +
                            if(isNaN(values[k])) {
         | 
| 3577 | 
            +
                               notSelected = true;
         | 
| 3578 | 
            +
                               return false; 
         | 
| 3579 | 
            +
                            }
         | 
| 3580 | 
            +
                        });
         | 
| 3581 | 
            +
                        
         | 
| 3582 | 
            +
                        //if at least one visible combo not selected - return empty string
         | 
| 3583 | 
            +
                        if(notSelected) {
         | 
| 3584 | 
            +
                           return '';
         | 
| 3585 | 
            +
                        }
         | 
| 3586 | 
            +
                        
         | 
| 3587 | 
            +
                        //convert hours if 12h format
         | 
| 3588 | 
            +
                        if(this.$ampm) {
         | 
| 3589 | 
            +
                           values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
         | 
| 3590 | 
            +
                           if(values.hour === 24) {
         | 
| 3591 | 
            +
                               values.hour = 0;
         | 
| 3592 | 
            +
                           }  
         | 
| 3593 | 
            +
                        }    
         | 
| 3594 | 
            +
                        
         | 
| 3595 | 
            +
                        dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
         | 
| 3596 | 
            +
                        
         | 
| 3597 | 
            +
                        //highlight invalid date
         | 
| 3598 | 
            +
                        this.highlight(dt);
         | 
| 3599 | 
            +
                                          
         | 
| 3600 | 
            +
                        format = format === undefined ? this.options.format : format;
         | 
| 3601 | 
            +
                        if(format === null) {
         | 
| 3602 | 
            +
                           return dt.isValid() ? dt : null; 
         | 
| 3603 | 
            +
                        } else {
         | 
| 3604 | 
            +
                           return dt.isValid() ? dt.format(format) : ''; 
         | 
| 3605 | 
            +
                        }           
         | 
| 3606 | 
            +
                    },
         | 
| 3607 | 
            +
                    
         | 
| 3608 | 
            +
                    setValue: function(value) {
         | 
| 3609 | 
            +
                        if(!value) {
         | 
| 3610 | 
            +
                            return;
         | 
| 3611 | 
            +
                        }
         | 
| 3612 | 
            +
                        
         | 
| 3613 | 
            +
                        var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
         | 
| 3614 | 
            +
                            that = this,
         | 
| 3615 | 
            +
                            values = {};
         | 
| 3616 | 
            +
                        
         | 
| 3617 | 
            +
                        if(dt.isValid()) {
         | 
| 3618 | 
            +
                             //read values from date object
         | 
| 3619 | 
            +
                             $.each(this.map, function(k, v) {
         | 
| 3620 | 
            +
                                 if(k === 'ampm') {
         | 
| 3621 | 
            +
                                     return; 
         | 
| 3622 | 
            +
                                 }
         | 
| 3623 | 
            +
                                 values[k] = dt[v[1]]();
         | 
| 3624 | 
            +
                             });
         | 
| 3625 | 
            +
                           
         | 
| 3626 | 
            +
                           if(this.$ampm) {
         | 
| 3627 | 
            +
                               if(values.hour > 12) {
         | 
| 3628 | 
            +
                                   values.hour -= 12;
         | 
| 3629 | 
            +
                                   values.ampm = 'pm';
         | 
| 3630 | 
            +
                               } else {
         | 
| 3631 | 
            +
                                   values.ampm = 'am';                  
         | 
| 3632 | 
            +
                               } 
         | 
| 3633 | 
            +
                           }
         | 
| 3634 | 
            +
                           
         | 
| 3635 | 
            +
                           $.each(values, function(k, v) {
         | 
| 3636 | 
            +
                               if(that['$'+k]) {
         | 
| 3637 | 
            +
                                   that['$'+k].val(v);                       
         | 
| 3638 | 
            +
                               }
         | 
| 3639 | 
            +
                           });
         | 
| 3640 | 
            +
                           
         | 
| 3641 | 
            +
                           this.$element.val(dt.format(this.options.format));
         | 
| 3642 | 
            +
                        }
         | 
| 3643 | 
            +
                    },
         | 
| 3644 | 
            +
                    
         | 
| 3645 | 
            +
                    /*
         | 
| 3646 | 
            +
                     highlight combos if date is invalid
         | 
| 3647 | 
            +
                    */
         | 
| 3648 | 
            +
                    highlight: function(dt) {
         | 
| 3649 | 
            +
                        if(!dt.isValid()) {
         | 
| 3650 | 
            +
                            if(this.options.errorClass) {
         | 
| 3651 | 
            +
                                this.$widget.addClass(this.options.errorClass);
         | 
| 3652 | 
            +
                            } else {
         | 
| 3653 | 
            +
                                //store original border color
         | 
| 3654 | 
            +
                                if(!this.borderColor) {
         | 
| 3655 | 
            +
                                    this.borderColor = this.$widget.find('select').css('border-color'); 
         | 
| 3656 | 
            +
                                }
         | 
| 3657 | 
            +
                                this.$widget.find('select').css('border-color', 'red');
         | 
| 3658 | 
            +
                            } 
         | 
| 3659 | 
            +
                        } else {
         | 
| 3660 | 
            +
                            if(this.options.errorClass) {
         | 
| 3661 | 
            +
                                this.$widget.removeClass(this.options.errorClass);
         | 
| 3662 | 
            +
                            } else {
         | 
| 3663 | 
            +
                                this.$widget.find('select').css('border-color', this.borderColor);
         | 
| 3664 | 
            +
                            }  
         | 
| 3665 | 
            +
                        }
         | 
| 3666 | 
            +
                    },
         | 
| 3667 | 
            +
                    
         | 
| 3668 | 
            +
                    leadZero: function(v) {
         | 
| 3669 | 
            +
                        return v <= 9 ? '0' + v : v; 
         | 
| 3670 | 
            +
                    },
         | 
| 3671 | 
            +
                    
         | 
| 3672 | 
            +
                    destroy: function() {
         | 
| 3673 | 
            +
                        this.$widget.remove();
         | 
| 3674 | 
            +
                        this.$element.removeData('combodate').show();
         | 
| 3675 | 
            +
                    }
         | 
| 3676 | 
            +
                    
         | 
| 3677 | 
            +
                    //todo: clear method        
         | 
| 3678 | 
            +
                };
         | 
| 3679 | 
            +
             | 
| 3680 | 
            +
                $.fn.combodate = function ( option ) {
         | 
| 3681 | 
            +
                    var d, args = Array.apply(null, arguments);
         | 
| 3682 | 
            +
                    args.shift();
         | 
| 3683 | 
            +
             | 
| 3684 | 
            +
                    //getValue returns date as string / object (not jQuery object)
         | 
| 3685 | 
            +
                    if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) {
         | 
| 3686 | 
            +
                      return d.getValue.apply(d, args);
         | 
| 3687 | 
            +
                    }        
         | 
| 3688 | 
            +
                    
         | 
| 3689 | 
            +
                    return this.each(function () {
         | 
| 3690 | 
            +
                        var $this = $(this),
         | 
| 3691 | 
            +
                        data = $this.data('combodate'),
         | 
| 3692 | 
            +
                        options = typeof option == 'object' && option;
         | 
| 3693 | 
            +
                        if (!data) {
         | 
| 3694 | 
            +
                            $this.data('combodate', (data = new Combodate(this, options)));
         | 
| 3695 | 
            +
                        }
         | 
| 3696 | 
            +
                        if (typeof option == 'string' && typeof data[option] == 'function') {
         | 
| 3697 | 
            +
                            data[option].apply(data, args);
         | 
| 3698 | 
            +
                        }
         | 
| 3699 | 
            +
                    });
         | 
| 3700 | 
            +
                };  
         | 
| 3701 | 
            +
                
         | 
| 3702 | 
            +
                $.fn.combodate.defaults = {
         | 
| 3703 | 
            +
                     //in this format value stored in original input
         | 
| 3704 | 
            +
                    format: 'DD-MM-YYYY HH:mm',      
         | 
| 3705 | 
            +
                    //in this format items in dropdowns are displayed
         | 
| 3706 | 
            +
                    template: 'D / MMM / YYYY   H : mm',
         | 
| 3707 | 
            +
                    //initial value, can be `new Date()`    
         | 
| 3708 | 
            +
                    value: null,                       
         | 
| 3709 | 
            +
                    minYear: 1970,
         | 
| 3710 | 
            +
                    maxYear: 2015,
         | 
| 3711 | 
            +
                    minuteStep: 5,
         | 
| 3712 | 
            +
                    secondStep: 1,
         | 
| 3713 | 
            +
                    firstItem: 'empty', //'name', 'empty', 'none'
         | 
| 3714 | 
            +
                    errorClass: null
         | 
| 3715 | 
            +
                };
         | 
| 3716 | 
            +
             | 
| 3717 | 
            +
            }(window.jQuery));
         | 
| 3718 | 
            +
            /**
         | 
| 3719 | 
            +
            Combodate input - dropdown date and time picker.    
         | 
| 3720 | 
            +
            Based on [combodate](http://vitalets.github.com/combodate) plugin. To use it you should manually include [momentjs](http://momentjs.com).
         | 
| 3721 | 
            +
             | 
| 3722 | 
            +
                <script src="js/moment.min.js"></script>
         | 
| 3723 | 
            +
               
         | 
| 3724 | 
            +
            Allows to input:
         | 
| 3725 | 
            +
             | 
| 3726 | 
            +
            * only date
         | 
| 3727 | 
            +
            * only time 
         | 
| 3728 | 
            +
            * both date and time  
         | 
| 3729 | 
            +
             | 
| 3730 | 
            +
            Please note, that format is taken from momentjs and **not compatible** with bootstrap-datepicker / jquery UI datepicker.  
         | 
| 3731 | 
            +
            Internally value stored as `momentjs` object. 
         | 
| 3732 | 
            +
             | 
| 3733 | 
            +
            @class combodate
         | 
| 3734 | 
            +
            @extends abstractinput
         | 
| 3735 | 
            +
            @final
         | 
| 3736 | 
            +
            @since 1.4.0
         | 
| 3737 | 
            +
            @example
         | 
| 3738 | 
            +
            <a href="#" id="dob" data-type="combodate" data-pk="1" data-url="/post" data-value="1984-05-15" data-original-title="Select date"></a>
         | 
| 3739 | 
            +
            <script>
         | 
| 3740 | 
            +
            $(function(){
         | 
| 3741 | 
            +
                $('#dob').editable({
         | 
| 3742 | 
            +
                    format: 'YYYY-MM-DD',    
         | 
| 3743 | 
            +
                    viewformat: 'DD.MM.YYYY',    
         | 
| 3744 | 
            +
                    template: 'D / MMMM / YYYY',    
         | 
| 3745 | 
            +
                    combodate: {
         | 
| 3746 | 
            +
                            minYear: 2000,
         | 
| 3747 | 
            +
                            maxYear: 2015,
         | 
| 3748 | 
            +
                            minuteStep: 1
         | 
| 3749 | 
            +
                       }
         | 
| 3750 | 
            +
                    }
         | 
| 3751 | 
            +
                });
         | 
| 3752 | 
            +
            });
         | 
| 3753 | 
            +
            </script>
         | 
| 3754 | 
            +
            **/
         | 
| 3755 | 
            +
             | 
| 3756 | 
            +
            /*global moment*/
         | 
| 3757 | 
            +
             | 
| 3758 | 
            +
            (function ($) {
         | 
| 3759 | 
            +
             | 
| 3760 | 
            +
                var Constructor = function (options) {
         | 
| 3761 | 
            +
                    this.init('combodate', options, Constructor.defaults);
         | 
| 3762 | 
            +
                    
         | 
| 3763 | 
            +
                    //by default viewformat equals to format
         | 
| 3764 | 
            +
                    if(!this.options.viewformat) {
         | 
| 3765 | 
            +
                        this.options.viewformat = this.options.format;
         | 
| 3766 | 
            +
                    }        
         | 
| 3767 | 
            +
                    
         | 
| 3768 | 
            +
                    //overriding combodate config (as by default jQuery extend() is not recursive)
         | 
| 3769 | 
            +
                    this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
         | 
| 3770 | 
            +
                        format: this.options.format,
         | 
| 3771 | 
            +
                        template: this.options.template
         | 
| 3772 | 
            +
                    });
         | 
| 3773 | 
            +
                };
         | 
| 3774 | 
            +
             | 
| 3775 | 
            +
                $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);    
         | 
| 3776 | 
            +
                
         | 
| 3777 | 
            +
                $.extend(Constructor.prototype, {
         | 
| 3778 | 
            +
                    render: function () {
         | 
| 3779 | 
            +
                        this.$input.combodate(this.options.combodate);
         | 
| 3780 | 
            +
                        
         | 
| 3781 | 
            +
                        //"clear" link
         | 
| 3782 | 
            +
                        /*
         | 
| 3783 | 
            +
                        if(this.options.clear) {
         | 
| 3784 | 
            +
                            this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
         | 
| 3785 | 
            +
                                e.preventDefault();
         | 
| 3786 | 
            +
                                e.stopPropagation();
         | 
| 3787 | 
            +
                                this.clear();
         | 
| 3788 | 
            +
                            }, this));
         | 
| 3789 | 
            +
                            
         | 
| 3790 | 
            +
                            this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));  
         | 
| 3791 | 
            +
                        } 
         | 
| 3792 | 
            +
                        */               
         | 
| 3793 | 
            +
                    },
         | 
| 3794 | 
            +
                    
         | 
| 3795 | 
            +
                    value2html: function(value, element) {
         | 
| 3796 | 
            +
                        var text = value ? value.format(this.options.viewformat) : '';
         | 
| 3797 | 
            +
                        $(element).text(text); 
         | 
| 3798 | 
            +
                    },
         | 
| 3799 | 
            +
             | 
| 3800 | 
            +
                    html2value: function(html) {
         | 
| 3801 | 
            +
                        return html ? moment(html, this.options.viewformat) : null;
         | 
| 3802 | 
            +
                    },   
         | 
| 3803 | 
            +
                    
         | 
| 3804 | 
            +
                    value2str: function(value) {
         | 
| 3805 | 
            +
                        return value ? value.format(this.options.format) : '';
         | 
| 3806 | 
            +
                   }, 
         | 
| 3807 | 
            +
                   
         | 
| 3808 | 
            +
                   str2value: function(str) {
         | 
| 3809 | 
            +
                       return str ? moment(str, this.options.format) : null;
         | 
| 3810 | 
            +
                   }, 
         | 
| 3811 | 
            +
                   
         | 
| 3812 | 
            +
                   value2submit: function(value) {
         | 
| 3813 | 
            +
                       return this.value2str(value);
         | 
| 3814 | 
            +
                   },                    
         | 
| 3815 | 
            +
             | 
| 3816 | 
            +
                   value2input: function(value) {
         | 
| 3817 | 
            +
                       this.$input.combodate('setValue', value);
         | 
| 3818 | 
            +
                   },
         | 
| 3819 | 
            +
                    
         | 
| 3820 | 
            +
                   input2value: function() { 
         | 
| 3821 | 
            +
                       return this.$input.combodate('getValue', null);
         | 
| 3822 | 
            +
                   },       
         | 
| 3823 | 
            +
                   
         | 
| 3824 | 
            +
                   activate: function() {
         | 
| 3825 | 
            +
                       this.$input.siblings('.combodate').find('select').eq(0).focus();
         | 
| 3826 | 
            +
                   },
         | 
| 3827 | 
            +
                   
         | 
| 3828 | 
            +
                   /*
         | 
| 3829 | 
            +
                   clear:  function() {
         | 
| 3830 | 
            +
                      this.$input.data('datepicker').date = null;
         | 
| 3831 | 
            +
                      this.$input.find('.active').removeClass('active');
         | 
| 3832 | 
            +
                   },
         | 
| 3833 | 
            +
                   */
         | 
| 3834 | 
            +
                   
         | 
| 3835 | 
            +
                   autosubmit: function() {
         | 
| 3836 | 
            +
                       
         | 
| 3837 | 
            +
                   }
         | 
| 3838 | 
            +
             | 
| 3839 | 
            +
                });
         | 
| 3840 | 
            +
                
         | 
| 3841 | 
            +
                Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
         | 
| 3842 | 
            +
                    /**
         | 
| 3843 | 
            +
                    @property tpl 
         | 
| 3844 | 
            +
                    @default <input type="text">
         | 
| 3845 | 
            +
                    **/         
         | 
| 3846 | 
            +
                    tpl:'<input type="text">',
         | 
| 3847 | 
            +
                    /**
         | 
| 3848 | 
            +
                    @property inputclass 
         | 
| 3849 | 
            +
                    @default null
         | 
| 3850 | 
            +
                    **/         
         | 
| 3851 | 
            +
                    inputclass: null,
         | 
| 3852 | 
            +
                    /**
         | 
| 3853 | 
            +
                    Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
         | 
| 3854 | 
            +
                    See list of tokens in [momentjs docs](http://momentjs.com/docs/#/parsing/string-format)  
         | 
| 3855 | 
            +
                    
         | 
| 3856 | 
            +
                    @property format 
         | 
| 3857 | 
            +
                    @type string
         | 
| 3858 | 
            +
                    @default YYYY-MM-DD
         | 
| 3859 | 
            +
                    **/         
         | 
| 3860 | 
            +
                    format:'YYYY-MM-DD',
         | 
| 3861 | 
            +
                    /**
         | 
| 3862 | 
            +
                    Format used for displaying date. Also applied when converting date from element's text on init.   
         | 
| 3863 | 
            +
                    If not specified equals to `format`.
         | 
| 3864 | 
            +
                    
         | 
| 3865 | 
            +
                    @property viewformat 
         | 
| 3866 | 
            +
                    @type string
         | 
| 3867 | 
            +
                    @default null
         | 
| 3868 | 
            +
                    **/          
         | 
| 3869 | 
            +
                    viewformat: null,        
         | 
| 3870 | 
            +
                    /**
         | 
| 3871 | 
            +
                    Template used for displaying dropdowns.
         | 
| 3872 | 
            +
                    
         | 
| 3873 | 
            +
                    @property template 
         | 
| 3874 | 
            +
                    @type string
         | 
| 3875 | 
            +
                    @default D / MMM / YYYY
         | 
| 3876 | 
            +
                    **/          
         | 
| 3877 | 
            +
                    template: 'D / MMM / YYYY',  
         | 
| 3878 | 
            +
                    /**
         | 
| 3879 | 
            +
                    Configuration of combodate.
         | 
| 3880 | 
            +
                    Full list of options: http://vitalets.github.com/combodate/#docs
         | 
| 3881 | 
            +
                    
         | 
| 3882 | 
            +
                    @property combodate 
         | 
| 3883 | 
            +
                    @type object
         | 
| 3884 | 
            +
                    @default null
         | 
| 3885 | 
            +
                    **/
         | 
| 3886 | 
            +
                    combodate: null
         | 
| 3887 | 
            +
                    
         | 
| 3888 | 
            +
                    /*
         | 
| 3889 | 
            +
                    (not implemented yet)
         | 
| 3890 | 
            +
                    Text shown as clear date button. 
         | 
| 3891 | 
            +
                    If <code>false</code> clear button will not be rendered.
         | 
| 3892 | 
            +
                    
         | 
| 3893 | 
            +
                    @property clear 
         | 
| 3894 | 
            +
                    @type boolean|string
         | 
| 3895 | 
            +
                    @default 'x clear'         
         | 
| 3896 | 
            +
                    */
         | 
| 3897 | 
            +
                    //clear: '× clear'
         | 
| 3898 | 
            +
                });   
         | 
| 3899 | 
            +
             | 
| 3900 | 
            +
                $.fn.editabletypes.combodate = Constructor;
         | 
| 3901 | 
            +
             | 
| 3902 | 
            +
            }(window.jQuery));
         | 
| 3903 | 
            +
             | 
| 2640 3904 | 
             
            /*
         | 
| 2641 3905 | 
             
            Editableform based on Twitter Bootstrap
         | 
| 2642 3906 | 
             
            */
         | 
| @@ -2666,7 +3930,7 @@ Editableform based on Twitter Bootstrap | |
| 2666 3930 | 
             
            (function ($) {
         | 
| 2667 3931 |  | 
| 2668 3932 | 
             
                //extend methods
         | 
| 2669 | 
            -
                $.extend($.fn.editableContainer. | 
| 3933 | 
            +
                $.extend($.fn.editableContainer.Popup.prototype, {
         | 
| 2670 3934 | 
             
                    containerName: 'popover',
         | 
| 2671 3935 | 
             
                    //for compatibility with bootstrap <= 2.2.1 (content inserted into <p> instead of directly .popover-content) 
         | 
| 2672 3936 | 
             
                    innerCss: $($.fn.popover.defaults.template).find('p').length ? '.popover-content p' : '.popover-content',
         | 
| @@ -2675,10 +3939,39 @@ Editableform based on Twitter Bootstrap | |
| 2675 3939 | 
             
                        $.extend(this.containerOptions, {
         | 
| 2676 3940 | 
             
                            trigger: 'manual',
         | 
| 2677 3941 | 
             
                            selector: false,
         | 
| 2678 | 
            -
                            content: ' '
         | 
| 3942 | 
            +
                            content: ' ',
         | 
| 3943 | 
            +
                            template: $.fn.popover.defaults.template
         | 
| 2679 3944 | 
             
                        });
         | 
| 3945 | 
            +
                        
         | 
| 3946 | 
            +
                        //as template property is used in inputs, hide it from popover
         | 
| 3947 | 
            +
                        var t;
         | 
| 3948 | 
            +
                        if(this.$element.data('template')) {
         | 
| 3949 | 
            +
                           t = this.$element.data('template');
         | 
| 3950 | 
            +
                           this.$element.removeData('template');  
         | 
| 3951 | 
            +
                        } 
         | 
| 3952 | 
            +
                        
         | 
| 2680 3953 | 
             
                        this.call(this.containerOptions);
         | 
| 2681 | 
            -
             | 
| 3954 | 
            +
                        
         | 
| 3955 | 
            +
                        if(t) {
         | 
| 3956 | 
            +
                           //restore data('template')
         | 
| 3957 | 
            +
                           this.$element.data('template', t); 
         | 
| 3958 | 
            +
                        }
         | 
| 3959 | 
            +
                    }, 
         | 
| 3960 | 
            +
                    
         | 
| 3961 | 
            +
                    /* show */
         | 
| 3962 | 
            +
                    innerShow: function () {
         | 
| 3963 | 
            +
                        this.call('show');                
         | 
| 3964 | 
            +
                    },  
         | 
| 3965 | 
            +
                    
         | 
| 3966 | 
            +
                    /* hide */
         | 
| 3967 | 
            +
                    innerHide: function () {
         | 
| 3968 | 
            +
                        this.call('hide');       
         | 
| 3969 | 
            +
                    }, 
         | 
| 3970 | 
            +
                    
         | 
| 3971 | 
            +
                    /* destroy */
         | 
| 3972 | 
            +
                    innerDestroy: function() {
         | 
| 3973 | 
            +
                        this.call('destroy');
         | 
| 3974 | 
            +
                    },                               
         | 
| 2682 3975 |  | 
| 2683 3976 | 
             
                    setContainerOption: function(key, value) {
         | 
| 2684 3977 | 
             
                        this.container().options[key] = value; 
         | 
| @@ -2742,18 +4035,13 @@ Editableform based on Twitter Bootstrap | |
| 2742 4035 | 
             
                    }            
         | 
| 2743 4036 | 
             
                });
         | 
| 2744 4037 |  | 
| 2745 | 
            -
                //defaults
         | 
| 2746 | 
            -
                /*
         | 
| 2747 | 
            -
                $.fn.editableContainer.defaults = $.extend({}, $.fn.popover.defaults, $.fn.editableContainer.defaults, {
         | 
| 2748 | 
            -
                    
         | 
| 2749 | 
            -
                });
         | 
| 2750 | 
            -
                */    
         | 
| 2751 | 
            -
             | 
| 2752 4038 | 
             
            }(window.jQuery));
         | 
| 2753 4039 | 
             
            /**
         | 
| 2754 4040 | 
             
            Bootstrap-datepicker.  
         | 
| 2755 | 
            -
            Description and examples:  | 
| 2756 | 
            -
            For  | 
| 4041 | 
            +
            Description and examples: https://github.com/eternicode/bootstrap-datepicker.  
         | 
| 4042 | 
            +
            For **i18n** you should include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
         | 
| 4043 | 
            +
            and set `language` option.  
         | 
| 4044 | 
            +
            Since 1.4.0 date has different appearance in **popup** and **inline** modes. 
         | 
| 2757 4045 |  | 
| 2758 4046 | 
             
            @class date
         | 
| 2759 4047 | 
             
            @extends abstractinput
         | 
| @@ -2777,45 +4065,52 @@ $(function(){ | |
| 2777 4065 |  | 
| 2778 4066 | 
             
                var Date = function (options) {
         | 
| 2779 4067 | 
             
                    this.init('date', options, Date.defaults);
         | 
| 2780 | 
            -
                    
         | 
| 2781 | 
            -
                    //set popular options directly from settings or data-* attributes
         | 
| 2782 | 
            -
                    var directOptions =  $.fn.editableutils.sliceObj(this.options, ['format']);
         | 
| 2783 | 
            -
             | 
| 2784 | 
            -
                    //overriding datepicker config (as by default jQuery extend() is not recursive)
         | 
| 2785 | 
            -
                    this.options.datepicker = $.extend({}, Date.defaults.datepicker, directOptions, options.datepicker);
         | 
| 2786 | 
            -
             | 
| 2787 | 
            -
                    //by default viewformat equals to format
         | 
| 2788 | 
            -
                    if(!this.options.viewformat) {
         | 
| 2789 | 
            -
                        this.options.viewformat = this.options.datepicker.format;
         | 
| 2790 | 
            -
                    }  
         | 
| 2791 | 
            -
                    
         | 
| 2792 | 
            -
                    //language
         | 
| 2793 | 
            -
                    this.options.datepicker.language = this.options.datepicker.language || 'en'; 
         | 
| 2794 | 
            -
                    
         | 
| 2795 | 
            -
                    //store DPglobal
         | 
| 2796 | 
            -
                    this.dpg = $.fn.datepicker.DPGlobal; 
         | 
| 2797 | 
            -
                    
         | 
| 2798 | 
            -
                    //store parsed formats
         | 
| 2799 | 
            -
                    this.parsedFormat = this.dpg.parseFormat(this.options.datepicker.format);
         | 
| 2800 | 
            -
                    this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);
         | 
| 4068 | 
            +
                    this.initPicker(options, Date.defaults);
         | 
| 2801 4069 | 
             
                };
         | 
| 2802 4070 |  | 
| 2803 4071 | 
             
                $.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);    
         | 
| 2804 4072 |  | 
| 2805 4073 | 
             
                $.extend(Date.prototype, {
         | 
| 4074 | 
            +
                    initPicker: function(options, defaults) {
         | 
| 4075 | 
            +
                        //'format' is set directly from settings or data-* attributes
         | 
| 4076 | 
            +
             | 
| 4077 | 
            +
                        //by default viewformat equals to format
         | 
| 4078 | 
            +
                        if(!this.options.viewformat) {
         | 
| 4079 | 
            +
                            this.options.viewformat = this.options.format;
         | 
| 4080 | 
            +
                        }
         | 
| 4081 | 
            +
                        
         | 
| 4082 | 
            +
                        //overriding datepicker config (as by default jQuery extend() is not recursive)
         | 
| 4083 | 
            +
                        //since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only
         | 
| 4084 | 
            +
                        this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, {
         | 
| 4085 | 
            +
                            format: this.options.viewformat
         | 
| 4086 | 
            +
                        });
         | 
| 4087 | 
            +
                        
         | 
| 4088 | 
            +
                        //language
         | 
| 4089 | 
            +
                        this.options.datepicker.language = this.options.datepicker.language || 'en'; 
         | 
| 4090 | 
            +
             | 
| 4091 | 
            +
                        //store DPglobal
         | 
| 4092 | 
            +
                        this.dpg = $.fn.datepicker.DPGlobal; 
         | 
| 4093 | 
            +
             | 
| 4094 | 
            +
                        //store parsed formats
         | 
| 4095 | 
            +
                        this.parsedFormat = this.dpg.parseFormat(this.options.format);
         | 
| 4096 | 
            +
                        this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);            
         | 
| 4097 | 
            +
                    },
         | 
| 4098 | 
            +
                    
         | 
| 2806 4099 | 
             
                    render: function () {
         | 
| 2807 | 
            -
                        Date.superclass.render.call(this);
         | 
| 2808 4100 | 
             
                        this.$input.datepicker(this.options.datepicker);
         | 
| 2809 | 
            -
             | 
| 4101 | 
            +
                        
         | 
| 4102 | 
            +
                        //"clear" link
         | 
| 2810 4103 | 
             
                        if(this.options.clear) {
         | 
| 2811 4104 | 
             
                            this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
         | 
| 2812 4105 | 
             
                                e.preventDefault();
         | 
| 2813 4106 | 
             
                                e.stopPropagation();
         | 
| 2814 4107 | 
             
                                this.clear();
         | 
| 2815 4108 | 
             
                            }, this));
         | 
| 2816 | 
            -
             | 
| 4109 | 
            +
                            
         | 
| 4110 | 
            +
                            this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));  
         | 
| 4111 | 
            +
                        }                
         | 
| 2817 4112 | 
             
                    },
         | 
| 2818 | 
            -
             | 
| 4113 | 
            +
                    
         | 
| 2819 4114 | 
             
                    value2html: function(value, element) {
         | 
| 2820 4115 | 
             
                        var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
         | 
| 2821 4116 | 
             
                        Date.superclass.value2html(text, element); 
         | 
| @@ -2869,12 +4164,12 @@ $(function(){ | |
| 2869 4164 | 
             
                    @property tpl 
         | 
| 2870 4165 | 
             
                    @default <div></div>
         | 
| 2871 4166 | 
             
                    **/         
         | 
| 2872 | 
            -
                    tpl:'<div></div>',
         | 
| 4167 | 
            +
                    tpl:'<div class="editable-date well"></div>',
         | 
| 2873 4168 | 
             
                    /**
         | 
| 2874 4169 | 
             
                    @property inputclass 
         | 
| 2875 | 
            -
                    @default  | 
| 4170 | 
            +
                    @default null
         | 
| 2876 4171 | 
             
                    **/         
         | 
| 2877 | 
            -
                    inputclass:  | 
| 4172 | 
            +
                    inputclass: null,
         | 
| 2878 4173 | 
             
                    /**
         | 
| 2879 4174 | 
             
                    Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
         | 
| 2880 4175 | 
             
                    Possible tokens are: <code>d, dd, m, mm, yy, yyyy</code>  
         | 
| @@ -2925,6 +4220,84 @@ $(function(){ | |
| 2925 4220 |  | 
| 2926 4221 | 
             
            }(window.jQuery));
         | 
| 2927 4222 |  | 
| 4223 | 
            +
            /**
         | 
| 4224 | 
            +
            Bootstrap datefield input - modification for inline mode.
         | 
| 4225 | 
            +
            Shows normal <input type="text"> and binds popup datepicker.  
         | 
| 4226 | 
            +
            Automatically shown in inline mode.
         | 
| 4227 | 
            +
             | 
| 4228 | 
            +
            @class datefield
         | 
| 4229 | 
            +
            @extends date
         | 
| 4230 | 
            +
             | 
| 4231 | 
            +
            @since 1.4.0
         | 
| 4232 | 
            +
            **/
         | 
| 4233 | 
            +
            (function ($) {
         | 
| 4234 | 
            +
             | 
| 4235 | 
            +
                var DateField = function (options) {
         | 
| 4236 | 
            +
                    this.init('datefield', options, DateField.defaults);
         | 
| 4237 | 
            +
                    this.initPicker(options, DateField.defaults);
         | 
| 4238 | 
            +
                };
         | 
| 4239 | 
            +
             | 
| 4240 | 
            +
                $.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);    
         | 
| 4241 | 
            +
                
         | 
| 4242 | 
            +
                $.extend(DateField.prototype, {
         | 
| 4243 | 
            +
                    render: function () {
         | 
| 4244 | 
            +
                        this.$input = this.$tpl.find('input');
         | 
| 4245 | 
            +
                        this.setClass();
         | 
| 4246 | 
            +
                        this.setAttr('placeholder');
         | 
| 4247 | 
            +
                        
         | 
| 4248 | 
            +
                        this.$tpl.datepicker(this.options.datepicker);
         | 
| 4249 | 
            +
                        
         | 
| 4250 | 
            +
                        //need to disable original event handlers
         | 
| 4251 | 
            +
                        this.$input.off('focus keydown');
         | 
| 4252 | 
            +
                        
         | 
| 4253 | 
            +
                        //update value of datepicker
         | 
| 4254 | 
            +
                        this.$input.keyup($.proxy(function(){
         | 
| 4255 | 
            +
                           this.$tpl.removeData('date');
         | 
| 4256 | 
            +
                           this.$tpl.datepicker('update');
         | 
| 4257 | 
            +
                        }, this));
         | 
| 4258 | 
            +
                        
         | 
| 4259 | 
            +
                    },   
         | 
| 4260 | 
            +
                    
         | 
| 4261 | 
            +
                   value2input: function(value) {
         | 
| 4262 | 
            +
                       this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
         | 
| 4263 | 
            +
                       this.$tpl.datepicker('update');
         | 
| 4264 | 
            +
                   },
         | 
| 4265 | 
            +
                    
         | 
| 4266 | 
            +
                   input2value: function() { 
         | 
| 4267 | 
            +
                       return this.html2value(this.$input.val());
         | 
| 4268 | 
            +
                   },              
         | 
| 4269 | 
            +
                    
         | 
| 4270 | 
            +
                   activate: function() {
         | 
| 4271 | 
            +
                       $.fn.editabletypes.text.prototype.activate.call(this);
         | 
| 4272 | 
            +
                   },
         | 
| 4273 | 
            +
                   
         | 
| 4274 | 
            +
                   autosubmit: function() {
         | 
| 4275 | 
            +
                     //reset autosubmit to empty  
         | 
| 4276 | 
            +
                   }
         | 
| 4277 | 
            +
                });
         | 
| 4278 | 
            +
                
         | 
| 4279 | 
            +
                DateField.defaults = $.extend({}, $.fn.editabletypes.date.defaults, {
         | 
| 4280 | 
            +
                    /**
         | 
| 4281 | 
            +
                    @property tpl 
         | 
| 4282 | 
            +
                    **/         
         | 
| 4283 | 
            +
                    tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
         | 
| 4284 | 
            +
                    /**
         | 
| 4285 | 
            +
                    @property inputclass 
         | 
| 4286 | 
            +
                    @default 'input-small'
         | 
| 4287 | 
            +
                    **/         
         | 
| 4288 | 
            +
                    inputclass: 'input-small',
         | 
| 4289 | 
            +
                    
         | 
| 4290 | 
            +
                    /* datepicker config */
         | 
| 4291 | 
            +
                    datepicker: {
         | 
| 4292 | 
            +
                        weekStart: 0,
         | 
| 4293 | 
            +
                        startView: 0,
         | 
| 4294 | 
            +
                        autoclose: true
         | 
| 4295 | 
            +
                    }
         | 
| 4296 | 
            +
                });
         | 
| 4297 | 
            +
                
         | 
| 4298 | 
            +
                $.fn.editabletypes.datefield = DateField;
         | 
| 4299 | 
            +
             | 
| 4300 | 
            +
            }(window.jQuery));
         | 
| 2928 4301 | 
             
            /* =========================================================
         | 
| 2929 4302 | 
             
             * bootstrap-datepicker.js
         | 
| 2930 4303 | 
             
             * http://www.eyecon.ro/bootstrap-datepicker
         | 
| @@ -2963,51 +4336,45 @@ $(function(){ | |
| 2963 4336 | 
             
            		this.element = $(element);
         | 
| 2964 4337 | 
             
            		this.language = options.language||this.element.data('date-language')||"en";
         | 
| 2965 4338 | 
             
            		this.language = this.language in dates ? this.language : "en";
         | 
| 4339 | 
            +
            		this.isRTL = dates[this.language].rtl||false;
         | 
| 2966 4340 | 
             
            		this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
         | 
| 2967 | 
            -
             | 
| 4341 | 
            +
            		this.isInline = false;
         | 
| 2968 4342 | 
             
            		this.isInput = this.element.is('input');
         | 
| 2969 4343 | 
             
            		this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
         | 
| 2970 4344 | 
             
            		this.hasInput = this.component && this.element.find('input').length;
         | 
| 2971 4345 | 
             
            		if(this.component && this.component.length === 0)
         | 
| 2972 4346 | 
             
            			this.component = false;
         | 
| 2973 4347 |  | 
| 2974 | 
            -
             | 
| 2975 | 
            -
                        this.element.on({
         | 
| 2976 | 
            -
                            focus: $.proxy(this.show, this),
         | 
| 2977 | 
            -
                            keyup: $.proxy(this.update, this),
         | 
| 2978 | 
            -
                            keydown: $.proxy(this.keydown, this)
         | 
| 2979 | 
            -
                        });
         | 
| 2980 | 
            -
                    } else if(this.component && this.hasInput) {  //component: input + button
         | 
| 2981 | 
            -
                            // For components that are not readonly, allow keyboard nav
         | 
| 2982 | 
            -
                            this.element.find('input').on({
         | 
| 2983 | 
            -
                                focus: $.proxy(this.show, this),
         | 
| 2984 | 
            -
                                keyup: $.proxy(this.update, this),
         | 
| 2985 | 
            -
                                keydown: $.proxy(this.keydown, this)
         | 
| 2986 | 
            -
                            });
         | 
| 2987 | 
            -
             | 
| 2988 | 
            -
                            this.component.on('click', $.proxy(this.show, this));
         | 
| 2989 | 
            -
                    } else if(this.element.is('div')) {  //inline datepicker
         | 
| 2990 | 
            -
                        this.isInline = true;
         | 
| 2991 | 
            -
                    } else {
         | 
| 2992 | 
            -
                        this.element.on('click', $.proxy(this.show, this));
         | 
| 2993 | 
            -
                    }
         | 
| 2994 | 
            -
             | 
| 2995 | 
            -
                    this.picker = $(DPGlobal.template)
         | 
| 2996 | 
            -
                                        .appendTo(this.isInline ? this.element : 'body')
         | 
| 2997 | 
            -
                                        .on({
         | 
| 2998 | 
            -
                                            click: $.proxy(this.click, this),
         | 
| 2999 | 
            -
                                            mousedown: $.proxy(this.mousedown, this)
         | 
| 3000 | 
            -
                                        });
         | 
| 3001 | 
            -
             | 
| 3002 | 
            -
                    if(this.isInline) {
         | 
| 3003 | 
            -
                        this.picker.addClass('datepicker-inline');
         | 
| 3004 | 
            -
                    } else {
         | 
| 3005 | 
            -
                        this.picker.addClass('dropdown-menu');
         | 
| 3006 | 
            -
                    }
         | 
| 4348 | 
            +
            		this._attachEvents();
         | 
| 3007 4349 |  | 
| 4350 | 
            +
            		this.forceParse = true;
         | 
| 4351 | 
            +
            		if ('forceParse' in options) {
         | 
| 4352 | 
            +
            			this.forceParse = options.forceParse;
         | 
| 4353 | 
            +
            		} else if ('dateForceParse' in this.element.data()) {
         | 
| 4354 | 
            +
            			this.forceParse = this.element.data('date-force-parse');
         | 
| 4355 | 
            +
            		}
         | 
| 4356 | 
            +
            		 
         | 
| 4357 | 
            +
             | 
| 4358 | 
            +
            		this.picker = $(DPGlobal.template)
         | 
| 4359 | 
            +
            							.appendTo(this.isInline ? this.element : 'body')
         | 
| 4360 | 
            +
            							.on({
         | 
| 4361 | 
            +
            								click: $.proxy(this.click, this),
         | 
| 4362 | 
            +
            								mousedown: $.proxy(this.mousedown, this)
         | 
| 4363 | 
            +
            							});
         | 
| 4364 | 
            +
             | 
| 4365 | 
            +
            		if(this.isInline) {
         | 
| 4366 | 
            +
            			this.picker.addClass('datepicker-inline');
         | 
| 4367 | 
            +
            		} else {
         | 
| 4368 | 
            +
            			this.picker.addClass('datepicker-dropdown dropdown-menu');
         | 
| 4369 | 
            +
            		}
         | 
| 4370 | 
            +
            		if (this.isRTL){
         | 
| 4371 | 
            +
            			this.picker.addClass('datepicker-rtl');
         | 
| 4372 | 
            +
            			this.picker.find('.prev i, .next i')
         | 
| 4373 | 
            +
            						.toggleClass('icon-arrow-left icon-arrow-right');
         | 
| 4374 | 
            +
            		}
         | 
| 3008 4375 | 
             
            		$(document).on('mousedown', function (e) {
         | 
| 3009 4376 | 
             
            			// Clicked outside the datepicker, hide it
         | 
| 3010 | 
            -
            			if ($(e.target).closest('.datepicker').length  | 
| 4377 | 
            +
            			if ($(e.target).closest('.datepicker').length === 0) {
         | 
| 3011 4378 | 
             
            				that.hide();
         | 
| 3012 4379 | 
             
            			}
         | 
| 3013 4380 | 
             
            		});
         | 
| @@ -3026,6 +4393,7 @@ $(function(){ | |
| 3026 4393 | 
             
            			this.keyboardNavigation = this.element.data('date-keyboard-navigation');
         | 
| 3027 4394 | 
             
            		}
         | 
| 3028 4395 |  | 
| 4396 | 
            +
            		this.viewMode = this.startViewMode = 0;
         | 
| 3029 4397 | 
             
            		switch(options.startView || this.element.data('date-start-view')){
         | 
| 3030 4398 | 
             
            			case 2:
         | 
| 3031 4399 | 
             
            			case 'decade':
         | 
| @@ -3035,11 +4403,6 @@ $(function(){ | |
| 3035 4403 | 
             
            			case 'year':
         | 
| 3036 4404 | 
             
            				this.viewMode = this.startViewMode = 1;
         | 
| 3037 4405 | 
             
            				break;
         | 
| 3038 | 
            -
            			case 0:
         | 
| 3039 | 
            -
            			case 'month':
         | 
| 3040 | 
            -
            			default:
         | 
| 3041 | 
            -
            				this.viewMode = this.startViewMode = 0;
         | 
| 3042 | 
            -
            				break;
         | 
| 3043 4406 | 
             
            		}
         | 
| 3044 4407 |  | 
| 3045 4408 | 
             
            		this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false);
         | 
| @@ -3049,21 +4412,73 @@ $(function(){ | |
| 3049 4412 | 
             
            		this.weekEnd = ((this.weekStart + 6) % 7);
         | 
| 3050 4413 | 
             
            		this.startDate = -Infinity;
         | 
| 3051 4414 | 
             
            		this.endDate = Infinity;
         | 
| 4415 | 
            +
            		this.daysOfWeekDisabled = [];
         | 
| 3052 4416 | 
             
            		this.setStartDate(options.startDate||this.element.data('date-startdate'));
         | 
| 3053 4417 | 
             
            		this.setEndDate(options.endDate||this.element.data('date-enddate'));
         | 
| 4418 | 
            +
            		this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled'));
         | 
| 3054 4419 | 
             
            		this.fillDow();
         | 
| 3055 4420 | 
             
            		this.fillMonths();
         | 
| 3056 4421 | 
             
            		this.update();
         | 
| 3057 4422 | 
             
            		this.showMode();
         | 
| 3058 4423 |  | 
| 3059 | 
            -
             | 
| 3060 | 
            -
             | 
| 3061 | 
            -
             | 
| 4424 | 
            +
            		if(this.isInline) {
         | 
| 4425 | 
            +
            			this.show();
         | 
| 4426 | 
            +
            		}
         | 
| 3062 4427 | 
             
            	};
         | 
| 3063 4428 |  | 
| 3064 4429 | 
             
            	Datepicker.prototype = {
         | 
| 3065 4430 | 
             
            		constructor: Datepicker,
         | 
| 3066 4431 |  | 
| 4432 | 
            +
            		_events: [],
         | 
| 4433 | 
            +
            		_attachEvents: function(){
         | 
| 4434 | 
            +
            			this._detachEvents();
         | 
| 4435 | 
            +
            			if (this.isInput) { // single input
         | 
| 4436 | 
            +
            				this._events = [
         | 
| 4437 | 
            +
            					[this.element, {
         | 
| 4438 | 
            +
            						focus: $.proxy(this.show, this),
         | 
| 4439 | 
            +
            						keyup: $.proxy(this.update, this),
         | 
| 4440 | 
            +
            						keydown: $.proxy(this.keydown, this)
         | 
| 4441 | 
            +
            					}]
         | 
| 4442 | 
            +
            				];
         | 
| 4443 | 
            +
            			}
         | 
| 4444 | 
            +
            			else if (this.component && this.hasInput){ // component: input + button
         | 
| 4445 | 
            +
            				this._events = [
         | 
| 4446 | 
            +
            					// For components that are not readonly, allow keyboard nav
         | 
| 4447 | 
            +
            					[this.element.find('input'), {
         | 
| 4448 | 
            +
            						focus: $.proxy(this.show, this),
         | 
| 4449 | 
            +
            						keyup: $.proxy(this.update, this),
         | 
| 4450 | 
            +
            						keydown: $.proxy(this.keydown, this)
         | 
| 4451 | 
            +
            					}],
         | 
| 4452 | 
            +
            					[this.component, {
         | 
| 4453 | 
            +
            						click: $.proxy(this.show, this)
         | 
| 4454 | 
            +
            					}]
         | 
| 4455 | 
            +
            				];
         | 
| 4456 | 
            +
            			}
         | 
| 4457 | 
            +
            						else if (this.element.is('div')) {  // inline datepicker
         | 
| 4458 | 
            +
            							this.isInline = true;
         | 
| 4459 | 
            +
            						}
         | 
| 4460 | 
            +
            			else {
         | 
| 4461 | 
            +
            				this._events = [
         | 
| 4462 | 
            +
            					[this.element, {
         | 
| 4463 | 
            +
            						click: $.proxy(this.show, this)
         | 
| 4464 | 
            +
            					}]
         | 
| 4465 | 
            +
            				];
         | 
| 4466 | 
            +
            			}
         | 
| 4467 | 
            +
            			for (var i=0, el, ev; i<this._events.length; i++){
         | 
| 4468 | 
            +
            				el = this._events[i][0];
         | 
| 4469 | 
            +
            				ev = this._events[i][1];
         | 
| 4470 | 
            +
            				el.on(ev);
         | 
| 4471 | 
            +
            			}
         | 
| 4472 | 
            +
            		},
         | 
| 4473 | 
            +
            		_detachEvents: function(){
         | 
| 4474 | 
            +
            			for (var i=0, el, ev; i<this._events.length; i++){
         | 
| 4475 | 
            +
            				el = this._events[i][0];
         | 
| 4476 | 
            +
            				ev = this._events[i][1];
         | 
| 4477 | 
            +
            				el.off(ev);
         | 
| 4478 | 
            +
            			}
         | 
| 4479 | 
            +
            			this._events = [];
         | 
| 4480 | 
            +
            		},
         | 
| 4481 | 
            +
             | 
| 3067 4482 | 
             
            		show: function(e) {
         | 
| 3068 4483 | 
             
            			this.picker.show();
         | 
| 3069 4484 | 
             
            			this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
         | 
| @@ -3081,7 +4496,7 @@ $(function(){ | |
| 3081 4496 | 
             
            		},
         | 
| 3082 4497 |  | 
| 3083 4498 | 
             
            		hide: function(e){
         | 
| 3084 | 
            -
             | 
| 4499 | 
            +
            			if(this.isInline) return;
         | 
| 3085 4500 | 
             
            			this.picker.hide();
         | 
| 3086 4501 | 
             
            			$(window).off('resize', this.place);
         | 
| 3087 4502 | 
             
            			this.viewMode = this.startViewMode;
         | 
| @@ -3089,7 +4504,14 @@ $(function(){ | |
| 3089 4504 | 
             
            			if (!this.isInput) {
         | 
| 3090 4505 | 
             
            				$(document).off('mousedown', this.hide);
         | 
| 3091 4506 | 
             
            			}
         | 
| 3092 | 
            -
             | 
| 4507 | 
            +
             | 
| 4508 | 
            +
            			if (
         | 
| 4509 | 
            +
            				this.forceParse &&
         | 
| 4510 | 
            +
            				(
         | 
| 4511 | 
            +
            					this.isInput && this.element.val() ||
         | 
| 4512 | 
            +
            					this.hasInput && this.element.find('input').val()
         | 
| 4513 | 
            +
            				)
         | 
| 4514 | 
            +
            			)
         | 
| 3093 4515 | 
             
            				this.setValue();
         | 
| 3094 4516 | 
             
            			this.element.trigger({
         | 
| 3095 4517 | 
             
            				type: 'hide',
         | 
| @@ -3097,9 +4519,15 @@ $(function(){ | |
| 3097 4519 | 
             
            			});
         | 
| 3098 4520 | 
             
            		},
         | 
| 3099 4521 |  | 
| 4522 | 
            +
            		remove: function() {
         | 
| 4523 | 
            +
            			this._detachEvents();
         | 
| 4524 | 
            +
            			this.picker.remove();
         | 
| 4525 | 
            +
            			delete this.element.data().datepicker;
         | 
| 4526 | 
            +
            		},
         | 
| 4527 | 
            +
             | 
| 3100 4528 | 
             
            		getDate: function() {
         | 
| 3101 4529 | 
             
            			var d = this.getUTCDate();
         | 
| 3102 | 
            -
            			return new Date(d.getTime() + (d.getTimezoneOffset()*60000))
         | 
| 4530 | 
            +
            			return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
         | 
| 3103 4531 | 
             
            		},
         | 
| 3104 4532 |  | 
| 3105 4533 | 
             
            		getUTCDate: function() {
         | 
| @@ -3119,18 +4547,19 @@ $(function(){ | |
| 3119 4547 | 
             
            			var formatted = this.getFormattedDate();
         | 
| 3120 4548 | 
             
            			if (!this.isInput) {
         | 
| 3121 4549 | 
             
            				if (this.component){
         | 
| 3122 | 
            -
            					this.element.find('input'). | 
| 4550 | 
            +
            					this.element.find('input').val(formatted);
         | 
| 3123 4551 | 
             
            				}
         | 
| 3124 4552 | 
             
            				this.element.data('date', formatted);
         | 
| 3125 4553 | 
             
            			} else {
         | 
| 3126 | 
            -
            				this.element. | 
| 4554 | 
            +
            				this.element.val(formatted);
         | 
| 3127 4555 | 
             
            			}
         | 
| 3128 4556 | 
             
            		},
         | 
| 3129 4557 |  | 
| 3130 | 
            -
             | 
| 3131 | 
            -
             | 
| 3132 | 
            -
             | 
| 3133 | 
            -
             | 
| 4558 | 
            +
            		getFormattedDate: function(format) {
         | 
| 4559 | 
            +
            			if (format === undefined)
         | 
| 4560 | 
            +
            				format = this.format;
         | 
| 4561 | 
            +
            			return DPGlobal.formatDate(this.date, format, this.language);
         | 
| 4562 | 
            +
            		},
         | 
| 3134 4563 |  | 
| 3135 4564 | 
             
            		setStartDate: function(startDate){
         | 
| 3136 4565 | 
             
            			this.startDate = startDate||-Infinity;
         | 
| @@ -3150,32 +4579,46 @@ $(function(){ | |
| 3150 4579 | 
             
            			this.updateNavArrows();
         | 
| 3151 4580 | 
             
            		},
         | 
| 3152 4581 |  | 
| 4582 | 
            +
            		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
         | 
| 4583 | 
            +
            			this.daysOfWeekDisabled = daysOfWeekDisabled||[];
         | 
| 4584 | 
            +
            			if (!$.isArray(this.daysOfWeekDisabled)) {
         | 
| 4585 | 
            +
            				this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
         | 
| 4586 | 
            +
            			}
         | 
| 4587 | 
            +
            			this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
         | 
| 4588 | 
            +
            				return parseInt(d, 10);
         | 
| 4589 | 
            +
            			});
         | 
| 4590 | 
            +
            			this.update();
         | 
| 4591 | 
            +
            			this.updateNavArrows();
         | 
| 4592 | 
            +
            		},
         | 
| 4593 | 
            +
             | 
| 3153 4594 | 
             
            		place: function(){
         | 
| 3154 | 
            -
             | 
| 4595 | 
            +
            						if(this.isInline) return;
         | 
| 3155 4596 | 
             
            			var zIndex = parseInt(this.element.parents().filter(function() {
         | 
| 3156 4597 | 
             
            							return $(this).css('z-index') != 'auto';
         | 
| 3157 4598 | 
             
            						}).first().css('z-index'))+10;
         | 
| 3158 4599 | 
             
            			var offset = this.component ? this.component.offset() : this.element.offset();
         | 
| 4600 | 
            +
            			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(true);
         | 
| 3159 4601 | 
             
            			this.picker.css({
         | 
| 3160 | 
            -
            				top: offset.top +  | 
| 4602 | 
            +
            				top: offset.top + height,
         | 
| 3161 4603 | 
             
            				left: offset.left,
         | 
| 3162 4604 | 
             
            				zIndex: zIndex
         | 
| 3163 4605 | 
             
            			});
         | 
| 3164 4606 | 
             
            		},
         | 
| 3165 4607 |  | 
| 3166 4608 | 
             
            		update: function(){
         | 
| 3167 | 
            -
             | 
| 3168 | 
            -
             | 
| 3169 | 
            -
             | 
| 3170 | 
            -
             | 
| 3171 | 
            -
             | 
| 3172 | 
            -
             | 
| 3173 | 
            -
             | 
| 4609 | 
            +
            			var date, fromArgs = false;
         | 
| 4610 | 
            +
            			if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
         | 
| 4611 | 
            +
            				date = arguments[0];
         | 
| 4612 | 
            +
            				fromArgs = true;
         | 
| 4613 | 
            +
            			} else {
         | 
| 4614 | 
            +
            				date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
         | 
| 4615 | 
            +
            			}
         | 
| 3174 4616 |  | 
| 3175 4617 | 
             
            			this.date = DPGlobal.parseDate(date, this.format, this.language);
         | 
| 3176 4618 |  | 
| 3177 | 
            -
             | 
| 4619 | 
            +
            			if(fromArgs) this.setValue();
         | 
| 3178 4620 |  | 
| 4621 | 
            +
            			var oldViewDate = this.viewDate;
         | 
| 3179 4622 | 
             
            			if (this.date < this.startDate) {
         | 
| 3180 4623 | 
             
            				this.viewDate = new Date(this.startDate);
         | 
| 3181 4624 | 
             
            			} else if (this.date > this.endDate) {
         | 
| @@ -3183,12 +4626,19 @@ $(function(){ | |
| 3183 4626 | 
             
            			} else {
         | 
| 3184 4627 | 
             
            				this.viewDate = new Date(this.date);
         | 
| 3185 4628 | 
             
            			}
         | 
| 4629 | 
            +
             | 
| 4630 | 
            +
            			if (oldViewDate && oldViewDate.getTime() != this.viewDate.getTime()){
         | 
| 4631 | 
            +
            				this.element.trigger({
         | 
| 4632 | 
            +
            					type: 'changeDate',
         | 
| 4633 | 
            +
            					date: this.viewDate
         | 
| 4634 | 
            +
            				});
         | 
| 4635 | 
            +
            			}
         | 
| 3186 4636 | 
             
            			this.fill();
         | 
| 3187 4637 | 
             
            		},
         | 
| 3188 4638 |  | 
| 3189 4639 | 
             
            		fillDow: function(){
         | 
| 3190 | 
            -
            			var dowCnt = this.weekStart | 
| 3191 | 
            -
            			 | 
| 4640 | 
            +
            			var dowCnt = this.weekStart,
         | 
| 4641 | 
            +
            			html = '<tr>';
         | 
| 3192 4642 | 
             
            			while (dowCnt < this.weekStart + 7) {
         | 
| 3193 4643 | 
             
            				html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
         | 
| 3194 4644 | 
             
            			}
         | 
| @@ -3197,8 +4647,8 @@ $(function(){ | |
| 3197 4647 | 
             
            		},
         | 
| 3198 4648 |  | 
| 3199 4649 | 
             
            		fillMonths: function(){
         | 
| 3200 | 
            -
            			var html = '' | 
| 3201 | 
            -
            			 | 
| 4650 | 
            +
            			var html = '',
         | 
| 4651 | 
            +
            			i = 0;
         | 
| 3202 4652 | 
             
            			while (i < 12) {
         | 
| 3203 4653 | 
             
            				html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
         | 
| 3204 4654 | 
             
            			}
         | 
| @@ -3251,7 +4701,8 @@ $(function(){ | |
| 3251 4701 | 
             
            				if (currentDate && prevMonth.valueOf() == currentDate) {
         | 
| 3252 4702 | 
             
            					clsName += ' active';
         | 
| 3253 4703 | 
             
            				}
         | 
| 3254 | 
            -
            				if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate | 
| 4704 | 
            +
            				if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
         | 
| 4705 | 
            +
            					$.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
         | 
| 3255 4706 | 
             
            					clsName += ' disabled';
         | 
| 3256 4707 | 
             
            				}
         | 
| 3257 4708 | 
             
            				html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
         | 
| @@ -3392,7 +4843,7 @@ $(function(){ | |
| 3392 4843 | 
             
            							var year = this.viewDate.getUTCFullYear(),
         | 
| 3393 4844 | 
             
            								month = this.viewDate.getUTCMonth();
         | 
| 3394 4845 | 
             
            							if (target.is('.old')) {
         | 
| 3395 | 
            -
            								if (month  | 
| 4846 | 
            +
            								if (month === 0) {
         | 
| 3396 4847 | 
             
            									month = 11;
         | 
| 3397 4848 | 
             
            									year -= 1;
         | 
| 3398 4849 | 
             
            								} else {
         | 
| @@ -3432,8 +4883,8 @@ $(function(){ | |
| 3432 4883 | 
             
            			}
         | 
| 3433 4884 | 
             
            			if (element) {
         | 
| 3434 4885 | 
             
            				element.change();
         | 
| 3435 | 
            -
            				if (this.autoclose) {
         | 
| 3436 | 
            -
             | 
| 4886 | 
            +
            				if (this.autoclose && (!which || which == 'date')) {
         | 
| 4887 | 
            +
            					this.hide();
         | 
| 3437 4888 | 
             
            				}
         | 
| 3438 4889 | 
             
            			}
         | 
| 3439 4890 | 
             
            		},
         | 
| @@ -3579,16 +5030,16 @@ $(function(){ | |
| 3579 5030 | 
             
            			if (dir) {
         | 
| 3580 5031 | 
             
            				this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
         | 
| 3581 5032 | 
             
            			}
         | 
| 3582 | 
            -
             | 
| 3583 | 
            -
             | 
| 3584 | 
            -
             | 
| 3585 | 
            -
             | 
| 3586 | 
            -
             | 
| 3587 | 
            -
             | 
| 3588 | 
            -
             | 
| 3589 | 
            -
             | 
| 3590 | 
            -
             | 
| 3591 | 
            -
             | 
| 5033 | 
            +
            			/*
         | 
| 5034 | 
            +
            				vitalets: fixing bug of very special conditions:
         | 
| 5035 | 
            +
            				jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
         | 
| 5036 | 
            +
            				Method show() does not set display css correctly and datepicker is not shown.
         | 
| 5037 | 
            +
            				Changed to .css('display', 'block') solve the problem.
         | 
| 5038 | 
            +
            				See https://github.com/vitalets/x-editable/issues/37
         | 
| 5039 | 
            +
             | 
| 5040 | 
            +
            				In jquery 1.7.2+ everything works fine.
         | 
| 5041 | 
            +
            			*/
         | 
| 5042 | 
            +
            			//this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
         | 
| 3592 5043 | 
             
            			this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
         | 
| 3593 5044 | 
             
            			this.updateNavArrows();
         | 
| 3594 5045 | 
             
            		}
         | 
| @@ -3622,7 +5073,7 @@ $(function(){ | |
| 3622 5073 | 
             
            			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
         | 
| 3623 5074 | 
             
            			today: "Today"
         | 
| 3624 5075 | 
             
            		}
         | 
| 3625 | 
            -
            	}
         | 
| 5076 | 
            +
            	};
         | 
| 3626 5077 |  | 
| 3627 5078 | 
             
            	var DPGlobal = {
         | 
| 3628 5079 | 
             
            		modes: [
         | 
| @@ -3642,28 +5093,28 @@ $(function(){ | |
| 3642 5093 | 
             
            				navStep: 10
         | 
| 3643 5094 | 
             
            		}],
         | 
| 3644 5095 | 
             
            		isLeapYear: function (year) {
         | 
| 3645 | 
            -
            			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
         | 
| 5096 | 
            +
            			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
         | 
| 3646 5097 | 
             
            		},
         | 
| 3647 5098 | 
             
            		getDaysInMonth: function (year, month) {
         | 
| 3648 | 
            -
            			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
         | 
| 5099 | 
            +
            			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
         | 
| 3649 5100 | 
             
            		},
         | 
| 3650 | 
            -
            		validParts: /dd?|mm?|MM?|yy(?:yy)?/g,
         | 
| 3651 | 
            -
            		nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\r]+/g,
         | 
| 5101 | 
            +
            		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
         | 
| 5102 | 
            +
            		nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
         | 
| 3652 5103 | 
             
            		parseFormat: function(format){
         | 
| 3653 5104 | 
             
            			// IE treats \0 as a string end in inputs (truncating the value),
         | 
| 3654 5105 | 
             
            			// so it's a bad format delimiter, anyway
         | 
| 3655 5106 | 
             
            			var separators = format.replace(this.validParts, '\0').split('\0'),
         | 
| 3656 5107 | 
             
            				parts = format.match(this.validParts);
         | 
| 3657 | 
            -
            			if (!separators || !separators.length || !parts || parts.length  | 
| 5108 | 
            +
            			if (!separators || !separators.length || !parts || parts.length === 0){
         | 
| 3658 5109 | 
             
            				throw new Error("Invalid date format.");
         | 
| 3659 5110 | 
             
            			}
         | 
| 3660 5111 | 
             
            			return {separators: separators, parts: parts};
         | 
| 3661 5112 | 
             
            		},
         | 
| 3662 5113 | 
             
            		parseDate: function(date, format, language) {
         | 
| 3663 5114 | 
             
            			if (date instanceof Date) return date;
         | 
| 3664 | 
            -
            			if (/^[ | 
| 3665 | 
            -
            				var part_re = /([ | 
| 3666 | 
            -
            					parts = date.match(/([ | 
| 5115 | 
            +
            			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
         | 
| 5116 | 
            +
            				var part_re = /([\-+]\d+)([dmwy])/,
         | 
| 5117 | 
            +
            					parts = date.match(/([\-+]\d+)([dmwy])/g),
         | 
| 3667 5118 | 
             
            					part, dir;
         | 
| 3668 5119 | 
             
            				date = new Date();
         | 
| 3669 5120 | 
             
            				for (var i=0; i<parts.length; i++) {
         | 
| @@ -3708,10 +5159,18 @@ $(function(){ | |
| 3708 5159 | 
             
            			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
         | 
| 3709 5160 | 
             
            			setters_map['dd'] = setters_map['d'];
         | 
| 3710 5161 | 
             
            			date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
         | 
| 3711 | 
            -
            			 | 
| 3712 | 
            -
             | 
| 5162 | 
            +
            			var fparts = format.parts.slice();
         | 
| 5163 | 
            +
            			// Remove noop parts
         | 
| 5164 | 
            +
            			if (parts.length != fparts.length) {
         | 
| 5165 | 
            +
            				fparts = $(fparts).filter(function(i,p){
         | 
| 5166 | 
            +
            					return $.inArray(p, setters_order) !== -1;
         | 
| 5167 | 
            +
            				}).toArray();
         | 
| 5168 | 
            +
            			}
         | 
| 5169 | 
            +
            			// Process remainder
         | 
| 5170 | 
            +
            			if (parts.length == fparts.length) {
         | 
| 5171 | 
            +
            				for (var i=0, cnt = fparts.length; i < cnt; i++) {
         | 
| 3713 5172 | 
             
            					val = parseInt(parts[i], 10);
         | 
| 3714 | 
            -
            					part =  | 
| 5173 | 
            +
            					part = fparts[i];
         | 
| 3715 5174 | 
             
            					if (isNaN(val)) {
         | 
| 3716 5175 | 
             
            						switch(part) {
         | 
| 3717 5176 | 
             
            							case 'MM':
         | 
| @@ -3736,8 +5195,8 @@ $(function(){ | |
| 3736 5195 | 
             
            				}
         | 
| 3737 5196 | 
             
            				for (var i=0, s; i<setters_order.length; i++){
         | 
| 3738 5197 | 
             
            					s = setters_order[i];
         | 
| 3739 | 
            -
            					if (s in parsed)
         | 
| 3740 | 
            -
            						setters_map[s](date, parsed[s])
         | 
| 5198 | 
            +
            					if (s in parsed && !isNaN(parsed[s]))
         | 
| 5199 | 
            +
            						setters_map[s](date, parsed[s]);
         | 
| 3741 5200 | 
             
            				}
         | 
| 3742 5201 | 
             
            			}
         | 
| 3743 5202 | 
             
            			return date;
         | 
| @@ -3745,6 +5204,8 @@ $(function(){ | |
| 3745 5204 | 
             
            		formatDate: function(date, format, language){
         | 
| 3746 5205 | 
             
            			var val = {
         | 
| 3747 5206 | 
             
            				d: date.getUTCDate(),
         | 
| 5207 | 
            +
            				D: dates[language].daysShort[date.getUTCDay()],
         | 
| 5208 | 
            +
            				DD: dates[language].days[date.getUTCDay()],
         | 
| 3748 5209 | 
             
            				m: date.getUTCMonth() + 1,
         | 
| 3749 5210 | 
             
            				M: dates[language].monthsShort[date.getUTCMonth()],
         | 
| 3750 5211 | 
             
            				MM: dates[language].months[date.getUTCMonth()],
         | 
| @@ -3757,7 +5218,7 @@ $(function(){ | |
| 3757 5218 | 
             
            				seps = $.extend([], format.separators);
         | 
| 3758 5219 | 
             
            			for (var i=0, cnt = format.parts.length; i < cnt; i++) {
         | 
| 3759 5220 | 
             
            				if (seps.length)
         | 
| 3760 | 
            -
            					date.push(seps.shift())
         | 
| 5221 | 
            +
            					date.push(seps.shift());
         | 
| 3761 5222 | 
             
            				date.push(val[format.parts[i]]);
         | 
| 3762 5223 | 
             
            			}
         | 
| 3763 5224 | 
             
            			return date.join('');
         | 
| @@ -3795,7 +5256,229 @@ $(function(){ | |
| 3795 5256 | 
             
            								'</table>'+
         | 
| 3796 5257 | 
             
            							'</div>'+
         | 
| 3797 5258 | 
             
            						'</div>';
         | 
| 3798 | 
            -
             | 
| 3799 | 
            -
             | 
| 3800 | 
            -
             | 
| 5259 | 
            +
             | 
| 5260 | 
            +
            	$.fn.datepicker.DPGlobal = DPGlobal;
         | 
| 5261 | 
            +
             | 
| 3801 5262 | 
             
            }( window.jQuery );
         | 
| 5263 | 
            +
             | 
| 5264 | 
            +
            /**
         | 
| 5265 | 
            +
            Typeahead input (bootstrap only). Based on Twitter Bootstrap [typeahead](http://twitter.github.com/bootstrap/javascript.html#typeahead).  
         | 
| 5266 | 
            +
            Depending on `source` format typeahead operates in two modes:
         | 
| 5267 | 
            +
             | 
| 5268 | 
            +
            * **strings**:  
         | 
| 5269 | 
            +
              When `source` defined as array of strings, e.g. `['text1', 'text2', 'text3' ...]`.  
         | 
| 5270 | 
            +
              User can submit one of these strings or any text entered in input (even if it is not matching source).
         | 
| 5271 | 
            +
              
         | 
| 5272 | 
            +
            * **objects**:  
         | 
| 5273 | 
            +
              When `source` defined as array of objects, e.g. `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`.  
         | 
| 5274 | 
            +
              User can submit only values that are in source (otherwise `null` is submitted). This is more like *dropdown* behavior.
         | 
| 5275 | 
            +
             | 
| 5276 | 
            +
            @class typeahead
         | 
| 5277 | 
            +
            @extends list
         | 
| 5278 | 
            +
            @since 1.4.1
         | 
| 5279 | 
            +
            @final
         | 
| 5280 | 
            +
            @example
         | 
| 5281 | 
            +
            <a href="#" id="country" data-type="typeahead" data-pk="1" data-url="/post" data-original-title="Input country"></a>
         | 
| 5282 | 
            +
            <script>
         | 
| 5283 | 
            +
            $(function(){
         | 
| 5284 | 
            +
                $('#country').editable({
         | 
| 5285 | 
            +
                    value: 'ru',    
         | 
| 5286 | 
            +
                    source: [
         | 
| 5287 | 
            +
                          {value: 'gb', text: 'Great Britain'},
         | 
| 5288 | 
            +
                          {value: 'us', text: 'United States'},
         | 
| 5289 | 
            +
                          {value: 'ru', text: 'Russia'}
         | 
| 5290 | 
            +
                       ]
         | 
| 5291 | 
            +
                    }
         | 
| 5292 | 
            +
                });
         | 
| 5293 | 
            +
            });
         | 
| 5294 | 
            +
            </script>
         | 
| 5295 | 
            +
            **/
         | 
| 5296 | 
            +
            (function ($) {
         | 
| 5297 | 
            +
             | 
| 5298 | 
            +
                var Constructor = function (options) {
         | 
| 5299 | 
            +
                    this.init('typeahead', options, Constructor.defaults);
         | 
| 5300 | 
            +
                    
         | 
| 5301 | 
            +
                    //overriding objects in config (as by default jQuery extend() is not recursive)
         | 
| 5302 | 
            +
                    this.options.typeahead = $.extend({}, Constructor.defaults.typeahead, {
         | 
| 5303 | 
            +
                        //set default methods for typeahead to work with objects
         | 
| 5304 | 
            +
                        matcher: this.matcher,  
         | 
| 5305 | 
            +
                        sorter: this.sorter,  
         | 
| 5306 | 
            +
                        highlighter: this.highlighter,  
         | 
| 5307 | 
            +
                        updater: this.updater  
         | 
| 5308 | 
            +
                    }, options.typeahead);
         | 
| 5309 | 
            +
                };
         | 
| 5310 | 
            +
             | 
| 5311 | 
            +
                $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.list);
         | 
| 5312 | 
            +
             | 
| 5313 | 
            +
                $.extend(Constructor.prototype, {
         | 
| 5314 | 
            +
                    renderList: function() {
         | 
| 5315 | 
            +
                        this.$input = this.$tpl.is('input') ? this.$tpl : this.$tpl.find('input[type="text"]');
         | 
| 5316 | 
            +
                        
         | 
| 5317 | 
            +
                        //set source of typeahead
         | 
| 5318 | 
            +
                        this.options.typeahead.source = this.sourceData;
         | 
| 5319 | 
            +
                        
         | 
| 5320 | 
            +
                        //apply typeahead
         | 
| 5321 | 
            +
                        this.$input.typeahead(this.options.typeahead);
         | 
| 5322 | 
            +
                        
         | 
| 5323 | 
            +
                        //attach own render method
         | 
| 5324 | 
            +
                        this.$input.data('typeahead').render = $.proxy(this.typeaheadRender, this.$input.data('typeahead'));
         | 
| 5325 | 
            +
             | 
| 5326 | 
            +
                        this.renderClear();
         | 
| 5327 | 
            +
                        this.setClass();
         | 
| 5328 | 
            +
                        this.setAttr('placeholder');
         | 
| 5329 | 
            +
                    },
         | 
| 5330 | 
            +
                   
         | 
| 5331 | 
            +
                    value2htmlFinal: function(value, element) {
         | 
| 5332 | 
            +
                        if(this.getIsObjects()) {
         | 
| 5333 | 
            +
                            var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
         | 
| 5334 | 
            +
                            $(element).text(items.length ? items[0].text : '');
         | 
| 5335 | 
            +
                        } else {
         | 
| 5336 | 
            +
                            $(element).text(value);
         | 
| 5337 | 
            +
                        }
         | 
| 5338 | 
            +
                    },
         | 
| 5339 | 
            +
                    
         | 
| 5340 | 
            +
                    html2value: function (html) {
         | 
| 5341 | 
            +
                        return html ? html : null;
         | 
| 5342 | 
            +
                    },
         | 
| 5343 | 
            +
                    
         | 
| 5344 | 
            +
                    value2input: function(value) {
         | 
| 5345 | 
            +
                        if(this.getIsObjects()) {
         | 
| 5346 | 
            +
                            var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
         | 
| 5347 | 
            +
                            this.$input.data('value', value).val(items.length ? items[0].text : '');                
         | 
| 5348 | 
            +
                        } else {
         | 
| 5349 | 
            +
                            this.$input.val(value);
         | 
| 5350 | 
            +
                        }
         | 
| 5351 | 
            +
                    },
         | 
| 5352 | 
            +
                    
         | 
| 5353 | 
            +
                    input2value: function() {
         | 
| 5354 | 
            +
                        if(this.getIsObjects()) {
         | 
| 5355 | 
            +
                            var value = this.$input.data('value'),
         | 
| 5356 | 
            +
                                items = $.fn.editableutils.itemsByValue(value, this.sourceData);
         | 
| 5357 | 
            +
                                
         | 
| 5358 | 
            +
                            if(items.length && items[0].text.toLowerCase() === this.$input.val().toLowerCase()) {
         | 
| 5359 | 
            +
                               return value;
         | 
| 5360 | 
            +
                            } else {
         | 
| 5361 | 
            +
                               return null; //entered string not found in source
         | 
| 5362 | 
            +
                            }                 
         | 
| 5363 | 
            +
                        } else {
         | 
| 5364 | 
            +
                            return this.$input.val();
         | 
| 5365 | 
            +
                        }
         | 
| 5366 | 
            +
                    },
         | 
| 5367 | 
            +
                    
         | 
| 5368 | 
            +
                    /*
         | 
| 5369 | 
            +
                     if in sourceData values <> texts, typeahead in "objects" mode: 
         | 
| 5370 | 
            +
                     user must pick some value from list, otherwise `null` returned.
         | 
| 5371 | 
            +
                     if all values == texts put typeahead in "strings" mode:
         | 
| 5372 | 
            +
                     anything what entered is submited.
         | 
| 5373 | 
            +
                    */        
         | 
| 5374 | 
            +
                    getIsObjects: function() {
         | 
| 5375 | 
            +
                        if(this.isObjects === undefined) {
         | 
| 5376 | 
            +
                            this.isObjects = false;
         | 
| 5377 | 
            +
                            for(var i=0; i<this.sourceData.length; i++) {
         | 
| 5378 | 
            +
                                if(this.sourceData[i].value !== this.sourceData[i].text) {
         | 
| 5379 | 
            +
                                    this.isObjects = true;
         | 
| 5380 | 
            +
                                    break;
         | 
| 5381 | 
            +
                                } 
         | 
| 5382 | 
            +
                            }
         | 
| 5383 | 
            +
                        } 
         | 
| 5384 | 
            +
                        return this.isObjects;
         | 
| 5385 | 
            +
                    },  
         | 
| 5386 | 
            +
                           
         | 
| 5387 | 
            +
                    /*
         | 
| 5388 | 
            +
                      Methods borrowed from text input
         | 
| 5389 | 
            +
                    */
         | 
| 5390 | 
            +
                    activate: $.fn.editabletypes.text.prototype.activate,
         | 
| 5391 | 
            +
                    renderClear: $.fn.editabletypes.text.prototype.renderClear,
         | 
| 5392 | 
            +
                    postrender: $.fn.editabletypes.text.prototype.postrender,
         | 
| 5393 | 
            +
                    toggleClear: $.fn.editabletypes.text.prototype.toggleClear,
         | 
| 5394 | 
            +
                    clear: function() {
         | 
| 5395 | 
            +
                        $.fn.editabletypes.text.prototype.clear.call(this);
         | 
| 5396 | 
            +
                        this.$input.data('value', ''); 
         | 
| 5397 | 
            +
                    },
         | 
| 5398 | 
            +
                    
         | 
| 5399 | 
            +
                    
         | 
| 5400 | 
            +
                    /*
         | 
| 5401 | 
            +
                      Typeahead option methods used as defaults
         | 
| 5402 | 
            +
                    */
         | 
| 5403 | 
            +
                    /*jshint eqeqeq:false, curly: false, laxcomma: true*/
         | 
| 5404 | 
            +
                    matcher: function (item) {
         | 
| 5405 | 
            +
                        return $.fn.typeahead.Constructor.prototype.matcher.call(this, item.text);
         | 
| 5406 | 
            +
                    },
         | 
| 5407 | 
            +
                    sorter: function (items) {
         | 
| 5408 | 
            +
                        var beginswith = []
         | 
| 5409 | 
            +
                        , caseSensitive = []
         | 
| 5410 | 
            +
                        , caseInsensitive = []
         | 
| 5411 | 
            +
                        , item
         | 
| 5412 | 
            +
                        , text;
         | 
| 5413 | 
            +
             | 
| 5414 | 
            +
                        while (item = items.shift()) {
         | 
| 5415 | 
            +
                            text = item.text;
         | 
| 5416 | 
            +
                            if (!text.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
         | 
| 5417 | 
            +
                            else if (~text.indexOf(this.query)) caseSensitive.push(item);
         | 
| 5418 | 
            +
                            else caseInsensitive.push(item);
         | 
| 5419 | 
            +
                        }
         | 
| 5420 | 
            +
             | 
| 5421 | 
            +
                        return beginswith.concat(caseSensitive, caseInsensitive);
         | 
| 5422 | 
            +
                    },
         | 
| 5423 | 
            +
                    highlighter: function (item) {
         | 
| 5424 | 
            +
                        return $.fn.typeahead.Constructor.prototype.highlighter.call(this, item.text);
         | 
| 5425 | 
            +
                    },
         | 
| 5426 | 
            +
                    updater: function (item) {
         | 
| 5427 | 
            +
                        item = this.$menu.find('.active').data('item');
         | 
| 5428 | 
            +
                        this.$element.data('value', item.value);
         | 
| 5429 | 
            +
                        return item.text;
         | 
| 5430 | 
            +
                    },  
         | 
| 5431 | 
            +
               
         | 
| 5432 | 
            +
                    
         | 
| 5433 | 
            +
                    /*
         | 
| 5434 | 
            +
                      Overwrite typeahead's render method to store objects.
         | 
| 5435 | 
            +
                      There are a lot of disscussion in bootstrap repo on this point and still no result.
         | 
| 5436 | 
            +
                      See https://github.com/twitter/bootstrap/issues/5967 
         | 
| 5437 | 
            +
                      
         | 
| 5438 | 
            +
                      This function just store item in via jQuery data() method instead of attr('data-value')
         | 
| 5439 | 
            +
                    */        
         | 
| 5440 | 
            +
                    typeaheadRender: function (items) {
         | 
| 5441 | 
            +
                        var that = this;
         | 
| 5442 | 
            +
             | 
| 5443 | 
            +
                        items = $(items).map(function (i, item) {
         | 
| 5444 | 
            +
            //                i = $(that.options.item).attr('data-value', item)
         | 
| 5445 | 
            +
                            i = $(that.options.item).data('item', item);
         | 
| 5446 | 
            +
                            i.find('a').html(that.highlighter(item));
         | 
| 5447 | 
            +
                            return i[0];
         | 
| 5448 | 
            +
                        });
         | 
| 5449 | 
            +
             | 
| 5450 | 
            +
                        items.first().addClass('active');
         | 
| 5451 | 
            +
                        this.$menu.html(items);
         | 
| 5452 | 
            +
                        return this;
         | 
| 5453 | 
            +
                    }
         | 
| 5454 | 
            +
                    /*jshint eqeqeq: true, curly: true, laxcomma: false*/  
         | 
| 5455 | 
            +
                    
         | 
| 5456 | 
            +
                });      
         | 
| 5457 | 
            +
             | 
| 5458 | 
            +
                Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
         | 
| 5459 | 
            +
                    /**
         | 
| 5460 | 
            +
                    @property tpl 
         | 
| 5461 | 
            +
                    @default <input type="text">
         | 
| 5462 | 
            +
                    **/         
         | 
| 5463 | 
            +
                    tpl:'<input type="text">',
         | 
| 5464 | 
            +
                    /**
         | 
| 5465 | 
            +
                    Configuration of typeahead. [Full list of options](http://twitter.github.com/bootstrap/javascript.html#typeahead).
         | 
| 5466 | 
            +
                    
         | 
| 5467 | 
            +
                    @property typeahead 
         | 
| 5468 | 
            +
                    @type object
         | 
| 5469 | 
            +
                    @default null
         | 
| 5470 | 
            +
                    **/
         | 
| 5471 | 
            +
                    typeahead: null,
         | 
| 5472 | 
            +
                    /**
         | 
| 5473 | 
            +
                    Whether to show `clear` button 
         | 
| 5474 | 
            +
                    
         | 
| 5475 | 
            +
                    @property clear 
         | 
| 5476 | 
            +
                    @type boolean
         | 
| 5477 | 
            +
                    @default true        
         | 
| 5478 | 
            +
                    **/
         | 
| 5479 | 
            +
                    clear: true
         | 
| 5480 | 
            +
                });
         | 
| 5481 | 
            +
             | 
| 5482 | 
            +
                $.fn.editabletypes.typeahead = Constructor;      
         | 
| 5483 | 
            +
                
         | 
| 5484 | 
            +
            }(window.jQuery));
         |