Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve/fix #4435

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
minor update
hoavmavada committed Oct 2, 2024
commit 91dbff785a40956fa61d7a74c1b88d7201002812
2 changes: 1 addition & 1 deletion packages/quill/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hoavm-quill",
"version": "2.0.2-alpha1.13",
"version": "2.0.2-alpha1.15",
"description": "Your powerful, rich text editor",
"author": "Jason Chen <jhchen7@gmail.com>",
"homepage": "https://quilljs.com",
9 changes: 8 additions & 1 deletion packages/quill/src/formats/font.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,14 @@ import { ClassAttributor, Scope, StyleAttributor } from 'parchment';

const config = {
scope: Scope.INLINE,
whitelist: ['serif', 'monospace'],
whitelist: [
'arial',
'comic-sans',
'courier-new',
'georgia',
'helvetica',
'lucida',
],
};

const FontClass = new ClassAttributor('font', 'ql-font', config);
48 changes: 39 additions & 9 deletions packages/quill/src/formats/image.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
import { EmbedBlot } from 'parchment';
import { sanitize } from './link.js';
// import { sanitize } from './link.js';

const ATTRIBUTES = ['alt', 'height', 'width'];
const ATTRIBUTES = [
'alt',
'height',
'width',
'src',
'srcset',
'sizes',
'crossorigin',
'usemap',
'ismap',
'loading',
'referrerpolicy',
'decoding',
'longdesc',
'title',
'class',
'id',
'style',
'tabindex',
'draggable',
'align',
'border',
'hspace',
'vspace',
'accesskey',
];

