VukRC
VukRC

Reputation: 1

Summernote uploading image problem (outside of note-editable)

I have problem regarding uploading image sometimes inside the editor. When I upload image, image is going outside of note-editable div. I saw that some people has same problem but I did not find the solution. Here is the image:

enter image description here

As you can see, the image is outside of note-editable div. I was trying to fix by scss hacks but it's same. Please help me if someone has same issue or know how to fix it. Thank you.

Steps:

Here is the my .ts file of summernote component:

   @Component({
    selector: 'summernote-editor',
    templateUrl: './summernote-editor.component.html',
    styleUrls: ['./summernote-editor.component.scss'],
    encapsulation: ViewEncapsulation.None,
    standalone: true,
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => SummernoteEditorComponent),
            multi: true,
        },
    ],
    imports: [FormsModule, NgxSummernoteModule],
})

export class SummernoteEditorComponent implements OnChanges, ControlValueAccessor {
    constructor() {this.InitSummernote(); }

    readonly value = signal(null);
    private onChange: Function = () => {};
    private onTouched: Function = () => {};
    summernoteConfig: any;

    ngOnChanges() {
    }

    handleOnChange(value: any) {
        this.onChangedAndTouched(value?.toString());
    }

    onChangedAndTouched(value: string) {
        this.onTouched();
        this.onChange(value);
        this.writeValue(value);
    }

    setStateTouched() {
        this.onTouched();
    }

    writeValue(obj: any): void {
        this.value.set(obj);
    }

    registerOnChange(fn: any): void {
        this.onChange = fn;
    }

    registerOnTouched(fn: any): void {
        this.onTouched = fn;
    }

    private InitSummernote() {
        // Summer Note / Description
        this.summernoteConfig = {
            disableDragAndDrop: true,
            // airMode: true,
            placeholder: '',
            tabsize: 2,
            height: '400px',
            //uploadImagePath: '/api/upload',
            toolbar: [
                ['style', ['style']],
                ['undoredo', ['undo', 'redo']],
                [
                    'font',
                    [
                        'bold',
                        'italic',
                        'underline',
                        'strikethrough',
                        'superscript',
                        'subscript',
                        'clear',
                    ],
                ],
                ['color', ['forecolor']],
                ['para', ['ul', 'ol']],
                ['insert', ['table', 'picture', 'link', 'video', 'hr']],
                ['misc', ['fullscreen', 'codeview']],
                ['mybutton', ['disableBg', 'enableBg', 'flex', 'imageLink', 'addNote', 'addWarning', 'addTip']],
            ],
            buttons: {
                disableBg: GrayBgButton,
                flex: flexAlign,
                imageLink: ImageLink,
                addNote: addNoteButton,
                addWarning: addWarningButton,
                addTip: addTipButton,
            },
            styleTags: ['h2', 'h3', 'h4', 'h5', 'p'],
            imageAttributes: {
                icon: '<i class="note-icon-pencil"/>',
                figureClass: 'figureClass',
                figcaptionClass: 'captionClass',
                captionText: 'Caption Goes Here.',
            },
            lang: 'en-US',
            popover: {
                image: [
                    [
                        'image',
                        [
                            'resizeFull',
                            'resizeHalf',
                            'resizeQuarter',
                            'resizeNone',
                        ],
                    ],
                    /*['float', ['floatLeft', 'floatRight', 'floatNone']],*/
                    ['remove', ['removeMedia']],
                    ['custom', ['imageAttributes']],
                ],
            },
            callbacks: {
                onInit: () => {
                    const editor = $('#summernote')
                    enableVideoResize(editor);
                },
            }
        };
    }

