view.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* global document */
  6. 'use strict';
  7. CKEDITOR.define( [ 'Collection', 'Model' ], function( Collection, Model ) {
  8. class View extends Model {
  9. /**
  10. * Creates an instance of the {@link View} class.
  11. *
  12. * @param {Model} mode (View)Model of this View.
  13. * @constructor
  14. */
  15. constructor( model ) {
  16. super();
  17. /**
  18. * Model of this view.
  19. */
  20. this.model = new Model( model );
  21. /**
  22. * Regions which belong to this view.
  23. */
  24. this.regions = new Collection();
  25. this.regions.on( 'add', ( evt, region ) => this.el.appendChild( region.el ) );
  26. }
  27. /**
  28. * Element of this view.
  29. *
  30. * @property el
  31. */
  32. get el() {
  33. if ( this._el ) {
  34. return this._el;
  35. }
  36. return ( this._el = this.render() );
  37. }
  38. /**
  39. * Binds a property of the model to a specific listener that
  40. * updates the view when the property changes.
  41. *
  42. * @param {Model} model Model to which the property is bound to.
  43. * @param {String} property Property name in the model.
  44. * @param {Function} [callback] Callback function executed on property change in model.
  45. * @constructor
  46. */
  47. bind( model, property, callback ) {
  48. return function( el, attr ) {
  49. // TODO: Use ES6 default arguments syntax.
  50. var changeCallback = callback || setAttribute;
  51. function setAttribute( el, value ) {
  52. el.setAttribute( attr, value );
  53. }
  54. function executeCallback( el, value ) {
  55. var result = changeCallback( el, value );
  56. if ( typeof result != 'undefined' ) {
  57. setAttribute( el, result );
  58. }
  59. }
  60. // Execute callback when the property changes.
  61. model.on( 'change:' + property, ( evt, value ) => executeCallback( el, value ) );
  62. // Set the initial state of the view.
  63. executeCallback( el, model[ property ] );
  64. };
  65. }
  66. /**
  67. * Renders {@link el} using {@link template}.
  68. *
  69. * @param {Object} [def] Template definition to be rendered.
  70. * @returns HTMLElement {@link el} ready to be injected into DOM.
  71. */
  72. render( template ) {
  73. // TODO: Use ES6 default arguments syntax.
  74. template = template || this.template;
  75. if ( !template ) {
  76. return null;
  77. }
  78. var el = document.createElement( template.tag );
  79. var attr;
  80. var value;
  81. // Set the text first.
  82. if ( template.text ) {
  83. el.innerHTML = template.text;
  84. }
  85. // Set attributes.
  86. for ( attr in template.attributes ) {
  87. value = template.attributes[ attr ];
  88. // Attribute bound directly to the model.
  89. if ( typeof value == 'function' ) {
  90. value( el, attr );
  91. }
  92. // Explicit attribute definition (string).
  93. else {
  94. // Attribute can be an array, i.e. classes.
  95. if ( Array.isArray( value ) ) {
  96. value = value.join( ' ' );
  97. }
  98. el.setAttribute( attr, value );
  99. }
  100. }
  101. // Invoke children recursively.
  102. if ( template.children ) {
  103. for ( let child of template.children ) {
  104. el.appendChild( this.render( child ) );
  105. }
  106. }
  107. return el;
  108. }
  109. destroy() {}
  110. }
  111. return View;
  112. } );