x-editable-rails 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5efea27a1619957c2f3197189d9e17bb51a3b4ef
4
- data.tar.gz: 8af1c69ce928792a5ac658b3b2b8d75bdc27b878
3
+ metadata.gz: f2c2b641183f292b3bc8ba7131c00b3b416b5845
4
+ data.tar.gz: 15f114f8300f620b6ad0f668fac167b07bc5a416
5
5
  SHA512:
6
- metadata.gz: 3f3de3e4bf6ea289cc325353c619c2479591589ec968c8bb2db9084d5e53753187616c6a6c4fd6aee43528cc1566bcccee8d52290a7ef29b189fa14dfb9988c1
7
- data.tar.gz: f3bf084a7399627b4ab3d5a8315eab3c3d1ead2e233e2d402a4c820f8892cbffd3782622de4106ce77064e07bc9bb080fc62250a962887064f1ab2b5e834e6a5
6
+ metadata.gz: 9a91e096a1e4a653559e0e0bc191ebd800e0fc711e69b769bc798c501b0c76d46d75c8c066095d03d7ca3e3490758a7fe0f962846cee4bfde663f55c590db4b6
7
+ data.tar.gz: fe090ecd2f49610a240f00ec55973ad7947a7c2d7310dd2b0a9f13a475c122e4165c8b42484407b29e9e1a5063709ef32cbb0ab05ada73a9d8711d9ca80e8b42
data/README.md CHANGED
@@ -65,7 +65,7 @@ You can also update everything directly.
65
65
  ```
66
66
  or if nested
67
67
  ```haml
