KillerCodeMonkey / ngx-quill

Angular (>=2) components for the Quill Rich Text Editor
MIT License
1.77k stars 258 forks source link

What is the correct way to modify modules and icons? #370

Closed ArsalanSavand closed 4 years ago

ArsalanSavand commented 5 years ago

Hello, I have used ng-quill on an Angularjs project and I was able to modify modules and icons and even add new handlers and buttons.

I'm now on an Angular 7 project, I was wondering how can I modify let's say icons. Do I have to use quilljs for it which is Javascript, or is there a way to modify icons in ngx-quill ?

This is what I wrote in a component called WriteComponent and I'm not sure if It's the correct way.

import { Component, OnInit } from '@angular/core';
const Quill = require('quill');

const icons = Quill.import('ui/icons');

@Component({
  selector: 'app-write',
  templateUrl: './write.component.html',
  styleUrls: ['./write.component.scss'],
})
export class WriteComponent implements OnInit {

  constructor() {
    icons['bold'] = '<ion-icon name="add"></ion-icon>';
  }

  ngOnInit() {
  }

}

I need Quill to add new handlers, modules, icons and registering them and so on. This code works just fine, but I'm still not sure if I should do such code in Angular 7.

KillerCodeMonkey commented 5 years ago

eehm i do not know how you have did this with ng-quill. But in generel you should create a quilljs theme:

https://quilljs.com/docs/themes/#themes or override the existing style with css or build a custom toolbar:

<quill-editor>
  <div quill-editor-toolbar>
    <span class="ql-formats">
      <button class="ql-bold" [title]="'Bold'"></button>
    </span>
    <span class="ql-formats">
      <select class="ql-align" [title]="'Aligment'">
        <option selected></option>
        <option value="center"></option>
        <option value="right"></option>
        <option value="justify"></option>
      </select>
      <select class="ql-align" [title]="'Aligment2'">
        <option selected></option>
        <option value="center"></option>
        <option value="right"></option>
        <option value="justify"></option>
      </select>
    </span>
  </div>
</quill-editor>
ArsalanSavand commented 5 years ago

I can override the existing styles or build a custom toolbar. The problem is if I add an icon inside a button element, it will be override by quill.

My question is not custom toolbar. I just want to know how can I for example import something from Quill in Angular 7.

This is how I did it in Angularjs:

import Quill from "quill";

const BlockEmbed = Quill.import("blots/block/embed");
const Clipboard = Quill.import("modules/clipboard");
const icons = Quill.import("ui/icons");
KillerCodeMonkey commented 5 years ago

This should work the same with angular >2

Install the the quill typings and go an. in my demo repo i am using Quill.import to change fonts or change the default block element.

I never changed icons, but if this worked before i see no problem, why this should not work.

ArsalanSavand commented 5 years ago

Alright got it. Thanks for the quick response 👍

srinivasthutika commented 4 years ago

Arsalan, do you have your working version of angular7 project where you changed icon.

srinivasthutika commented 4 years ago

Can you give working example on importing quill icons. I am looking to import table icons from assets. This is how i am doing private getInsertTableButton() { const myButton = new QuillToolbarButton({ icon: 'TI' }); const table = this.table; myButton.onClick = function(quill) { table.insertTable(2, 2); }; myButton.attach(this.quill); }

I am using text now. How can i add icon for the same. I can see table SVG icon in quill/assets/icons

ArsalanSavand commented 4 years ago

@srinivasthutika What icons are you using? Angular FontAwesome?

If yes, then I wrote a .ts file to change QuillJs's built-in icons to FontAwesome icons:

