x-editable-rails 1.0.2 → 1.0.3

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.
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