    insertImageLink() {
        const reader = new FileReader();
        const file = $("#imageFile")[0].files[0];
        const link = $("#linkUrl").val();
        const aNode = document.createElement("a");
        const img = document.createElement("img");
        if (!link) {
            alert('You need to specify anchor link');
            return;
        }
        aNode.target = "_blank";
        aNode.href = link;
        aNode.appendChild(img);

        reader.onload = function (e) {
            img.src = e.target.result as string;
            // selection
            $("#summernote").summernote("editor.saveRange");
            $("#summernote").summernote("editor.restoreRange");
            $("#summernote").summernote("editor.focus");
            $("#summernote").summernote("editor.insertNode", aNode);
            // reset
            $("#imageFile").val("");
            $("#linkUrl").val("");

        }

        reader.readAsDataURL(file);
        this.hideInsertImageLinkModal();
    }
    hideInsertImageLinkModal() {
        $('#imageLinkModal').modal('hide');
    }
}

Also here is the HTML code of my parent component where I am calling this summernote component on the bottom:

<div [formGroup]="articleForm">
<div class="modal fade" id="ModalArticle" data-bs-backdrop="static" data-bs-keyboard="true" tabindex="-1"
    aria-labelledby="staticBackdropLabel" aria-hidden="true">
    <div class="modal-dialog modal-xl">
        <div class="modal-content">

            <div class="modal-header">
                <h5 class="modal-title">
                    <span *ngIf="this.addNew">Add Article</span>
                    <span *ngIf="!this.addNew">Edit Article</span>
                </h5>
                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"
                    (click)="Close()"></button>
            </div>

            <div class="modal-body">

                <div class="row">
                    <div class="col-xs-12 col-md-4">
                        <div class="form-group">
                            <label for="isPublished">Visibility <span class="asterisks">*</span></label>
                            <div class="form-check">
                                <label class="form-check-label" for="isPublished">
                                    <input type="checkbox" class="form-check-input" id="isPublished"
                                        formControlName="isPublished"
                                        [ngClass]="{ 'is-invalid': articleForm.get('isPublished').errors && articleForm.controls['isPublished'].touched}"
                                        [ngClass]="{ 'is-valid': !articleForm.get('isPublished').errors && articleForm.controls['isPublished'].touched}" />
                                    <i *ngIf="articleForm.get('isPublished').value == false"
                                        style="color:rgb(200,200,200)">Article <b>is not published</b></i>
                                    <i *ngIf="articleForm.get('isPublished').value == true"
                                        style="color:rgb(50,50,50)">Article <b>is published</b></i>
                                </label>
                            </div>
                            <div class="form-check">
                                <label for="isPublic">
                                    <input type="checkbox" class="form-check-input" id="isPublic"
                                        formControlName="isPublic"
                                        [ngClass]="{ 'is-invalid': articleForm.get('isPublic').errors }" />
                                    <i *ngIf="articleForm.get('isPublic').value == false"
                                        style="color:rgb(200,200,200)">Article <b>is not public</b></i>
                                    <i *ngIf="articleForm.get('isPublic').value == true"
                                        style="color:rgb(50,50,50)">Article <b>is public</b></i>
                                </label>
                            </div>
                            <div class="form-check">
                                <label for="isCortexAllowed">
                                    <input type="checkbox" class="form-check-input" id="isCortexAllowed"
                                        formControlName="isCortexAllowed"
                                        [ngClass]="{ 'is-invalid': articleForm.get('isCortexAllowed').errors }" />
                                    <i *ngIf="articleForm.get('isCortexAllowed').value == false"
                                        style="color:rgb(200,200,200)">Article <b>is not editable by cortex user</b></i>
                                    <i *ngIf="articleForm.get('isCortexAllowed').value == true"
                                        style="color:rgb(50,50,50)">Article <b>is editable by cortex user</b></i>
                                </label>
                            </div>
                        </div>
                    </div>
                    <div class="col-xs-12 col-md-4">
                        <div class="form-group">
                            <label for="code">Code <span class="asterisks">*</span></label>
                            <input type="text" maxlength="10" class="form-control" formControlName="code"
                                [ngClass]="{ 'is-invalid': articleForm.get('code').errors && articleForm.controls['code'].touched }"
                                [ngClass]="{ 'is-valid': !articleForm.get('code').errors && articleForm.controls['code'].touched}" />
                            <div *ngIf="articleForm.get('code').errors != null && (articleForm.controls['code'].dirty || articleForm.controls['code'].touched)"
                                class="invalid-feedback">
                                <div *ngIf="articleForm.get('code').errors.required">Code is required</div>
                            </div>
                        </div>
                    </div>
                    <div class="col-xs-12 col-md-4">
                        <div class="form-group">
                            <label for="kbArticleVersionId">Version <span class="asterisks">*</span></label>
                            <select class="form-select" formControlName="kbArticleVersionId"
                                aria-label="Default select example"
                                [ngClass]="{ 'is-invalid': articleForm.get('kbArticleVersionId').errors && articleForm.controls['kbArticleVersionId'].touched}"
                                [ngClass]="{ 'is-valid': !articleForm.get('kbArticleVersionId').errors && articleForm.controls['kbArticleVersionId'].touched}">
                                <option *ngFor="let version of versions" value="{{version.id}}">{{version.name}}
                                </option>
                            </select>
                        </div>
                    </div>
                </div>

                <div class="row pt-3">
                    <div class="col-xs-12 col-md-6">
                        <div class="form-group">
                            <label for="subject">Subject <span class="asterisks">*</span></label>
                            <input type="text" (keyup)="subjectChanged()" maxlength="900" class="form-control"
                                formControlName="subject"
                                [ngClass]="{ 'is-invalid': articleForm.get('subject').errors && articleForm.controls['subject'].touched }"
                                [ngClass]="{ 'is-valid': !articleForm.get('subject').errors && articleForm.controls['subject'].touched}" />
                            <div *ngIf="articleForm.get('subject').errors && (articleForm.controls['subject'].dirty || articleForm.controls['subject'].touched)"
                                class="invalid-feedback">
                                <div *ngIf="articleForm.get('subject').errors.required">Subject is required</div>
                            </div>
                        </div>
                    </div>
                    <div class="col-xs-12 col-md-6">
                        <div class="form-group">
                            <label for="url">
                                Url <span class="asterisks">*</span>
                                <i style="font-size: 12px;">(Url is autogenerated by the subject)</i>
                            </label>
                            <input type="text" maxlength="1000" class="form-control" formControlName="url"
                                [ngClass]="{ 'is-invalid': articleForm.get('url').errors && articleForm.controls['url'].touched}"
                                [ngClass]="{ 'is-valid': !articleForm.get('url').errors && articleForm.controls['url'].touched}" />
                            <div *ngIf="articleForm.get('url').errors && (articleForm.controls['url'].dirty || articleForm.controls['url'].touched)"
                                class="invalid-feedback">
                                <div *ngIf="articleForm.get('url').errors.required">Url is required</div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="row pt-3">
                    <div class="col-xs-12 col-md-6">
                        <div class="form-group">
                            <label for="description">Meta description</label>
                            <input type="text" maxlength="500" class="form-control" formControlName="description" />
                        </div>
                    </div>
                    <div class="col-xs-12 col-md-6">
                        <div class="form-group">
                            <label for="tags">Tags &nbsp;<i style="font-size: 12px;">(Please use the comma , as a
                                    separator)</i></label>
                            <input type="text" maxlength="500" class="form-control" formControlName="tags" />
                        </div>
                    </div>
                </div>
                <!--CALLING SUMMERNOTE COMPONENT-->
                <div class="form-group pt-3">
                    <label for="body">Body</label>
                    <summernote-editor formControlName="body"></summernote-editor>
                </div>

            </div>

            <div class="modal-footer">
                <button type="button" #closeModal id="closeModal" (click)="Close()" type="button"
                    data-bs-dismiss="modal" class="btn btn-secondary">Close</button>
                <button type="button" class="btn btn-primary" (click)="Save()" label="Create">Save</button>
            </div>
        </div>
    </div>
</div>

And please tell me if you need something else. Thank you so much.

NOTE: Here is the link of GitHub where someone has the same problem but I did not found the solution:

https://github.com/summernote/summernote/issues/2939

Upvotes: 0

Views: 15

Answers (0)

Related Questions