class Image extends EmbedBlot {
static blotName = 'image';
static tagName = 'IMG';

static create(value: string) {
const node = super.create(value) as Element;
if (typeof value === 'string') {
node.setAttribute('src', this.sanitize(value));
}
static create(value: any) {
const node = document.createElement('img');
ATTRIBUTES.forEach((attr) => {
if (value[attr]) {
node.setAttribute(attr, value[attr]);
}
});
return node;
}

@@ -32,11 +59,14 @@ class Image extends EmbedBlot {
}

static sanitize(url: string) {
return sanitize(url, ['http', 'https', 'data']) ? url : '//:0';
return url;
}

static value(domNode: Element) {
return domNode.getAttribute('src');
return ATTRIBUTES.reduce((acc: any, attr) => {
acc[attr] = domNode.getAttribute(attr);
return acc;
}, {});
}

domNode: HTMLImageElement;
54 changes: 45 additions & 9 deletions packages/quill/src/formats/link.ts
Original file line number Diff line number Diff line change
@@ -7,29 +7,65 @@ class Link extends Inline {
static PROTOCOL_WHITELIST = ['http', 'https', 'mailto', 'tel', 'sms'];

static create(value: string) {
const node = super.create(value) as HTMLElement;
node.setAttribute('href', this.sanitize(value));
node.setAttribute('rel', 'noopener noreferrer');
node.setAttribute('target', '_blank');
const node = super.create();
let newValue;
if (isStringified(value)) {
newValue = JSON.parse(value);
} else {
newValue = value;
}

if (typeof newValue !== 'string') {
['href', 'target', 'title'].forEach((attr) => {
if (newValue[attr]) node.setAttribute(attr, newValue[attr]);
});
return node;
}

node.setAttribute('href', newValue);
return node;
}

static formats(domNode: HTMLElement) {
return domNode.getAttribute('href');
return JSON.stringify({
href: domNode.getAttribute('href'),
target: domNode.getAttribute('target'),
title: domNode.getAttribute('title'),
});
}

static sanitize(url: string) {
return sanitize(url, this.PROTOCOL_WHITELIST) ? url : this.SANITIZED_URL;
}

format(name: string, value: unknown) {
format(name: string, value: any) {
if (name !== this.statics.blotName || !value) {
super.format(name, value);
return super.format(name, value);
}
let newValue;
if (isStringified(value)) {
newValue = JSON.parse(value);
} else {
// @ts-expect-error
this.domNode.setAttribute('href', this.constructor.sanitize(value));
newValue = value;
}

if (typeof newValue !== 'string') {
this.domNode.setAttribute('href', newValue.href);
this.domNode.setAttribute('target', newValue.target);
this.domNode.setAttribute('title', newValue.title);
} else {
this.domNode.setAttribute('href', newValue);
}
}
}

function isStringified(value: any) {
try {
JSON.parse(value);
} catch (e) {
return false;
}
return true;
}

function sanitize(url: string, protocols: string[]) {
52 changes: 34 additions & 18 deletions packages/quill/src/formats/list.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import Quill from '../core/quill.js';

class ListContainer extends Container {}
ListContainer.blotName = 'list-container';
ListContainer.tagName = 'OL';
ListContainer.tagName = ['OL', 'UL']; // Support both ordered and unordered lists

class ListItem extends Block {
static create(value: string) {
@@ -15,7 +15,11 @@ class ListItem extends Block {
}

static formats(domNode: HTMLElement) {
return domNode.getAttribute('data-list') || undefined;
// Handle more formats for list types: ordered, unordered, checked, unchecked
const format = domNode.getAttribute('data-list') || '';
return ['ordered', 'bullet', 'checked', 'unchecked'].includes(format)
? format
: undefined;
}

static register() {
@@ -24,26 +28,37 @@ class ListItem extends Block {

constructor(scroll: Scroll, domNode: HTMLElement) {
super(scroll, domNode);
const ui = domNode.ownerDocument.createElement('span');
const listEventHandler = (e: Event) => {
if (!scroll.isEnabled()) return;
const format = this.statics.formats(domNode, scroll);
if (format === 'checked') {
this.format('list', 'unchecked');
e.preventDefault();
} else if (format === 'unchecked') {
this.format('list', 'checked');
e.preventDefault();
}
};
ui.addEventListener('mousedown', listEventHandler);
ui.addEventListener('touchstart', listEventHandler);
this.attachUI(ui);
const format = this.statics.formats(domNode);

// Create UI for checkbox if the list format is checked or unchecked
if (['checked', 'unchecked'].includes(format)) {
const ui = domNode.ownerDocument.createElement('span');
ui.classList.add('list-ui'); // Add a CSS class for styling

const listEventHandler = (e: Event) => {
if (!scroll.isEnabled()) return;

if (format === 'checked') {
this.format('list', 'unchecked');
e.preventDefault();
} else if (format === 'unchecked') {
this.format('list', 'checked');
e.preventDefault();
}
};

ui.addEventListener('mousedown', listEventHandler);
ui.addEventListener('touchstart', listEventHandler);
this.attachUI(ui);
}
}

format(name: string, value: string) {
// Extend format handling to include more list types
if (name === this.statics.blotName && value) {
this.domNode.setAttribute('data-list', value);
if (['ordered', 'bullet', 'checked', 'unchecked'].includes(value)) {
this.domNode.setAttribute('data-list', value);
}
} else {
super.format(name, value);
}
@@ -52,6 +67,7 @@ class ListItem extends Block {
ListItem.blotName = 'list';
ListItem.tagName = 'LI';

// Allow both ordered (OL) and unordered (UL) containers
ListContainer.allowedChildren = [ListItem];
ListItem.requiredContainer = ListContainer;

28 changes: 28 additions & 0 deletions packages/quill/src/formats/scriptTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Block from '../blots/block.js';

class ScriptTag extends Block {
static blotName = 'script';
static tagName = 'SCRIPT';

static insertAt() {
return;
}

static insertBefore() {
return;
}

static replaceWith() {
return;
}

format() {
return;
}

formatAt() {
return;
}
}

export default ScriptTag;
2 changes: 1 addition & 1 deletion packages/quill/src/formats/size.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { ClassAttributor, Scope, StyleAttributor } from 'parchment';

const SizeClass = new ClassAttributor('size', 'ql-size', {
scope: Scope.INLINE,
whitelist: ['small', 'large', 'huge'],
whitelist: ['extra-small', 'small', 'medium', 'large'],
});
const SizeStyle = new StyleAttributor('size', 'font-size', {
scope: Scope.INLINE,
18 changes: 12 additions & 6 deletions packages/quill/src/formats/video.ts
Original file line number Diff line number Diff line change
@@ -2,19 +2,25 @@ import { BlockEmbed } from '../blots/block.js';
import Link from './link.js';

const ATTRIBUTES = [
'title',
'sandbox',
'referrerpolicy',
'name',
'src',
'srcdoc',
'name',
'width',
'height',
'frameborder',
'allowfullscreen',
'allow',
'allowfullscreen',
'sandbox',
'referrerpolicy',
'loading',
'allowpaymentrequest',
'longdesc',
'title',
'class',
'id',
'style',
'tabindex',
'draggable',
'scrolling',
];

class Video extends BlockEmbed {
2 changes: 2 additions & 0 deletions packages/quill/src/quill.ts
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ import Link from './formats/link.js';
import Script from './formats/script.js';
import Strike from './formats/strike.js';
import Underline from './formats/underline.js';
import ScriptTag from './formats/scriptTag.js';

import Formula from './formats/formula.js';
import Image from './formats/image.js';
@@ -98,6 +99,7 @@ Quill.register(
'formats/formula': Formula,
'formats/image': Image,
'formats/video': Video,
'formats/scriptTag': ScriptTag,

'modules/syntax': Syntax,
'modules/table': Table,