editingcontroller.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. import ViewDocument from './view/document.js';
  7. import MutationObserver from './view/observer/mutationobserver.js';
  8. import SelectionObserver from './view/observer/selectionobserver.js';
  9. import FocusObserver from './view/observer/focusobserver.js';
  10. import KeyObserver from './view/observer/keyobserver.js';
  11. import Mapper from './conversion/mapper.js';
  12. import ModelConversionDispatcher from './conversion/modelconversiondispatcher.js';
  13. import {
  14. convertRangeSelection,
  15. convertCollapsedSelection,
  16. clearAttributes
  17. } from './conversion/model-selection-to-view-converters.js';
  18. import {
  19. insertText,
  20. remove,
  21. move
  22. } from './conversion/model-to-view-converters.js';
  23. import EmitterMixin from '../utils/emittermixin.js';
  24. export default class EditingController {
  25. constructor( model ) {
  26. this._listenters = Object.create( EmitterMixin );
  27. this.model = model;
  28. const view = new ViewDocument();
  29. this.view = view;
  30. this.view.addObserver( MutationObserver );
  31. this.view.addObserver( SelectionObserver );
  32. this.view.addObserver( FocusObserver );
  33. this.view.addObserver( KeyObserver );
  34. this.mapper = new Mapper();
  35. // Move selection change to model
  36. this._listenters.listenTo( this.view, 'selectionChange', ( evt, data ) => {
  37. model.enqueueChanges( () => {
  38. const viewSelection = data.newSelection;
  39. model.selection.removeAllRanges();
  40. for ( let viewRange of viewSelection.getRanges() ) {
  41. const modelRange = this.mapper.toModelRange( viewRange );
  42. model.selection.addRange( modelRange, viewSelection.isBackward );
  43. }
  44. } );
  45. } );
  46. this.modelToView = new ModelConversionDispatcher( {
  47. writer: this.view.writer,
  48. mapper: this.mapper,
  49. viewSelection: this.view.selection
  50. } );
  51. this._listenters.listenTo( this.model, 'change', ( evt, type, changes ) => {
  52. this.modelToView.convertChange( type, changes );
  53. } );
  54. this._listenters.listenTo( this.model, 'changesDone', () => {
  55. this.modelToView.convertSelection( model.selection );
  56. this.view.render();
  57. } );
  58. this.modelToView.on( 'insert:$text', insertText() );
  59. this.modelToView.on( 'remove', remove() );
  60. this.modelToView.on( 'move', move() );
  61. this.modelToView.on( 'selection', clearAttributes() );
  62. this.modelToView.on( 'selection', convertRangeSelection() );
  63. this.modelToView.on( 'selection', convertCollapsedSelection() );
  64. }
  65. createRoot( domRoot, name = 'main' ) {
  66. const viewRoot = this.view.createRoot( domRoot, name );
  67. const modelRoot = this.model.getRoot( name );
  68. this.mapper.bindElements( modelRoot, viewRoot );
  69. }
  70. destroy() {
  71. this._listenters.stopListening();
  72. }
  73. }