HTML5 rich text editor. Try the demo integration at

Related tags

Editors Squire
Overview

Squire

Squire is an HTML5 rich text editor, which provides powerful cross-browser normalisation in a flexible lightweight package (only 16.5KB of JS after minification and gzip, with no dependencies!).

It was designed to handle email composition for the Fastmail web app. The most important consequence of this (and where Squire differs from most other modern rich text editors) is that it must handle arbitrary HTML, because it may be used to forward or quote emails from third-parties and must be able to preserve their HTML without breaking the formatting. This means that it can't use a more structured (but limited) internal data model (as most other modern HTML editors do) and the HTML remains the source-of-truth. The other consequence is excellent handling of multiple levels of blockquotes.

Squire was designed to be integrated with your own UI framework, and so does not provide its own UI toolbar, widgets or overlays. Instead, you get a component you can insert in place of a <textarea> and manipulate programatically, allowing you to integrate seamlessly with the rest of your application and lose the bloat of having two UI toolkits loaded.

Squire supports all reasonably recent, and even moderately old, browsers (even IE11, although this is not tested much these days).

In addition to its use at Fastmail, it is also currently used in production at ProtonMail, SnappyMail, StartMail, Tutanota, Zoho Mail and Superhuman, as well as other non-mail apps including Google Earth (drop me a line if you're using Squire elsewhere, I'm always interested to hear about it!).

An example UI integration can be tried at http://neilj.github.io/Squire/. Please note though, this is an out-of-date version of Squire and a slightly buggy implementation written by an intern many years ago. For a demo of the latest version with a production-level UI integration, sign up for a free Fastmail trial :). There's also a very bare-bones integration in the repo; just clone it and open Demo.html. If you are reporting a bug, please report the steps to reproduce using Demo.html, to make sure it's not a bug in your integration.

Installation and usage

  1. Copy the contents of the build/ directory onto your server.
  2. Edit the <style> block in document.html to add the default styles you would like the editor to use (or link to an external stylesheet).
  3. In your application, instead of a <textarea>, use an <iframe src="path/to/document.html">.
  4. In your JS, attach an event listener to the load event of the iframe. When this fires you can grab a reference to the editor object through iframe.contentWindow.editor.
  5. Use the API below with the editor object to set and get data and integrate with your application or framework.

Using Squire without an iframe.

Squire can also be used without an iframe for the document. To use it this way:

  1. Add a <script> tag to load in build/squire.js (or squire-raw.js for the debuggable unminified version).
  2. Get a reference to the DOM node in the document that you want to make into the rich textarea, e.g. node = document.getElementById( 'editor-div' ).
  3. Call editor = new Squire( node ). This will instantiate a new Squire instance. Please note, this will remove any current children of the node; you must use the setHTML command after initialising to set any content.

You can have multiple squire instances in a single page without issue. If you are using the editor as part of a long lived single-page app, be sure to call editor.destroy() once you have finished using an instance to ensure it doesn't leak resources.

Security

Malicious HTML can be a source of XSS and other security issues. I highly recommended you use DOMPurify with Squire to prevent these security issues. If DOMPurify is included in the page (with the standard global variable), Squire will automatically sanitise any HTML passed in via setHTML or insertHTML (which includes HTML the user pastes from the clipboard).

You can override this by setting properties on the config object (the second argument passed to the constructor, see below). The properties are:

  • isSetHTMLSanitized: Boolean Should the HTML passed via calls to setHTML be passed to the sanitizer? If your app always sanitizes the HTML in some other way before calling this, you may wish to set this to false to avoid the overhead.
  • isInsertedHTMLSanitized: Boolean (defaults to true) – Should the HTML passed via calls to insertHTML be passed to the sanitizer? This includes when the user pastes from the clipboard. Since you cannot control what other apps put on the clipboard, it is highly recommended you do not set this to false.
  • sanitizeToDOMFragment: (html: String, isPaste: Boolean, self: Squire) -> DOMFragment A custom sanitization function. This will be called instead of the default call to DOMPurify to sanitize the potentially dangerous HTML. It is passed three arguments: the first is the string of HTML, the second is a boolean indicating if this content has come from the clipboard, rather than an explicit call by your own code, the third is the squire instance. It must return a DOM Fragment node belonging to the same document as the editor's root node, with the contents being clean DOM nodes to set/insert.

