ko.editable.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Licensed to Cloudera, Inc. under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. Cloudera, Inc. licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // based on the original https://github.com/brianchance/knockout-x-editable
  17. (function (factory) {
  18. if (typeof define === "function" && define.amd) {
  19. // AMD anonymous module
  20. define(["knockout", "jquery"], factory);
  21. } else {
  22. // No module loader (plain <script> tag) - put directly in global namespace
  23. factory(window.ko, window.jQuery);
  24. }
  25. })(function (ko, $) {
  26. ko.bindingHandlers.editable = {
  27. init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
  28. var $element = $(element),
  29. value = valueAccessor(),
  30. allBindings = allBindingsAccessor(),
  31. editableOptions = allBindings.editableOptions || {};
  32. editableOptions.value = ko.utils.unwrapObservable(value);
  33. if (!editableOptions.name) {
  34. $.each(bindingContext.$data, function (k, v) {
  35. if (v == value) {
  36. editableOptions.name = k;
  37. return false;
  38. }
  39. });
  40. }
  41. //wrap calls to knockout.validation
  42. if (!editableOptions.validate && value.isValid) {
  43. editableOptions.validate = function (testValue) {
  44. //have to set to new value, then call validate, then reset to original value
  45. //not pretty, but works
  46. var initalValue = value();
  47. value(testValue);
  48. var res = value.isValid() ? null : ko.utils.unwrapObservable(value.error);
  49. value(initalValue);
  50. return res;
  51. }
  52. }
  53. if ((editableOptions.type === 'select' || editableOptions.type === 'checklist' || editableOptions.type === 'typeahead') && !editableOptions.source && editableOptions.options) {
  54. if (editableOptions.optionsCaption)
  55. editableOptions.prepend = editableOptions.optionsCaption;
  56. //taken directly from ko.bindingHandlers['options']
  57. function applyToObject(object, predicate, defaultValue) {
  58. var predicateType = typeof predicate;
  59. if (predicateType == "function") // Given a function; run it against the data value
  60. return predicate(object);
  61. else if (predicateType == "string") // Given a string; treat it as a property name on the data value
  62. return object[predicate];
  63. else // Given no optionsText arg; use the data value itself
  64. return defaultValue;
  65. }
  66. editableOptions.source = function () {
  67. return ko.utils.arrayMap(editableOptions.options(), function (item) {
  68. var optionValue = applyToObject(item, editableOptions.optionsValue, item);
  69. var optionText = applyToObject(item, editableOptions.optionsText, optionText);
  70. return {
  71. value: ko.utils.unwrapObservable(optionValue),
  72. text: ko.utils.unwrapObservable(optionText)
  73. };
  74. });
  75. }
  76. }
  77. if (editableOptions.visible && ko.isObservable(editableOptions.visible)) {
  78. editableOptions.toggle = 'manual';
  79. }
  80. //create editable
  81. var $editable = $element.editable(editableOptions);
  82. //update observable on save
  83. if (ko.isObservable(value)) {
  84. $editable.on('save.ko', function (e, params) {
  85. value(params.newValue);
  86. })
  87. }
  88. ;
  89. if (editableOptions.save) {
  90. $editable.on('save', editableOptions.save);
  91. }
  92. //setup observable to fire only when editable changes, not when options change
  93. //http://www.knockmeout.net/2012/06/knockoutjs-performance-gotcha-3-all-bindings.html
  94. ko.computed({
  95. read: function () {
  96. var _allBindings = ko.utils.unwrapObservable(allBindingsAccessor());
  97. var _options = _allBindings.editableOptions || {};
  98. if (_options.enabled != null && _options.enabled) {
  99. $editable.editable('enable');
  100. }
  101. else {
  102. $editable.editable('disable');
  103. }
  104. var val = ko.utils.unwrapObservable(valueAccessor());
  105. if (val === null) val = '';
  106. $editable.editable('setValue', val, true)
  107. },
  108. owner: this,
  109. disposeWhenNodeIsRemoved: element
  110. });
  111. if (editableOptions.visible && ko.isObservable(editableOptions.visible)) {
  112. ko.computed({
  113. read: function () {
  114. var val = ko.utils.unwrapObservable(editableOptions.visible());
  115. if (val)
  116. $editable.editable('show');
  117. },
  118. owner: this,
  119. disposeWhenNodeIsRemoved: element
  120. });
  121. $editable.on('hidden.ko', function (e, params) {
  122. editableOptions.visible(false);
  123. });
  124. }
  125. }
  126. };
  127. });