import { CustomIcon } from '@app/interfaces/custom-icon';
import { IconDefinition } from '@fortawesome/fontawesome-common-types';
import { faYoutube } from '@fortawesome/free-brands-svg-icons';
import { faAlignCenter } from '@fortawesome/free-solid-svg-icons/faAlignCenter';
import { faAlignJustify } from '@fortawesome/free-solid-svg-icons/faAlignJustify';
import { faAlignLeft } from '@fortawesome/free-solid-svg-icons/faAlignLeft';
import { faAlignRight } from '@fortawesome/free-solid-svg-icons/faAlignRight';
import { faBan } from '@fortawesome/free-solid-svg-icons/faBan';
import { faBold } from '@fortawesome/free-solid-svg-icons/faBold';
import { faCode } from '@fortawesome/free-solid-svg-icons/faCode';
import { faImage } from '@fortawesome/free-solid-svg-icons/faImage';
import { faItalic } from '@fortawesome/free-solid-svg-icons/faItalic';
import { faLink } from '@fortawesome/free-solid-svg-icons/faLink';
import { faListUl } from '@fortawesome/free-solid-svg-icons/faListUl';
import { faMinus } from '@fortawesome/free-solid-svg-icons/faMinus';
import { faParagraph } from '@fortawesome/free-solid-svg-icons/faParagraph';
import { faQuoteRight } from '@fortawesome/free-solid-svg-icons/faQuoteRight';
import { faStrikethrough } from '@fortawesome/free-solid-svg-icons/faStrikethrough';
import { faUnderline } from '@fortawesome/free-solid-svg-icons/faUnderline';
import Quill, { StringMap } from 'quill';

/**
 * Quill icons
 */
const Icons: StringMap = Quill.import('ui/icons');

/**
 * List of icons to change
 */
const customIcons: CustomIcon[] = [{
  default: 'bold',
  new: faBold,
}, {
  default: 'italic',
  new: faItalic,
}, {
  default: 'underline',
  new: faUnderline,
}, {
  default: 'strike',
  new: faStrikethrough,
}, {
  default: 'blockquote',
  new: faQuoteRight,
}, {
  default: 'link',
  new: faLink,
}, {
  default: 'code-block',
  new: faCode,
}, {
  default: 'divider',
  new: faMinus,
}, {
  default: 'image',
  new: faImage,
}, {
  default: 'video',
  new: faYoutube,
}, {
  default: 'clean',
  new: faBan,
}];

/**
 * Convert given icon to SVG element which contains a path element
 *
 * @param icon FortAwesome icon
 * @param classList List of classes to attach to SVG element
 *
 * @see IconDefinition
 * @link https://github.com/FortAwesome/angular-fontawesome/blob/master/docs/usage.md
 *
 * @returns SVG element based on given icon
 */
export function iconToSVGElement(icon: IconDefinition, classList?: string): SVGSVGElement {
  /**
   * Create SVG element
   */
  const node: SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  /**
   * Add classes
   */
  node.classList.add('svg-inline--fa', 'fa-fw', `${icon.prefix}-${icon.iconName}`);
  if (classList) {
    node.classList.add(classList);
  }
  /**
   * Set node viewBox
   */
  node.viewBox.baseVal.width = icon.icon[0];
  node.viewBox.baseVal.height = icon.icon[1];
  /**
   * Create Path element
   */
  const path: SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  /**
   * Set `fill` attribute's value to `currentColor` so it can adjustable
   */
  path.setAttributeNS(null, 'fill', 'currentColor');
  /**
   * Set `d` attribute's value to given icon's path commands
   *
   * 'd' is a string containing a series of path commands that define the path to be drawn
   */
  path.setAttributeNS(null, 'd', icon.icon[icon.icon.length - 1] as string);
  /**
   * Append {@link path} to {@link node} as a child
   */
  node.appendChild<SVGPathElement>(path);
  /**
   * Return node
   */
  return node;
}

/**
 * Loop into {@link customIcons} and change default icons
 */
customIcons.forEach((icon: CustomIcon): void => {
  Icons[icon.default] = iconToSVGElement(icon.new).outerHTML;
});

Icons.list.bullet = iconToSVGElement(faListUl).outerHTML;
Icons.direction[''] = iconToSVGElement(faParagraph).outerHTML;
Icons.direction.rtl = iconToSVGElement(faParagraph, 'fa-flip-horizontal').outerHTML;
Icons.align[''] = iconToSVGElement(faAlignLeft).outerHTML;
Icons.align.center = iconToSVGElement(faAlignCenter).outerHTML;
Icons.align.right = iconToSVGElement(faAlignRight).outerHTML;
Icons.align.justify = iconToSVGElement(faAlignJustify).outerHTML;

Quill.register(Icons, true);
KillerCodeMonkey commented 4 years ago

@ArsalanSavand why reopening this issue?

ArsalanSavand commented 4 years ago

@KillerCodeMonkey Sorry my bad, I will just comment. I will close it now.

KillerCodeMonkey commented 4 years ago

