import { ApplicationRef , ComponentFactoryResolver , ComponentRef , Injector } from '@angular/core' ; import { Node as ProseMirrorNode } from 'prosemirror-model' ; import { NodeSelection , Plugin , PluginKey } from 'prosemirror-state' ; import { EditorView , NodeView } from 'prosemirror-view' ; import { Subscription } from 'rxjs' ; import { ImageViewComponent } from '../components/image-view/image-view.component' ; class ImageRezieView implements NodeView { dom : HTMLElement ; view : EditorView ; getPos : ( ) => number ; applicationRef : ApplicationRef ; imageComponentRef : ComponentRef < ImageViewComponent > ; resizeSubscription : Subscription ; node : ProseMirrorNode ; updating = false ; constructor ( node , view , getPos , injector ) { const dom = document . createElement ( 'image-view' ) ; const componentFactoryResolver = injector . get ( ComponentFactoryResolver ) ; this . applicationRef = injector . get ( ApplicationRef ) ; const factory = componentFactoryResolver . resolveComponentFactory ( ImageViewComponent ) ; this . imageComponentRef = factory . create ( injector , [ ] , dom ) ; this . applicationRef . attachView ( this . imageComponentRef . hostView ) ; this . setNodeAttributes ( node . attrs ) ; this . imageComponentRef . instance . view = view ; this . dom = dom ; this . view = view ; this . node = node ; this . getPos = getPos ; this . resizeSubscription = this . imageComponentRef . instance . imageResize . subscribe ( ( ) => { this . handleResize ( ) ; } ) ; } private computeChanges ( prevAttrs , newAttrs ) { return JSON . stringify ( prevAttrs ) === JSON . stringify ( newAttrs ) ; } private setNodeAttributes ( attrs ) { this . imageComponentRef . instance . src = attrs [ 'src' ] ; this . imageComponentRef . instance . alt = attrs [ 'alt' ] ; this . imageComponentRef . instance . title = attrs [ 'title' ] ; this . imageComponentRef . instance . outerWidth = attrs [ 'width' ] ; } handleResize = ( ) : void => { if ( this . updating ) { return ; } const { state , dispatch } = this . view ; const { tr } = state ; const transaction = tr . setNodeMarkup ( this . getPos ( ) , undefined , { ... this . node . attrs , width : this . imageComponentRef . instance . outerWidth , } ) ; const resolvedPos = transaction . doc . resolve ( this . getPos ( ) ) ; const newSelection = new NodeSelection ( resolvedPos ) ; transaction . setSelection ( newSelection ) ; dispatch ( transaction ) ; } ; update ( node ) { if ( node . type !== this . node . type ) { return false ; } this . node = node ; const changed = this . computeChanges ( this . node . attrs , node . attrs ) ; if ( changed ) { this . updating = true ; this . setNodeAttributes ( node . attrs ) ; this . updating = false ; } return true ; } ignoreMutation ( ) { return true ; } selectNode ( ) { this . imageComponentRef . instance . selected = true ; } deselectNode ( ) { this . imageComponentRef . instance . selected = false ; } destroy ( ) { this . resizeSubscription . unsubscribe ( ) ; this . applicationRef . detachView ( this . imageComponentRef . hostView ) ; } } const imageResizePlugin = ( injector ) : Plugin => { return new Plugin ( { key : new PluginKey ( 'image-resize' ) , props : { nodeViews : { image : ( node , view , getPos ) => { return new ImageRezieView ( node , view , getPos , injector ) ; } , } } } ) ; } ; export default imageResizePlugin ;