binding.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. var Emitter = require('emitter')
  2. /*
  3. * Binding class
  4. */
  5. function Binding (value) {
  6. this.value = value
  7. this.instances = []
  8. this.dependents = []
  9. }
  10. /*
  11. * Pre-process a passed in value based on its type
  12. */
  13. Binding.prototype.set = function (value) {
  14. var type = typeOf(value),
  15. self = this
  16. // preprocess the value depending on its type
  17. if (type === 'Object') {
  18. if (value.get) { // computed property
  19. self.isComputed = true
  20. } else { // normal object
  21. // TODO watchObject
  22. }
  23. } else if (type === 'Array') {
  24. watchArray(value)
  25. value.on('mutate', function () {
  26. self.emitChange()
  27. })
  28. }
  29. this.value = value
  30. }
  31. /*
  32. * Process the value, then trigger updates on all dependents
  33. */
  34. Binding.prototype.update = function (value) {
  35. this.set(value)
  36. this.instances.forEach(function (instance) {
  37. instance.update(value)
  38. })
  39. this.emitChange()
  40. }
  41. /*
  42. * Notify computed properties that depend on this binding
  43. * to update themselves
  44. */
  45. Binding.prototype.emitChange = function () {
  46. this.dependents.forEach(function (dept) {
  47. dept.refresh()
  48. })
  49. }
  50. /*
  51. * get accurate type of an object
  52. */
  53. var toString = Object.prototype.toString
  54. function typeOf (obj) {
  55. return toString.call(obj).slice(8, -1)
  56. }
  57. /*
  58. * augment an Array so that it emit events when mutated
  59. */
  60. var aproto = Array.prototype,
  61. arrayMutators = ['push','pop','shift','unshift','splice','sort','reverse'],
  62. arrayAugmentations = {
  63. remove: function (scope) {
  64. this.splice(scope.$index, 1)
  65. },
  66. replace: function (index, data) {
  67. if (typeof index !== 'number') {
  68. index = index.$index
  69. }
  70. this.splice(index, 1, data)
  71. }
  72. }
  73. function watchArray (collection) {
  74. Emitter(collection)
  75. arrayMutators.forEach(function (method) {
  76. collection[method] = function () {
  77. var result = aproto[method].apply(this, arguments)
  78. collection.emit('mutate', {
  79. method: method,
  80. args: aproto.slice.call(arguments),
  81. result: result
  82. })
  83. }
  84. })
  85. for (var method in arrayAugmentations) {
  86. collection[method] = arrayAugmentations[method]
  87. }
  88. }
  89. module.exports = Binding