68
- %a{href: '#', class: 'editable', data: { type: 'text', model: 'post', nested: 'translations', name: 'name', nid: '#{post.translation.id}', url: post_path(post), 'original-title' => 'Your info here'}}= post.name
68
+ %a{href: '#', class: 'editable', data: { type: 'text', model: 'post', nested: 'translations', name: 'name', nid: "#{post.translation.id}", url: post_path(post), 'original-title' => 'Your info here'}}= post.name
69
69
  ```
70
70
 
71
71
  You need to specify:
@@ -1,7 +1,7 @@
1
1
  module X
2
2
  module Editable
3
3
  module Rails
4
- VERSION = "1.0.2"
4
+ VERSION = "1.0.3"
5
5
  end
6
6
  end
7
7
  end
@@ -1,4 +1,4 @@
1
- /*! X-editable - v1.4.5
1
+ /*! X-editable - v1.4.6
2
2
  * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
3
3
  * http://github.com/vitalets/x-editable
4
4
  * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
@@ -107,7 +107,8 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
107
107
  this.error(false);
108
108
  this.input.$input.removeAttr('disabled');
109
109
  this.$form.find('.editable-submit').removeAttr('disabled');
110
- this.input.value2input(this.value);
110
+ var value = (this.value === null || this.value === undefined || this.value === '') ? this.options.defaultValue : this.value;
111
+ this.input.value2input(value);
111
112
  //attach submit handler
112
113
  this.$form.submit($.proxy(this.submit, this));
113
114
  }
@@ -482,8 +483,17 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
482
483
  **/
483
484
  value: null,
484
485
  /**
485
- Strategy for sending data on server. Can be <code>auto|always|never</code>.
486
- When 'auto' data will be sent on server only if pk defined, otherwise new value will be stored in element.
486
+ Value that will be displayed in input if original field value is empty (`null|undefined|''`).
487
+
488
+ @property defaultValue
489
+ @type string|object
490
+ @default null
491
+ @since 1.4.6
492
+ **/
493
+ defaultValue: null,
494
+ /**
495
+ Strategy for sending data on server. Can be `auto|always|never`.
496
+ When 'auto' data will be sent on server **only if pk and url defined**, otherwise new value will be stored locally.
487
497
 
488
498
  @property send
489
499
  @type string
@@ -753,7 +763,10 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
753
763
  return [];
754
764
  }
755
765
 
756
- valueProp = valueProp || 'value';
766
+ if (typeof(valueProp) !== "function") {
767
+ var idKey = valueProp || 'value';
768
+ valueProp = function (e) { return e[idKey]; };
769
+ }
757
770
 
758
771
  var isValArray = $.isArray(value),
759
772
  result = [],
@@ -765,11 +778,12 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
765
778
  } else {
766
779
  /*jslint eqeq: true*/
767
780
  if(isValArray) {
768
- if($.grep(value, function(v){ return v == (o && typeof o === 'object' ? o[valueProp] : o); }).length) {
781
+ if($.grep(value, function(v){ return v == (o && typeof o === 'object' ? valueProp(o) : o); }).length) {
769
782
  result.push(o);
770
783
  }
771
784
  } else {
772
- if(value == (o && typeof o === 'object' ? o[valueProp] : o)) {
785
+ var itemValue = (o && (typeof o === 'object')) ? valueProp(o) : o;
786
+ if(value == itemValue) {
773
787
  result.push(o);
774
788
  }
775
789
  }
@@ -880,7 +894,8 @@ Applied as jQuery method.
880
894
 
881
895
  //methods
882
896
  Popup.prototype = {
883
- containerName: null, //tbd in child class
897
+ containerName: null, //method to call container on element
898
+ containerDataName: null, //object name in element's .data()
884
899
  innerCss: null, //tbd in child class
885
900
  containerClass: 'editable-container editable-popup', //css class applied to container element
886
901
  init: function(element, options) {
@@ -981,7 +996,16 @@ Applied as jQuery method.
981
996
 
982
997
  /* returns container object */
983
998
  container: function() {
984
- return this.$element.data(this.containerDataName || this.containerName);
999
+ var container;
1000
+ //first, try get it by `containerDataName`
1001
+ if(this.containerDataName) {
1002
+ if(container = this.$element.data(this.containerDataName)) {
1003
+ return container;
1004
+ }
1005
+ }
1006
+ //second, try `containerName`
1007
+ container = this.$element.data(this.containerName);
1008
+ return container;
985
1009
  },
986
1010
 
987
1011
  /* call native method of underlying container, e.g. this.$element.popover('method') */
@@ -1026,7 +1050,7 @@ Applied as jQuery method.
1026
1050
  /*
1027
1051
  TODO: added second param mainly to distinguish from bootstrap's shown event. It's a hotfix that will be solved in future versions via namespaced events.
1028
1052
  */
1029
- this.$element.triggerHandler('shown', this);
1053
+ this.$element.triggerHandler('shown', $(this.options.scope).data('editable'));
1030
1054
  }, this)
1031
1055
  })
1032
1056
  .editableform('render');
@@ -1480,6 +1504,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
1480
1504
  //add 'editable' class to every editable element
1481
1505
  this.$element.addClass('editable');
1482
1506
 
1507
+ //specifically for "textarea" add class .editable-pre-wrapped to keep linebreaks
1508
+ if(this.input.type === 'textarea') {
1509
+ this.$element.addClass('editable-pre-wrapped');
1510
+ }
1511
+
1483
1512
  //attach handler activating editable. In disabled mode it just prevent default action (useful for links)
1484
1513
  if(this.options.toggle !== 'manual') {
1485
1514
  this.$element.addClass('editable-click');
@@ -1809,16 +1838,19 @@ Makes editable any HTML element on the page. Applied as jQuery method.
1809
1838
  //highlight when saving
1810
1839
  if(this.options.highlight) {
1811
1840
  var $e = this.$element,
1812
- $bgColor = $e.css('background-color');
1841
+ bgColor = $e.css('background-color');
1813
1842
 
1814
1843
  $e.css('background-color', this.options.highlight);
1815
1844
  setTimeout(function(){
1816
- $e.css('background-color', $bgColor);
1845
+ if(bgColor === 'transparent') {
1846
+ bgColor = '';
1847
+ }
1848
+ $e.css('background-color', bgColor);
1817
1849
  $e.addClass('editable-bg-transition');
1818
1850
  setTimeout(function(){
1819
1851
  $e.removeClass('editable-bg-transition');
1820
1852
  }, 1700);
1821
- }, 0);
1853
+ }, 10);
1822
1854
  }
1823
1855
 
1824
1856
  //set new value
@@ -2032,6 +2064,14 @@ Makes editable any HTML element on the page. Applied as jQuery method.
2032
2064
  data = $this.data(datakey),
2033
2065
  options = typeof option === 'object' && option;
2034
2066
 
2067
+ //for delegated targets do not store `editable` object for element
2068
+ //it's allows several different selectors.
2069
+ //see: https://github.com/vitalets/x-editable/issues/312
2070
+ if(options && options.selector) {
2071
+ data = new Editable(this, options);
2072
+ return;
2073
+ }
2074
+
2035
2075
  if (!data) {
2036
2076
  $this.data(datakey, (data = new Editable(this, options)));
2037
2077
  }
@@ -2371,7 +2411,7 @@ To create your own input you can inherit from this class.
2371
2411
  /**
2372
2412
  Additional actions when destroying element
2373
2413
  **/
2374
- destroy: function() {
2414
+ destroy: function() {
2375
2415
  },
2376
2416
 
2377
2417
  // -------- helper functions --------
@@ -2919,8 +2959,10 @@ $(function(){
2919
2959
  }
2920
2960
  });
2921
2961
  },
2922
-
2923
- value2html: function(value, element) {
2962
+
2963
+ //using `white-space: pre-wrap` solves \n <--> BR conversion very elegant!
2964
+ /*
2965
+ value2html: function(value, element) {
2924
2966
  var html = '', lines;
2925
2967
  if(value) {
2926
2968
  lines = value.split("\n");
@@ -2931,7 +2973,7 @@ $(function(){
2931
2973
  }
2932
2974
  $(element).html(html);
2933
2975
  },
2934
-
2976
+
2935
2977
  html2value: function(html) {
2936
2978
  if(!html) {
2937
2979
  return '';
@@ -2950,7 +2992,7 @@ $(function(){
2950
2992
  }
2951
2993
  return lines.join("\n");
2952
2994
  },
2953
-
2995
+ */
2954
2996
  activate: function() {
2955
2997
  $.fn.editabletypes.text.prototype.activate.call(this);
2956
2998
  }
@@ -3024,12 +3066,19 @@ $(function(){
3024
3066
  this.$input.empty();
3025
3067
 
3026
3068
  var fillItems = function($el, data) {
3069
+ var attr;
3027
3070
  if($.isArray(data)) {
3028
3071
  for(var i=0; i<data.length; i++) {
3072
+ attr = {};
3029
3073
  if(data[i].children) {
3030
- $el.append(fillItems($('<optgroup>', {label: data[i].text}), data[i].children));
3074
+ attr.label = data[i].text;
3075
+ $el.append(fillItems($('<optgroup>', attr), data[i].children));
3031
3076
  } else {
3032
- $el.append($('<option>', {value: data[i].value}).text(data[i].text));
3077
+ attr.value = data[i].value;
3078
+ if(data[i].disabled) {
3079
+ attr.disabled = true;
3080
+ }
3081
+ $el.append($('<option>', attr).text(data[i].text));
3033
3082
  }
3034
3083
  }
3035
3084
  }
@@ -3241,6 +3290,7 @@ Following types are supported:
3241
3290
  * tel
3242
3291
  * number
3243
3292
  * range
3293
+ * time
3244
3294
 
3245
3295
  Learn more about html5 inputs:
3246
3296
  http://www.w3.org/wiki/HTML5_form_additions
@@ -3425,7 +3475,30 @@ Range (inherit from number)
3425
3475
  inputclass: 'input-medium'
3426
3476
  });
3427
3477
  $.fn.editabletypes.range = Range;
3428
- }(window.jQuery));
3478
+ }(window.jQuery));
3479
+
3480
+ /*
3481
+ Time
3482
+ */
3483
+ (function ($) {
3484
+ "use strict";
3485
+
3486
+ var Time = function (options) {
3487
+ this.init('time', options, Time.defaults);
3488
+ };
3489
+ //inherit from abstract, as inheritance from text gives selection error.
3490
+ $.fn.editableutils.inherit(Time, $.fn.editabletypes.abstractinput);
3491
+ $.extend(Time.prototype, {
3492
+ render: function() {
3493
+ this.setClass();
3494
+ }
3495
+ });
3496
+ Time.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
3497
+ tpl: '<input type="time">'
3498
+ });
3499
+ $.fn.editabletypes.time = Time;
3500
+ }(window.jQuery));
3501
+
3429
3502
  /**
3430
3503
  Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
3431
3504
  Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
@@ -3453,6 +3526,7 @@ You need initially put both `data-value` and element's text youself:
3453
3526
  <a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-title="Select country"></a>
3454
3527
  <script>
3455
3528
  $(function(){
3529
+ //local source
3456
3530
  $('#country').editable({
3457
3531
  source: [
3458
3532
  {id: 'gb', text: 'Great Britain'},
@@ -3463,6 +3537,42 @@ $(function(){
3463
3537
  multiple: true
3464
3538
  }
3465
3539
  });
3540
+ //remote source (simple)
3541
+ $('#country').editable({
3542
+ source: '/getCountries'
3543
+ });
3544
+ //remote source (advanced)
3545
+ $('#country').editable({
3546
+ select2: {
3547
+ placeholder: 'Select Country',
3548
+ allowClear: true,
3549
+ minimumInputLength: 3,
3550
+ id: function (item) {
3551
+ return item.CountryId;
3552
+ },
3553
+ ajax: {
3554
+ url: '/getCountries',
3555
+ dataType: 'json',
3556
+ data: function (term, page) {
3557
+ return { query: term };
3558
+ },
3559
+ results: function (data, page) {
3560
+ return { results: data };
3561
+ }
3562
+ },
3563
+ formatResult: function (item) {
3564
+ return item.CountryName;
3565
+ },
3566
+ formatSelection: function (item) {
3567
+ return item.CountryName;
3568
+ },
3569
+ initSelection: function (element, callback) {
3570
+ return $.get('/getCountryById', { query: element.val() }, function (data) {
3571
+ callback(data);
3572
+ });
3573
+ }
3574
+ }
3575
+ });
3466
3576
  });
3467
3577
  </script>
3468
3578
  **/
@@ -3511,7 +3621,21 @@ $(function(){
3511
3621
 
3512
3622
  //detect whether it is multi-valued
3513
3623
  this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
3514
- this.isRemote = ('ajax' in this.options.select2);
3624
+ this.isRemote = ('ajax' in this.options.select2);
3625
+
3626
+ //store function returning ID of item
3627
+ //should be here as used inautotext for local source
3628
+ this.idFunc = this.options.select2.id;
3629
+ if (typeof(this.idFunc) !== "function") {
3630
+ var idKey = this.idFunc || 'id';
3631
+ this.idFunc = function (e) { return e[idKey]; };
3632
+ }
3633
+
3634
+ //store function that renders text in select2
3635
+ this.formatSelection = this.options.select2.formatSelection;
3636
+ if (typeof(this.formatSelection) !== "function") {
3637
+ this.formatSelection = function (e) { return e.text; };
3638
+ }
3515
3639
  };
3516
3640
 
3517
3641
  $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
@@ -3536,16 +3660,18 @@ $(function(){
3536
3660
  this.$input.on('change', function() {
3537
3661
  $(this).closest('form').parent().triggerHandler('resize');
3538
3662
  });
3539
- }
3663
+ }
3540
3664
  },
3541
3665
 
3542
3666
  value2html: function(value, element) {
3543
- var text = '', data;
3667
+ var text = '', data,
3668
+ that = this;
3544
3669
 
3545
3670
  if(this.options.select2.tags) { //in tags mode just assign value
3546
3671
  data = value;
3672
+ //data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
3547
3673
  } else if(this.sourceData) {
3548
- data = $.fn.editableutils.itemsByValue(value, this.sourceData, 'id');
3674
+ data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
3549
3675
  } else {
3550
3676
  //can not get list of possible values (e.g. autotext for select2 with ajax source)
3551
3677
  }
@@ -3555,10 +3681,10 @@ $(function(){
3555
3681
  //collect selected data and show with separator
3556
3682
  text = [];
3557
3683
  $.each(data, function(k, v){
3558
- text.push(v && typeof v === 'object' ? v.text : v);
3684
+ text.push(v && typeof v === 'object' ? that.formatSelection(v) : v);
3559
3685
  });
3560
3686
  } else if(data) {
3561
- text = data.text;
3687
+ text = that.formatSelection(data);
3562
3688
  }
3563
3689
 
3564
3690
  text = $.isArray(text) ? text.join(this.options.viewseparator) : text;
@@ -3571,25 +3697,28 @@ $(function(){
3571
3697
  },
3572
3698
 
3573
3699
  value2input: function(value) {
3574
- //for remote source .val() is not working, need to look in sourceData
3575
- if(this.isRemote) {
3576
- //todo: check value for array
3577
- var item, items;
3578
- //if sourceData loaded, use it to get text for display
3579
- if(this.sourceData) {
3580
- items = $.fn.editableutils.itemsByValue(value, this.sourceData, 'id');
3581
- if(items.length) {
3582
- item = items[0];
3583
- }
3584
- }
3585
- //if item not found by sourceData, use element text (e.g. for the first show)
3586
- if(!item) {
3587
- item = {id: value, text: $(this.options.scope).text()};
3588
- }
3589
- //select2('data', ...) allows to set both id and text --> usefull for initial show when items are not loaded
3590
- this.$input.select2('data', item).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
3591
- } else {
3592
- this.$input.val(value).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
3700
+ //for local source use data directly from source (to allow autotext)
3701
+ /*
3702
+ if(!this.isRemote && !this.isMultiple) {
3703
+ var items = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
3704
+ if(items.length) {
3705
+ this.$input.select2('data', items[0]);
3706
+ return;
3707
+ }
3708
+ }
3709
+ */
3710
+
3711
+ //for remote source just set value, text is updated by initSelection
3712
+ this.$input.val(value).trigger('change', true); //second argument needed to separate initial change from user's click (for autosubmit)
3713
+
3714
+ //if remote source AND no user's initSelection provided --> try to use element's text
3715
+ if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
3716
+ var customId = this.options.select2.id,
3717
+ customText = this.options.select2.formatSelection;
3718
+ if(!customId && !customText) {
3719
+ var data = {id: value, text: $(this.options.scope).text()};
3720
+ this.$input.select2('data', data);
3721
+ }
3593
3722
  }
3594
3723
  },
3595
3724
 
@@ -3639,6 +3768,12 @@ $(function(){
3639
3768
  }
3640
3769
  }
3641
3770
  return source;
3771
+ },
3772
+
3773
+ destroy: function() {
3774
+ if(this.$input.data('select2')) {
3775
+ this.$input.select2('destroy');
3776
+ }
3642
3777
  }
3643
3778
 
3644
3779
  });
@@ -3694,7 +3829,7 @@ $(function(){
3694
3829
  * Dropdown date and time picker.
3695
3830
  * Converts text input into dropdowns to pick day, month, year, hour, minute and second.
3696
3831
  * Uses momentjs as datetime library http://momentjs.com.
3697
- * For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
3832
+ * For internalization include corresponding file from https://github.com/timrwood/moment/tree/master/lang
3698
3833
  *
3699
3834
  * Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
3700
3835
  * In combodate:
@@ -4423,7 +4558,11 @@ Editableform based on Twitter Bootstrap
4423
4558
  , actualWidth
4424
4559
  , actualHeight
4425
4560
  , placement
4426
- , tp;
4561
+ , tp
4562
+ , tpt
4563
+ , tpb
4564
+ , tpl
4565
+ , tpr;
4427
4566
 
4428
4567
  placement = typeof this.options.placement === 'function' ?
4429
4568
  this.options.placement.call(this, $tip[0], this.$element[0]) :
@@ -4443,18 +4582,78 @@ Editableform based on Twitter Bootstrap
4443
4582
  actualWidth = $tip[0].offsetWidth;
4444
4583
  actualHeight = $tip[0].offsetHeight;
4445
4584
 
4446
- switch (inside ? placement.split(' ')[1] : placement) {
4585
+ placement = inside ? placement.split(' ')[1] : placement;
4586
+
4587
+ tpb = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2};
4588
+ tpt = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2};
4589
+ tpl = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth};
4590
+ tpr = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width};
4591
+
4592
+ switch (placement) {
4447
4593
  case 'bottom':
4448
- tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2};
4594
+ if ((tpb.top + actualHeight) > ($(window).scrollTop() + $(window).height())) {
4595
+ if (tpt.top > $(window).scrollTop()) {
4596
+ placement = 'top';
4597
+ } else if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
4598
+ placement = 'right';
4599
+ } else if (tpl.left > $(window).scrollLeft()) {
4600
+ placement = 'left';
4601
+ } else {
4602
+ placement = 'right';
4603
+ }
4604
+ }
4449
4605
  break;
4450
4606
  case 'top':
4451
- tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2};
4607
+ if (tpt.top < $(window).scrollTop()) {
4608
+ if ((tpb.top + actualHeight) < ($(window).scrollTop() + $(window).height())) {
4609
+ placement = 'bottom';
4610
+ } else if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
4611
+ placement = 'right';
4612
+ } else if (tpl.left > $(window).scrollLeft()) {
4613
+ placement = 'left';
4614
+ } else {
4615
+ placement = 'right';
4616
+ }
4617
+ }
4452
4618
  break;
4453
4619
  case 'left':
4454
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth};
4620
+ if (tpl.left < $(window).scrollLeft()) {
4621
+ if ((tpr.left + actualWidth) < ($(window).scrollLeft() + $(window).width())) {
4622
+ placement = 'right';
4623
+ } else if (tpt.top > $(window).scrollTop()) {
4624
+ placement = 'top';
4625
+ } else if (tpt.top > $(window).scrollTop()) {
4626
+ placement = 'bottom';
4627
+ } else {
4628
+ placement = 'right';
4629
+ }
4630
+ }
4455
4631
  break;
4456
4632
  case 'right':
4457
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width};
4633
+ if ((tpr.left + actualWidth) > ($(window).scrollLeft() + $(window).width())) {
4634
+ if (tpl.left > $(window).scrollLeft()) {
4635
+ placement = 'left';
4636
+ } else if (tpt.top > $(window).scrollTop()) {
4637
+ placement = 'top';
4638
+ } else if (tpt.top > $(window).scrollTop()) {
4639
+ placement = 'bottom';
4640
+ }
4641
+ }
4642
+ break;
4643
+ }
4644
+
4645
+ switch (placement) {
4646
+ case 'bottom':
4647
+ tp = tpb;
4648
+ break;
4649
+ case 'top':
4650
+ tp = tpt;
4651
+ break;
4652
+ case 'left':
4653
+ tp = tpl;
4654
+ break;
4655
+ case 'right':
4656
+ tp = tpr;
4458
4657
  break;
4459
4658
  }
4460
4659
 
@@ -4468,7 +4667,8 @@ Editableform based on Twitter Bootstrap
4468
4667
  }
4469
4668
  });
4470
4669
 
4471
- }(window.jQuery));
4670
+ }(window.jQuery));
4671
+
4472
4672
  /* =========================================================
4473
4673
  * bootstrap-datepicker.js
4474
4674
  * http://www.eyecon.ro/bootstrap-datepicker
@@ -5774,6 +5974,9 @@ $(function(){
5774
5974
  this.options.viewformat = this.options.format;
5775
5975
  }
5776
5976
 
5977
+ //try parse datepicker config defined as json string in data-datepicker
5978
+ options.datepicker = $.fn.editableutils.tryParseJson(options.datepicker, true);
5979
+
5777
5980
  //overriding datepicker config (as by default jQuery extend() is not recursive)
5778
5981
  //since 1.4 datepicker internally uses viewformat instead of format. Format is for submit only
5779
5982
  this.options.datepicker = $.extend({}, defaults.datepicker, options.datepicker, {
@@ -6080,6 +6283,9 @@ $(function(){
6080
6283
  if(!this.options.viewformat) {
6081
6284
  this.options.viewformat = this.options.format;
6082
6285
  }
6286
+
6287
+ //try parse datetimepicker config defined as json string in data-datetimepicker
6288
+ options.datetimepicker = $.fn.editableutils.tryParseJson(options.datetimepicker, true);
6083
6289
 
6084
6290
  //overriding datetimepicker config (as by default jQuery extend() is not recursive)
6085
6291
  //since 1.4 datetimepicker internally uses viewformat instead of format. Format is for submit only