in general this is done like for plain quilljs. So just search the issues in the quilljs repo. https://github.com/quilljs/quill/issues/1099#issuecomment-258560326

karlosmrez commented 4 years ago

How can i overwrite the dropdown icon? This icon is not into icons.js.

KillerCodeMonkey commented 4 years ago

I do Not know what icon.js is. But in general overwrite The theme css and use your own Icons / Icon Font.

Or Just build your own quilljs theme.

Or create a custom toolbar.

Modules configuration can be Passed via Input property or in the quillmodules config.

If you want to Change The behavior of an existing module you Need to implement your own Module.

In general your question is regarding quilljs. So Just ASK your question there.

There is a Guide how to create custom modules and how to customize Formats.

Karlos Mrez notifications@github.com schrieb am Fr., 27. März 2020, 12:51:

How can i overwrite the dropdown icon? This icon is not into icons.js.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/KillerCodeMonkey/ngx-quill/issues/370#issuecomment-604958639, or unsubscribe https://github.com/notifications/unsubscribe-auth/AARI4YGVAUZQYRV3232QXI3RJSHMNANCNFSM4HFEI7WQ .

konlanx commented 2 years ago

Hello!

Maybe someone can point me in the right direction as I am having problems with using quill and ngx-quill in a library and then including that library and it seems to be related to the icons, as the error-message indicates that.

Recently these projects went from Angular 9 to Angular 11. In Angular 9 we had no issues with the icons not being available. The same constellation of projects built successfully using Angular 9. Without quill the projects built successfully using Angular 11. But with quill and Angular 11 I run into issues.

I have a library that includes quill and ngx-quill. In the library we modify the icons like this:

ngOnInit(): void {
    const icons: StringMap = Quill.import('ui/icons');
    icons.bold = '<i class="icon icon-bold" aria-hidden="true"></i>';
    icons.italic = '<i class="icon icon-italic" aria-hidden="true"></i>';
...
}

When using for example storybook I can just run the library and all icons work just fine. But when I include the library in a different project I get a compilation error:

PS C:\project> ng build some-project
Building Angular Package

------------------------------------------------------------------------------
Building entry point '@some-org/some-project'
------------------------------------------------------------------------------
× Compiling TypeScript sources through NGC
ERROR: The target entry-point "@some-org/some-lib" has missing dependencies:
 - ui/icons

An unhandled exception occurred: The target entry-point "@some-org/some-lib" has missing dependencies:
 - ui/icons

See "C:\angular-errors.log" for further details.

I tried setting quill (and related libs) as whitelistedNonPeerDependencies for the library in the hopes of making the files available this way, but it did not succeed:

package.json

  "dependencies": {
    "ngx-quill": "14.3.0",
    "quill": "1.3.7",
    "quill-blot-formatter": "1.0.5",
    "quill-drag-and-drop-module": "0.3.0"
  },
  "peerDependencies": {
    "@angular/common": "11.2.14",
    "@angular/core": "11.2.14",
    "@angular/animations": "11.2.14",

ng-package.json

  "allowedNonPeerDependencies": [
    "ngx-quill",
    "quill",
    "quill-blot-formatter",
    "quill-drag-and-drop-module"
  ]

This did not help and did not resolve the issue. I also tried including quill explicitely in all projects, but the error persists.

I could verify that quill is available in node_modules and does in fact contain a folder ui and a file icons.js. This was the case for all projects, including the project that reports the missing dependency.

Am I missing something here? I am unable to pinpoint why the ui/icons would be a missing dependency.

Thanks in advance!

konlanx commented 2 years ago

The current workaround is to remove the Quill.import('ui/icons')-part and call it in the root-project that imports all libraries. This isn't optimal since we wanted to hide this code, but it works and gets rid of the error.

I was able to make the code short by keeping the logic in the library. My application now has this code:

app.component.ts

import {LibraryComponent} from '@some-org/some-lib';

ngOnInit() {
  // Initialize quill
  const icons: StringMap = Quill.import('ui/icons');
  LibraryComponent.initEditor(icons);
...
}

And in the library I have the following function:

some-component.component.ts

  public static initEditor(icons: StringMap): void {
    icons.bold = '<i class="icon icon-bold" aria-hidden="true"></i>';
    icons.italic = '<i class="icon icon-italic" aria-hidden="true"></i>';
...
}