knockout.x-editable.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. (function(factory) {
  2. if (typeof define === "function" && define.amd) {
  3. // AMD anonymous module
  4. define(["knockout", "jquery"], factory);
  5. } else {
  6. // No module loader (plain <script> tag) - put directly in global namespace
  7. factory(window.ko, window.jQuery);
  8. }
  9. })(function(ko, $) {
  10. ko.bindingHandlers.editable = {
  11. init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  12. var $element = $(element),
  13. value = valueAccessor(),
  14. allBindings = allBindingsAccessor(),
  15. editableOptions = allBindings.editableOptions || {};
  16. editableOptions.value = ko.utils.unwrapObservable(value);
  17. if (!editableOptions.name) {
  18. $.each(bindingContext.$data, function (k, v) {
  19. if (v == value) {
  20. editableOptions.name = k;
  21. return false;
  22. }
  23. });
  24. }
  25. //wrap calls to knockout.validation
  26. if (!editableOptions.validate && value.isValid) {
  27. editableOptions.validate = function (testValue) {
  28. //have to set to new value, then call validate, then reset to original value
  29. //not pretty, but works
  30. var initalValue = value();
  31. value(testValue);
  32. var res = value.isValid() ? null : ko.utils.unwrapObservable(value.error);
  33. value(initalValue);
  34. return res;
  35. }
  36. }
  37. if ((editableOptions.type === 'select' || editableOptions.type === 'checklist'|| editableOptions.type === 'typeahead') && !editableOptions.source && editableOptions.options) {
  38. if (editableOptions.optionsCaption)
  39. editableOptions.prepend = editableOptions.optionsCaption;
  40. //taken directly from ko.bindingHandlers['options']
  41. function applyToObject(object, predicate, defaultValue) {
  42. var predicateType = typeof predicate;
  43. if (predicateType == "function") // Given a function; run it against the data value
  44. return predicate(object);
  45. else if (predicateType == "string") // Given a string; treat it as a property name on the data value
  46. return object[predicate];
  47. else // Given no optionsText arg; use the data value itself
  48. return defaultValue;
  49. }
  50. editableOptions.source = function() {
  51. return ko.utils.arrayMap(editableOptions.options(), function (item) {
  52. var optionValue = applyToObject(item, editableOptions.optionsValue, item);
  53. var optionText = applyToObject(item, editableOptions.optionsText, optionText);
  54. return {
  55. value: ko.utils.unwrapObservable(optionValue),
  56. text: ko.utils.unwrapObservable(optionText)
  57. };
  58. });
  59. }
  60. }
  61. if (editableOptions.visible && ko.isObservable(editableOptions.visible)) {
  62. editableOptions.toggle = 'manual';
  63. }
  64. //create editable
  65. var $editable = $element.editable(editableOptions);
  66. //update observable on save
  67. if (ko.isObservable(value)) {
  68. $editable.on('save.ko', function (e, params) {
  69. value(params.newValue);
  70. })
  71. };
  72. if (editableOptions.save) {
  73. $editable.on('save', editableOptions.save);
  74. }
  75. //setup observable to fire only when editable changes, not when options change
  76. //http://www.knockmeout.net/2012/06/knockoutjs-performance-gotcha-3-all-bindings.html
  77. ko.computed({
  78. read: function () {
  79. var val = ko.utils.unwrapObservable(valueAccessor());
  80. if (val === null) val = '';
  81. $editable.editable('setValue', val, true)
  82. },
  83. owner: this,
  84. disposeWhenNodeIsRemoved: element
  85. });
  86. if (editableOptions.visible && ko.isObservable(editableOptions.visible)) {
  87. ko.computed({
  88. read: function () {
  89. var val = ko.utils.unwrapObservable(editableOptions.visible());
  90. if (val)
  91. $editable.editable('show');
  92. },
  93. owner: this,
  94. disposeWhenNodeIsRemoved: element
  95. });
  96. $editable.on('hidden.ko', function (e, params) {
  97. editableOptions.visible(false);
  98. });
  99. }
  100. }
  101. };
  102. });