Advanced usage

Squire provides an engine that handles the heavy work for you, making it easy to add extra features. With the changeFormat method you can easily add or remove any inline formatting you wish. And the modifyBlocks method can be used to make complicated block-level changes in a relatively easy manner.

If you load the library into a top-level document (rather than an iframe), or load it in an iframe without the data-squireinit="true" attribute on its <html> element, it will not turn the page into an editable document, but will instead add a constructor named Squire to the global scope.

You can also require the NPM package squire-rte to import Squire in a modular program without adding names to the global namespace.

Call new Squire( document ), with the document from an iframe to instantiate multiple rich text areas on the same page efficiently. Note, for compatibility with all browsers (particularly Firefox), you MUST wait for the iframe's onload event to fire before instantiating Squire.

If you need more commands than in the simple API, I suggest you check out the source code (it's not very long), and see how a lot of the other API methods are implemented in terms of these two methods.

The general philosophy of Squire is to allow the browser to do as much as it can (which unfortunately is not very much), but take control anywhere it deviates from what is required, or there are significant cross-browser differences. As such, the document.execCommand method is not used at all; instead all formatting is done via custom functions, and certain keys, such as 'enter' and 'backspace' are handled by the editor.

Setting the default block style

By default, the editor will use a <div> for blank lines, as most users have been conditioned by Microsoft Word to expect Enter to act like pressing return on a typewriter. If you would like to use <p> tags (or anything else) for the default block type instead, you can pass a config object as the second parameter to the squire constructor. You can also pass a set of attributes to apply to each default block:

var editor = new Squire( document, {
    blockTag: 'P',
    blockAttributes: { style: 'font-size: 16px;' }
})

If using the simple setup, call editor.setConfig(…); with your config object instead. Be sure to do this before calling editor.setHTML().

Determining button state

If you are adding a UI to Squire, you'll probably want to show a button in different states depending on whether a particular style is active in the current selection or not. For example, a "Bold" button would be in a depressed state if the text under the cursor is already bold.

The efficient way to determine the state for most buttons is to monitor the "pathChange" event in the editor, and determine the state from the new path. If the selection goes across nodes, you will need to call the hasFormat method for each of your buttons to determine whether the styles are active. See the getPath and hasFormat documentation for more information.

License

Squire is released under the MIT license. See LICENSE for full license.

API

addEventListener

Attach an event listener to the editor. The handler can be either a function or an object with a handleEvent method. This function or method will be called whenever the event fires, with an event object as the sole argument. The following events may be observed:

  • focus: The editor gained focus.
  • blur: The editor lost focus
  • keydown: Standard DOM keydown event.
  • keypress: Standard DOM keypress event.
  • keyup: Standard DOM keyup event.
  • input: The user inserted, deleted or changed the style of some text; in other words, the result for editor.getHTML() will have changed.
  • pathChange: The path (see getPath documentation) to the cursor has changed. The new path is available as the path property on the event object.
  • select: The user selected some text.
  • cursor: The user cleared their selection or moved the cursor to a different position.
  • undoStateChange: The availability of undo and/or redo has changed. The event object has two boolean properties, canUndo and canRedo to let you know the new state.
  • willPaste: The user is pasting content into the document. The content that will be inserted is available as either the fragment property on the event object, or the text property for plain text being inserted into a <pre>. You can modify this text/fragment in your event handler to change what will be pasted. You can also call the preventDefault on the event object to cancel the paste operation.

The method takes two arguments:

  • type: The event to listen for. e.g. 'focus'.
  • handler: The callback function to invoke

Returns self (the Squire instance).

removeEventListener

Remove an event listener attached via the addEventListener method.

The method takes two arguments:

  • type: The event type the handler was registered for.
  • handler: The handler to remove.

Returns self (the Squire instance).

setKeyHandler

Adds or removes a keyboard shortcut. You can use this to override the default keyboard shortcuts (e.g. Ctrl-B for bold – see the bottom of KeyHandlers.js for the list).

This method takes two arguments:

  • key: The key to handle, including any modifiers in alphabetical order. e.g. "alt-ctrl-meta-shift-enter"
  • fn: The function to be called when this key is pressed, or null if removing a key handler. The function will be passed three arguments when called:
    • self: A reference to the Squire instance.
    • event: The key event object.
    • range: A Range object representing the current selection.

Returns self (the Squire instance).

focus

Focuses the editor.

The method takes no arguments.

Returns self (the Squire instance).

blur

Removes focus from the editor.

The method takes no arguments.

Returns self (the Squire instance).

getDocument

Returns the document object of the editable area. May be useful to do transformations outside the realm of the API.

getHTML

Returns the HTML value of the editor in its current state. This value is equivalent to the contents of the <body> tag and does not include any surrounding boilerplate.

setHTML

Sets the HTML value for the editor. The value supplied should not contain <body> tags or anything outside of that.

The method takes one argument:

  • html: The html to set.

Returns self (the Squire instance).

getSelectedText

Returns the text currently selected in the editor.

insertImage

Inserts an image at the current cursor location.

The method takes two arguments:

  • src: The source path for the image.
  • attributes: (optional) An object containing other attributes to set on the <img> node. e.g. { class: 'class-name' }. Any src attribute will be overwritten by the url given as the first argument.

Returns a reference to the newly inserted image element.

insertHTML

Inserts an HTML fragment at the current cursor location, or replaces the selection if selected. The value supplied should not contain <body> tags or anything outside of that.

The method takes one argument:

  • html: The html to insert.

Returns self (the Squire instance).

getPath

Returns the path through the DOM tree from the <body> element to the current current cursor position. This is a string consisting of the tag, id, class, font, and color names in CSS format. For example BODY>BLOCKQUOTE>DIV#id>STRONG>SPAN.font[fontFamily=Arial,sans-serif]>EM. If a selection has been made, so different parts of the selection may have different paths, the value will be (selection). The path is useful for efficiently determining the current formatting for bold, italic, underline etc, and thus determining button state. If a selection has been made, you can has the hasFormat method instead to get the current state for the properties you care about.

getFontInfo

Returns an object containing the active font family, size, colour and background colour for the the current cursor position, if any are set. The property names are respectively family, size, color and backgroundColor. It looks at style attributes to detect this, so will not detect <FONT> tags or non-inline styles. If a selection across multiple elements has been made, it will return an empty object.

createRange

Creates a range in the document belonging to the editor. Takes 4 arguments, matching the W3C Range properties they set:

  • startContainer
  • startOffset
  • endContainer (optional; if not collapsed)
  • endOffset (optional; if not collapsed)

getCursorPosition

Returns a bounding client rect (top/left/right/bottom properties relative to the viewport) for the current selection/cursor.

getSelection

Returns a W3C Range object representing the current selection/cursor position.

setSelection

Changes the current selection/cursor position.

The method takes one argument:

Returns self (the Squire instance).

moveCursorToStart

Removes any current selection and moves the cursor to the very beginning of the document.

Returns self (the Squire instance).

moveCursorToEnd

Removes any current selection and moves the cursor to the very end of the document.

Returns self (the Squire instance).

saveUndoState

Saves an undo checkpoint with the current editor state. Methods that modify the state (e.g. bold/setHighlightColour/modifyBlocks) will automatically save undo checkpoints; you only need this method if you want to modify the DOM outside of one of these methods, and you want to save an undo checkpoint first.

Returns self (the Squire instance).

undo

Undoes the most recent change.

Returns self (the Squire instance).

redo

If the user has just undone a change, this will reapply that change.

Returns self (the Squire instance).

hasFormat

Queries the editor for whether a particular format is applied anywhere in the current selection.

The method takes two arguments:

  • tag: The tag of the format
  • attributes: (optional) Any attributes the format.

Returns true if the entire selection is contained within an element with the specified tag and attributes, otherwise returns false.

bold

Makes any non-bold currently selected text bold (by wrapping it in a <b> tag).

Returns self (the Squire instance).

italic

Makes any non-italic currently selected text italic (by wrapping it in an <i> tag).

Returns self (the Squire instance).

underline

Makes any non-underlined currently selected text underlined (by wrapping it in a <u> tag).

Returns self (the Squire instance).

removeBold

Removes any bold formatting from the selected text.

Returns self (the Squire instance).

removeItalic

Removes any italic formatting from the selected text.

Returns self (the Squire instance).

removeUnderline

Removes any underline formatting from the selected text.

Returns self (the Squire instance).

makeLink

Makes the currently selected text a link. If no text is selected, the URL or email will be inserted as text at the current cursor point and made into a link.

This method takes two arguments:

  • url: The url or email to link to.
  • attributes: (optional) An object containing other attributes to set on the <a> node. e.g. { target: '_blank' }. Any href attribute will be overwritten by the url given as the first argument.

Returns self (the Squire instance).

removeLink

Removes any link that is currently at least partially selected.

Returns self (the Squire instance).

setFontFace

Sets the font face for the selected text.

This method takes one argument:

  • font: A comma-separated list of fonts (in order of preference) to set.

Returns self (the Squire instance).

setFontSize

Sets the font size for the selected text.

This method takes one argument:

Returns self (the Squire instance).

setTextColour

Sets the colour of the selected text.

This method takes one argument:

  • colour: The colour to set. Any CSS colour value is accepted, e.g. '#f00', or 'hsl(0,0,0)'.

Returns self (the Squire instance).

setHighlightColour

Sets the colour of the background of the selected text.

This method takes one argument:

  • colour: The colour to set. Any CSS colour value is accepted, e.g. '#f00', or 'hsl(0,0,0)'.

Returns self (the Squire instance).

setTextAlignment

Sets the text alignment in all blocks at least partially contained by the selection.

This method takes one argument:

  • alignment: The direction to align to. Can be 'left', 'right', 'center' or 'justify'.

Returns self (the Squire instance).

setTextDirection

Sets the text direction in all blocks at least partially contained by the selection.

This method takes one argument:

  • direction: The text direction. Can be 'ltr' or 'rtl'.

Returns self (the Squire instance).

forEachBlock

Executes a function on each block in the current selection, or until the function returns a truthy value.

This method takes two arguments:

  • fn The function to execute on each block node at least partially contained in the current selection. The function will be called with the block node as the only argument.
  • mutates A boolean indicating whether your function may modify anything in the document in any way.

Returns self (the Squire instance).

modifyBlocks

Extracts a portion of the DOM tree (up to the block boundaries of the current selection), modifies it and then reinserts it and merges the edges. See the code for examples if you're interested in using this function.

This method takes one argument:

  • modify The function to apply to the extracted DOM tree; gets a document fragment as a sole argument. this is bound to the Squire instance. Should return the node or fragment to be reinserted in the DOM.

Returns self (the Squire instance).

increaseQuoteLevel

Increases by 1 the quote level (number of <blockquote> tags wrapping) all blocks at least partially selected.

Returns self (the Squire instance).

decreaseQuoteLevel

Decreases by 1 the quote level (number of <blockquote> tags wrapping) all blocks at least partially selected.

Returns self (the Squire instance).

makeUnorderedList

Changes all at-least-partially selected blocks to be part of an unordered list.

Returns self (the Squire instance).

makeOrderedList

Changes all at-least-partially selected blocks to be part of an ordered list.

Returns self (the Squire instance).

removeList

Changes any at-least-partially selected blocks which are part of a list to no longer be part of a list.

Returns self (the Squire instance).

increaseListLevel

Increases by 1 the nesting level of any at-least-partially selected blocks which are part of a list.

Returns self (the Squire instance).

decreaseListLevel

Decreases by 1 the nesting level of any at-least-partially selected blocks which are part of a list.

Returns self (the Squire instance).

code

If no selection, or selection across blocks, converts the block to a <pre> to format the text as fixed-width. If a selection within a single block is present, wraps that in <code> tags for inline formatting instead.

Returns self (the Squire instance).

removeCode

If inside a <pre>, converts that to the default block type instead. Otherwise, removes any <code> tags.

Returns self (the Squire instance).

toggleCode

If inside a <pre> or <code>, calls removeCode(), otherwise callse code().

Returns self (the Squire instance).

removeAllFormatting

Removes all formatting from the selection. Block elements (list items, table cells, etc.) are kept as separate blocks.

Returns self (the Squire instance).

changeFormat

Change the inline formatting of the current selection. This is a high-level method which is used to implement the bold, italic etc. helper methods. THIS METHOD IS ONLY FOR USE WITH INLINE TAGS, NOT BLOCK TAGS. It takes 4 arguments:

  1. An object describing the formatting to add, or null if you only wish to remove formatting. If supplied, this object should have a tag property with the string name of the tag to wrap around the selected text (e.g. "STRONG") and optionally an attributes property, consisting of an object of attributes to apply to the tag (e.g. {"class": "bold"}).
  2. An object describing the formatting to remove, in the same format as the object given to add formatting, or null if you only wish to add formatting.
  3. A Range object with the range to apply the formatting changes to (or null/omit to apply to current selection).
  4. A boolean (defaults to false if omitted). If true, any formatting nodes that cover at least part of the selected range will be removed entirely (so will potentially be removed from text outside the selected range as well). If false, the formatting nodes will continue to apply to any text outside the selection. This is useful, for example, when removing links. If any of the text in the selection is part of a link, the whole link is removed, rather than the link continuing to apply to bits of text outside the selection.

modifyDocument

Takes in a function that can modify the document without the modifications being treated as input.

This is useful when the document needs to be changed programmatically, but those changes should not raise input events or modify the undo state.

linkRegExp

This is the regular expression used to automatically mark up links when inserting HTML or after pressing space. You can change it if you want to use a custom regular expression for detecting links, or set to null to turn off link detection.

Comments
  • Honouring no-break spaces

    Honouring no-break spaces

    Hello,

    I am a user of the ProtonMail webmail service, which seems to incorporate Squire for its email editor.

    I noticed today the editor honours the "narrow no-break space" (UTF encoding U+202F) but not the "no-break space" (UTF U+00A0). By "honours" I mean that if one types, for instance, "aaaaaa[space]test[no-break space]test" then adds "a"s to the beginning until the "test" reaches the side of the editor, "test[no-break space]test" gets broken, where as "test[narrow no-break space]test" does not (which is expected behaviour). I ran tests on this implementation: https://neilj.github.io/Squire/ as well as in ProtonMail's one.

    In French this is used for instance in « quotation marks », which should not break from what they are quoting on line-end, but do require inlay spacing.

    For info, the narrow no-break space is a latter addition to unicode. It is the one that should be used in French, but in effect, it is rarely seen, and the plain no-break space is usually preferred. See: https://en.wikipedia.org/wiki/Non-breaking_space for more information.

    Thanks for a great editor though, just thought I'd mentions this :) Regards, Mark.

    opened by Marcool04 13
  • Pre blocks

    Pre blocks

    I added functions to create and remove PRE elements in a sensible way. I'm not fantastically happy with the removePreformatted function - I get the sense that there are easier, better ways to do this. But it has satisfying functionality at this juncture. Said functionality is also covered by some tests. These are not exhaustive, but ought to provide a good baseline for the functionality. I put the two functions under the key shortcut 'ctrl-shift-m', which will toggle based on hasFormat('pre') whether it creates or removes PREs.

    (The things we do to make our systems engineers happy...)

    opened by gertsonderby 13
  • Calling hasFormat in the pathChanged handler breaks functionality

    Calling hasFormat in the pathChanged handler breaks functionality

    If you call hasFormat in the pathChanged event when using Squire with a contenteditable, it seems to break the path. The path ends up being "" instead of "UL>" etc. You have to change the cursor position for it to correct itself.

    This seems odd as it seems like the most logical way to code your own buttons in this editor is to used the pathChanged event in conjunction with hasFormat so I would've thought people would come across this issue already.

    Here is a gist with an example that breaks here: https://gist.github.com/JaTochNietDan/364bce89fa1cf131602ba955ad262d9b

    Edit: I've narrowed it down to being related to calling getSelection in the event handler. If you use editor.getSelection() in the event handler it causes the same issue. That function is also used in hasFormat. It is this line that's causing it: https://github.com/neilj/Squire/blob/master/build/squire-raw.js#L2927

    It seems to be a race condition because if you add a timeout before calling getSelection then the issue doesn't occur.

    opened by JaTochNietDan 12
  • Add

    Add "clear formatting" feature

    There is no way to completely reset all of the text attributes of text pasted into the text area. Gmail has "clear formatting" button which does that. I propose we add this to the editor. Are there technical difficulties preventing implementation of clear formatting feature?

    I really miss this in fastmail. I usually have notepad open just to paste text into it and immediately copy it into fastmail.

    opened by AmadeusW 12
  • iOS (WKWebView) Hangs on Ctrl+B|U|I

    iOS (WKWebView) Hangs on Ctrl+B|U|I

    This is for the WKWebView control and not necessarily Safari. If you do a ctrl+b, ctrl+i, or ctrl+u in the editor it will case the UI to hang. After doing a little debugging, I noticed the _docWasChanged function is getting called continuously until another key is pressed. This appears to be more of an issue with WKWebView's MutationObserver implementation, but I wanted to report in case others were seeing similar issues. I fixed by disabling the MutationObserver, but have not fully tested to see if there are other issues caused by my change.

    Possible fix: var canObserveMutations = typeof MutationObserver !== 'undefined' && !isIOS;

    opened by mikep-ll 9
  • If the range is collapsed doesn't modify the font size

    If the range is collapsed doesn't modify the font size

    Hello! If the range is collapsed we can not increase/decrease the font size. For example, if the user want to start from the current caret position with a bigger font size...

    Thanks!

    opened by frankai 9
  • cannot paste image from clipboard, works in Trix, Quill, GitHub, etc

    cannot paste image from clipboard, works in Trix, Quill, GitHub, etc

    Reproduce:

    1. create a screen shot using any of:

      • "Take Screenshot" with Gimp
      • "Take a Screenshot" in FF context menu
      • Flameshot
      • possibly any other screenshot utility?
    2. Open http://neilj.github.io/Squire/

    3. Paste the image in using CTRL+V

    4. nothing happens

    Other editors handle it fine:

    Quill: image

    Trix image

    And finally Github editor: image

    opened by tomholub 8
  • No scrolling editor's iframe when a new paragraph is opened at the last line

    No scrolling editor's iframe when a new paragraph is opened at the last line

    Dear Author of (nice) Squire When you edit the last line in the current paragraph and it happens to be the last line visible in the editor's iframe, pressing Enter to open new paragraph hides the cursor and no scroll action is executed. Best wishes Vwadec Skarbek

    opened by vwadec-skarbek 8
  • Scroll behaviour

    Scroll behaviour

    Hi,

    There is an issue when you add something inside the editor, ex:

    Many paste

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
    consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
    cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
    proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    

    Actual behaviour: It doesn't scroll for a copy/paste, only if there is a keyup/down.

    squiredemoopt

    Edit: No scroll for ENTER_KEY.

    opened by dhoko 7
  • How to add more custom functionality to the Editor?

    How to add more custom functionality to the Editor?

    Hey Let's say I want some functionality(button) of my own in my editor, I cannot find any API to add new custom functionality with buttons and shortcuts in you documentation, I reviewed some of the codes but couldn't figure the code structure out.

    Any advice? Thanks in advance

    opened by alphamarket 7
  • Shortcut for increase list level and decrease list level

    Shortcut for increase list level and decrease list level

    Hi , Tab and shift+tab -> for increasing and decreasing list level respectively. So that every time I need not go to the toolbar for doing this.This feature is available in many standard editors. I think it will be very useful if this feature is provided in Squire too.

    Also for eg:

    1.sample1 2.sample2 3.sample3 4.sample4

    In the above case if i select the entire ordered list and apply makeOrderedList , It should remove the list structure (removeList should work). More like toggling .This also seem to be available in many editors. It would be really nice if these features are available in Squire .

    Thank you.

    opened by mukundmurrali 7
  • Header element gets ignored when pasted in the editor

    Header element gets ignored when pasted in the editor

    Editor : http://neilj.github.io/Squire/ Sample header : https://azkarim.netlify.app/scrap/header.html

    Copy and pasting the sample header into the editor results in nothing being appeared in the editor. Note this is only applicable if you are visiting the sample header site from Firefox

    Chrome and Safari changes it to p tag. You can check the underlying markup by pasting here https://html-online.com/editor/

    opened by azkarim 0
  • Inserted HTML <button> gets immediately removed

    Inserted HTML

    Hello, I tried to add some HTML within the editor div that contains a clickable <button onclick="doStuff()">Test</button>, I can see the button for a short time then it gets removed and replaced by a div instead. Is there a way to configure/prevent this behavior?

    opened by Patapom 0
  • Problem on editing Japanese text on iOS 14.5.1

    Problem on editing Japanese text on iOS 14.5.1

    Hi. Thank you very much for your effort on maintaining this great repository. Anyway, I've found a problem on editing Japanese text on Squire on iOS Safari.

    Environment

    • iOS: Ver 14.5.1
    • Device: iPhone X
    • Web browser: Safari

    Reproduce instruction

    • Input some Japanese text on Squire demo.
    • Press the ordered-list button on the edit menu.
    • It doesn't appear any ordered-list on that text.

    Problem

    I recorded a video of the above procedure in Safari on the iPhoneX, showing how the screen moves and how the DOM in the editing area changes in the inspector.

    As you can see from these captured video,

    • during the Japanese input process of IME, the entered Japanese text is inserted in the entire<div>...</div>,
    • however, once you finish the Japanese text process of IME, the pair of <div></div> disappears and the text is moved directly under the <body> tag.
    • The problem I pointed out above with the list item button not responding is probably due to the <div> not being set correctly.

    I hope it will be fixed as soon as possible. Best regards.

    opened by MasahiroMorita 0
  • Unexpected call to sanitizeToDOMFragment in Version 11.1.1 breaking new lines in iOS

    Unexpected call to sanitizeToDOMFragment in Version 11.1.1 breaking new lines in iOS

    Since version 11.1.1 there is a Problem with creating a new line on iOS.

    When using a simple sanitizeToDOMFragment like this:

    const createSanitizeToDOMFragment = () => {
      const purify = createDOMPurify(window);
      purify.setConfig({
        ALLOWED_TAGS: ["div", "br"],
        RETURN_DOM: true,
      });
    
      return (html: string) => {
        const frag = document.createDocumentFragment();
        if (html) {
          // Added this for debug.
          alert(html);
    
          const sanitized = purify.sanitize(html);
          while (sanitized.firstChild) {
            frag.appendChild(sanitized.firstChild);
          }
        }
        return frag;
      };
    };
    

    Starting with version 11.1.1 sanitizeToDOMFragment would be called when tapping Enter to create a new line.

    image

    Afterwards the cursor gets moved to the beginning of the RTE without actually creating a new line.

    image

    This only happens in version 11.1.1, so it must be caused by this commit https://github.com/neilj/Squire/commit/108ff8f4756db384b4607f42469eaee142c91aea

    As a workaround I have downgraded to 11.1.0 which fixed the issue.

    Also I want to take this moment to thank you all for this awesome open source project <3

    opened by cvle 0
  • Additional line breaks - creates extra spacing in HTML

    Additional line breaks - creates extra spacing in HTML

    Hi,

    Context: We're using Squire as a HTML editor primarily for HTML that is generated by Outlook originally.

    We've noticed that for <p> elements (and others) that Squire inserts a <br> at the end, it's this line: https://github.com/neilj/Squire/blob/8ff042dd22f34a50e79e122bc443e9227035ebaa/source/Node.js#L277

    Testing internally, by removing this line, does indeed break the cursor as expected. (but we get lovely clean HTML)

    But unfortunately this is affecting our output from Squire with it adding in a bunch of <br>s and extra whitespace in :(

    HTML Before:

    <p class="MsoNormal">Test</p>
    

    HTML After:

    <p class="MsoNormal">Test<br></p>
    

    How are other people handling this? Should we re-process the HTML afterwards and strip these out? Are we maybe doing something dumb with the way we get the HTML back from Squire? (listening to the input event and using .getHTML())

    opened by mattisdada 1
  • Korean Language, for some chars the cursor jump back to previous line and deleted last typed copy text.

    Korean Language, for some chars the cursor jump back to previous line and deleted last typed copy text.

    Problem Statement: Using this lib in hybrid mobile app, device is iOS. During the writing mail in Korean language, for some specific characters when press the enter(return) key and again start typing in next line, the cursor jump back to just previous line and new line copy text got deleted. Any help would be appreciated.

    opened by ucs123 0
Open source rich text editor based on HTML5 and the progressive-enhancement approach. Uses a sophisticated security concept and aims to generate fully valid HTML5 markup by preventing unmaintainable tag soups and inline styles.

This project isn’t maintained anymore Please check out this fork. wysihtml5 0.3.0 wysihtml5 is an open source rich text editor based on HTML5 technolo

Christopher Blum 6.5k Dec 30, 2022
Popline is an HTML5 Rich-Text-Editor Toolbar

popline Popline is a non-intrusive WYSIWYG editor that shows up only after selecting a piece of text on the page, inspired by popclip. Usage Load jQue

kenshin 1k Nov 4, 2022
Override the rich text editor in Strapi admin with ToastUI Editor.

strapi-plugin-wysiwyg-tui-editor ⚠️ This is a strapi v4 plugin which does not support any earlier version! A Strapi plugin to replace the default rich

Zhuo Chen 12 Dec 23, 2022
Simple rich text editor (contentEditable) for jQuery UI

Hallo - contentEditable for jQuery UI Hallo is a very simple in-place rich text editor for web pages. It uses jQuery UI and the HTML5 contentEditable

Henri Bergius 2.4k Dec 17, 2022
A modern, simple and elegant WYSIWYG rich text editor.

jQuery-Notebook A simple, clean and elegant WYSIWYG rich text editor for web aplications Note: Check out the fully functional demo and examples here.

Raphael Cruzeiro 1.7k Dec 12, 2022
Medium.com WYSIWYG editor clone. Uses contenteditable API to implement a rich text solution.

If you would be interested in helping to maintain one of the most successful WYSIWYG text editors on github, let us know! (See issue #1503) MediumEdit

yabwe 15.7k Jan 4, 2023
Tiny bootstrap-compatible WISWYG rich text editor

bootstrap-wysiwyg Important information for Github requests/issues Please do not submit issues/comments to this repo. Instead, submit it to https://gi

MindMup 5.6k Jan 3, 2023
A rich text editor for everyday writing

Trix A Rich Text Editor for Everyday Writing Compose beautifully formatted text in your web application. Trix is a WYSIWYG editor for writing messages

Basecamp 17.3k Jan 3, 2023
A powerful WYSIWYG rich text web editor by pure javascript

KothingEditor A powerful WYSIWYG rich text web editor by pure javascript Demo : kothing.github.io/editor The KothingEditor is a lightweight, flexible,

Kothing 34 Dec 25, 2022
The world's #1 JavaScript library for rich text editing. Available for React, Vue and Angular

TinyMCE TinyMCE is the world's most advanced open source core rich text editor. Trusted by millions of developers, and used by some of the world's lar

Tiny 12.4k Jan 4, 2023
A completely customizable framework for building rich text editors. (Currently in beta.)

A completely customizable framework for building rich text editors. Why? · Principles · Demo · Examples · Documentation · Contributing! Slate lets you

Ian Storm Taylor 26.2k Dec 30, 2022
Collection of tools for building rich text editors.

psst we have great documentation at https://bangle.dev What is bangle.dev ? bangle.dev is a collection of components for building powerful editing exp

null 553 Dec 29, 2022
Raptor, an HTML5 WYSIWYG content editor!

Raptor Editor Raptor Editor is a user-focused extensible WYSIWYG website content editor - check out the Demo. It is designed to be user and developer

PANmedia 533 Sep 24, 2022
A markdown editor. http://lab.lepture.com/editor/

Editor A markdown editor you really want. Sponsors Editor is sponsored by Typlog. Overview Editor is not a WYSIWYG editor, it is a plain text markdown

Hsiaoming Yang 2.8k Dec 19, 2022
A chrome extension which helps change ace editor to monaco editor in web pages, supporting all features including autocompletes.

Monaco-It Monaco-It is a chrome extension turning Ace Editor into Monaco Editor, supporting all features including autocompletes. 一些中文说明 Supported Lan

null 3 May 17, 2022
Typewriter is a simple, FOSS, Web-based text editor that aims to provide a simple and intuitive environment for you to write in.

Typewriter Typewriter is a simple, FOSS, Web-based text editor that aims to provide a simple and intuitive environment for you to write in. Features S

Isla 2 May 24, 2022
Verbum is a fully flexible text editor based on lexical framework.

Verbum Verbum - Flexible Text Editor for React Verbum is a fully flexible rich text editor based on lexical-playground and lexical framework. ⚠️ As th

Ozan Yurtsever 560 Dec 29, 2022
The next generation Javascript WYSIWYG HTML Editor.

Froala Editor V3 Froala WYSIWYG HTML Editor is one of the most powerful JavaScript rich text editors ever. Slim - only add the plugins that you need (

Froala 5k Jan 1, 2023
Ace (Ajax.org Cloud9 Editor)

Ace (Ajax.org Cloud9 Editor) Note: The new site at http://ace.c9.io contains all the info below along with an embedding guide and all the other resour

Ajax.org B.V. 25.2k Jan 4, 2023