binding.js 2.5 KB

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