Giter Club home page Giter Club logo

squire's Introduction

Squire

Squire is an HTML5 rich text editor, which provides powerful cross-browser normalisation in a flexible lightweight package (only 16KB 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 is 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 programmatically, 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 browsers. It no longer supports any version of IE.

In addition to its use at Fastmail, it is also currently used in production at ProtonMail, SnappyMail, StartMail, Tutanota, Zoho Mail, Superhuman and Teamwork Desk, 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!).

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. Add Squire to your project: npm install squire-rte
  2. In your code, import Squire from 'squire-rte';
  3. Create your editor by calling editor = new Squire(node);.

Invoke with script tag

Squire can also be used in a script tag:

  1. Add a <script> tag to load in dist/squire.js (or squire-raw.js for the debuggable unminified version):
<script type="text/javascript" src="dist/squire.js"></script>
  1. 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').
  2. 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.

Editor lifecycle

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. You MUST provide a method to safely convert raw HTML into DOM nodes to use Squire. Squire will automatically integrate with DOMPurify to do this if present in the page. Otherwise you must set a custom sanitizeToDOMFragment function in your config.

  • sanitizeToDOMFragment: (html: string, editor: Squire) => DocumentFragment A custom sanitization function. This will be called instead of the default call to DOMPurify to sanitize the potentially dangerous HTML. It is passed two arguments: the first is the string of HTML, the second 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 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;' }
});

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's detail property 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 a detail property, which is an object with 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, or the text property for plain text, on the detail property of the event. 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.
  • pasteImage: The user is pasting image content into the document.

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).

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, color and background color for the the current cursor position, if any are set. The property names are respectively fontFamily, fontSize, color and backgroundColor (matching the CSS property names). 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/setHighlightColor/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).

setTextColor

Sets the color of the selected text.

This method takes one argument:

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

Returns self (the Squire instance).

setHighlightColor

Sets the color of the background of the selected text.

This method takes one argument:

  • color: The color to set. Any CSS color 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 /[]/ to turn off link detection.

squire's People

Contributors

akauffmangg avatar callumskeet-fm avatar chasenstark avatar crabmusket avatar craigmarvelley avatar cvrebert avatar dhoko avatar goldfire avatar ibash avatar ioanmo226 avatar jap avatar jatochnietdan avatar kkirsche avatar kyselberg avatar limonte avatar masonicboom avatar mkoryak avatar neilj avatar nowylie avatar priceld avatar rafalfilipek avatar selvan avatar sethfalco avatar shiawuen avatar shiren avatar stebalien avatar timgates42 avatar xfra35 avatar xionglun avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

squire's Issues

getSelectedText() returns wrong text.

I am getting a the wrong text in Squire when I use getSelectedText() on an empty line.

Assuming content of the editor is the following html block, getSelectedText() returns "456" if the selection is an empty line

<div>123<br></div>
<div><br></div>
<div><br></div>
<div><br></div>
<div>456<br></div>

any idea for modify the image inserted?

is there plugins or demos? thanks.

maybe we need some functions like:

  • getSelectedNode(), returns current selected node;
  • selectNode(node), select node (in range)

Deleting a link doesn't delete the anchor tag

Reproducable on the demo page (Chrome 40 Linux). Paste a link, then delete the text link. The anchor remains. You can do it over and over and get a pretty funky tree of elements.

squire-links

Empty line (<div><br></div>) appended when deleting with backspace

This bug does not show up in your demo page (http://neilj.github.io/Squire/), but it does show up if I try using Squire in a custom document or even in the Demo.html from your repository.

To reproduce the bug: type a few letters on the 1st line in a fresh editor window then delete one letter and you'll see that a new empty line was just appended below (press down arrow and the cursor will step down one line).

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.

Can't Escape Tag

At the end of the editor, if you have a tag running (say a span) around the text, there is no intuitive way to escape out of it.

Suggested route, would probably to escape the tag on enter?

media integration- slideshare and youtube

I am using the editor but i did not see the option of embedding the slideshare code and youtube code.
OR to see the source code.
Can you tell me how to sort out these feature into squire.

Register package in bower registry

More informations http://bower.io/docs/creating-packages/

  • The package name must adhere to the bower.json spec.
  • There must be a valid manifest JSON in the current working directory.
  • Your package should use semver Git tags.
  • Your package must be publically available at a Git endpoint (e.g., GitHub).
  • Remember to push your Git tags!

Empty link at end of HTML in latest Chromium

I'm running Chromium 41.0.2272.76 (Developer Build) Ubuntu 14.04. Lately I noticed that the HTML output of the editor ends up with an empty link if there is a link somewhere else in the document. To recreate with the provided Demo.html file:

  1. Type some text in the editor
  2. On a new line, type some text, select the text and click the "Link" button to add a link
  3. On another new line, type some text

You should end up with the following text in the editor, where the middle line is a link:

asdf
google.com
asdf

editor.getHTML() in the console returns the following:

"<div>asdf<br></div><div><a href="http://www.google.com">google.com</a><br></div><div>asdf<a href="http://www.google.com"></a><br></div>"

Notice the empty link (<a href="http://www.google.com"></a>) at the end. This happens every time I follow these steps. It does not happen when I type all three lines first then add the link on the second line. Also, it does not happen in Firefox 37.0.

Default attributes for all main tags

Hi!

It is possible in Squire to set defaults (attributes, classes) for the default block tag and the tag itself. What do you think about the ability to set attributes and classnames for all the other main tags: ul, ol, blockquote, for which Squire has built-in constructing API? Something like

editor.defaults = {
    ul: {
        'class': 'editor-list',
        ...
    },
    blockquote: {
        'class': 'editor-quote',
        ...
    },
}

Having classes on some these tags may be very convenient in that if one have given ul some stiles, he|she doesn't have to override all the other lists' styles.

Ability to add / override keyboard shortcut mapping.

I'm running Squire within a web view on iOS. The OS seems to be preventing keydown events for certain key combinations from making it through to the editor (and the JS context in general) - the tab key, ctrl-[ and ctrl-] don't trigger their assigned commands, for example.

Because of this I've had to reimplement the shortcuts for list indentation etc. Now there's two places in code where shortcuts are defined, which isn't ideal. It'd be really nice if there were a way to access Squire's shortcut map so I could add to/override the defaults. Cheers!

fix jshint warnings or silence them

jshint flips out during my build because your package is not yet on bower and i had to pull it into my codebase:

I can open a pull request if you are too busy to fix this right now

squire-raw.js: line 122, col 46, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 151, col 14, Unexpected use of '--'.
squire-raw.js: line 217, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 229, col 27, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 232, col 48, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 265, col 14, Unexpected use of '--'.
squire-raw.js: line 279, col 9, The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
squire-raw.js: line 330, col 26, Unexpected use of '--'.
squire-raw.js: line 444, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 464, col 14, Unexpected use of '--'.
squire-raw.js: line 505, col 24, Unexpected use of '--'.
squire-raw.js: line 638, col 1, Empty block.
squire-raw.js: line 790, col 14, Unexpected use of '--'.
squire-raw.js: line 844, col 45, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 1011, col 45, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 1244, col 5, The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
squire-raw.js: line 1250, col 14, Unexpected use of '--'.
squire-raw.js: line 1285, col 18, Unexpected use of '--'.
squire-raw.js: line 1390, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 1647, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 1931, col 49, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 2020, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 2072, col 19, Unexpected use of '--'.
squire-raw.js: line 2152, col 38, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 2155, col 49, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 2253, col 9, The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
squire-raw.js: line 2344, col 14, Unexpected use of '--'.
squire-raw.js: line 2476, col 14, Unexpected use of '--'.
squire-raw.js: line 2546, col 18, Unexpected use of '--'.
squire-raw.js: line 2629, col 53, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 3011, col 46, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 3125, col 43, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 3136, col 45, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 3147, col 18, Unexpected use of '--'.
squire-raw.js: line 3173, col 41, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 3179, col 36, Expected a conditional expression and instead saw an assignment.
squire-raw.js: line 21, col 10, 'navigator' is not defined.
squire-raw.js: line 1191, col 5, 'console' is not defined.
squire-raw.js: line 1443, col 5, 'top' is not defined.
squire-raw.js: line 2525, col 5, 'setTimeout' is not defined.
squire-raw.js: line 2605, col 5, 'setTimeout' is not defined.
squire-raw.js: line 2950, col 13, 'setTimeout' is not defined.
squire-raw.js: line 2998, col 13, 'setTimeout' is not defined.
squire-raw.js: line 3425, col 6, 'top' is not defined.
squire-raw.js: line 3435, col 4, 'document' is not defined.

Can you port this in Dart?

I'm working on a Dart project, and I'd love to use Squire in it. My only problem is that I need all dependencies to be Dart native (to be able to run natively up to 4x the speed of javascript on browsers supporting Dart natively). Dart syntax is not too different from javascript, very easy to convert, so I wonder if you can port this lib in Dart. Thank you.

select event is only fired when the selection spans multiple nodes

It looks like the 'select' event is only fired when a selection spans multiple nodes, while the documentation states that the select event should be fired when "[t]he user selected some text." Based on the documentation, I would expect that we would get a select event whenever the selection changes, regardless of the boundaries of the selection.

I believe these events are getting filtered out in Editor.js, line ~344-346:

    if ( anchor !== focus ) {
        this.fireEvent( 'select' );
    }

Could we use a <div> instead of <iframe> for the editor?

Hello! thanks for this great editor, I love its API.

I am working on a project where I can not use an iframe, I have to use a content editable DIV in the body of an html page.

Is it very difficult to modify Squire for this goal? Any clue?

Thanks in advance,

Best regards,

Frankai

Formatting commands throw exception when selection does not contain text nodes

When the current selection does not contain a text node (e.g., if you hit enter a few times and then select the empty lines), executing one of the formatting commands (e.g., bold()) will throw an exception.

This occurs when Squire tries to restore the selection, as startContainer will be null in _addFormat because we use the first node from TreeWalker if the startContainer is not a text node:

        // Make sure we start inside a text node.
        walker.currentNode = startContainer;
        if ( startContainer.nodeType !== TEXT_NODE ) {
            startContainer = walker.nextNode();
            startOffset = 0;
        }

Since the selection doesn't contain any text nodes, walker.nextNode() returns null here.

Unable to highlight and align text

Hey guys, I stumbled upon this bug while playing with Squire on the demo site.

Currently on http://neilj.github.io/Squire/ if you type in the following text:

Hello this is
a test message.

You can't then go and highlight the entire text then center/right align this text. "Selecting All" then doing the alignment doesn't work either.

A single line message like the message below however does work as intended.

Hello this is a test message.

defaultBlockTag doesn't use correct tag on first line

Apparently, the defaultBlockTag option only applies to lines after the first line in the editor. I can reproduce this bug consistently like so:

Step 1. Instantiate the editor:

var iframe = document.getElementbyId('editor'),
    editor = new Squire(iframe.contentDocument),
    editor.defaultBlockTag = 'P';

Step 2. Type a line, hit enter, type another line, then view HTML:

<div>This is a test.<br></div><p>This is only a test.</p>

Make Squire accessible

There are a lot of rich text editors out there, most of which are not accessible. Some have limited accessibility. As it stands now there isn't a way for a keyboard or screen reader user to navigate to the buttons controlling the formatting. Additionally, the letters being typed aren't spoken out.

Providing this functionality would put Squire in a rare atmosphere and make it a goto product for people looking to build accessible form implementations (and these are growing rapidly due to new laws and lawsuits).

do not allow me to double bind the plugin

I spent some time debugging today what ended up me using both the advanced init and basic init at the same time. I bound the plugin 2 times to the same iframe and it started doing really weird things.

[feature] Allow multiple iframes without multiple inclusions

I'm using squire in a way that loads multiple (commonly tens, possibly a hundred or so) iframes onto a single page.

To try to reduce script loads (though, I think the cached copy would be used?) I've changed the code to make a squire object instead of using a self-executing function: function Squire( doc ) { ... } instead of (function(doc) { ... }( document ) ); and then in each iframe executing new parent.Squire(document)

This required I change var RangePrototype = Range.prototype; to var RangePrototype = win.Range.prototype;

I'd like to try to further reduce duplication of function/object definitions (for example, not having a Range object per iframe). Is there an easy way to do this, or will I have to break apart things so they're attached to the main window object?

Are there any things that need their own instance, or do all functions use only what's passed to them?

No npm package

It seems like there ought to be an npm package in for this editor. Many front-end libraries use it, and support for including npm packages is improving (see systemjs for an excellent example). So would such a thing be possible? There already exists a squire package - a front-end build tool of some sort - but this could be named squire-rte, or squire-editor?

For my own purposes, I could get around this by maintaining a private package on our closed npm repository, but it would be far better for everyone if the package was public.

Replace <i> and <b> with the respective semantic elements

This editor should generate <em> and <strong> rather than <i> or <b>, as the latter aren't semantic as well as the fact that screen readers won't distinguish any difference between a text that's inside <b> tags, but will do so if it's inside a <strong>.

This topic has a great discussion around this issue.

is there any way to insert code snippet and upload images

Hi Guys,

I just found squire from keystonejs project issue
keystonejs/keystone#1112

It looks awesome.

I have been using

  1. ckeditor
  2. wysihtml5

The reason I tried is they have rails combination. But they can't fulfill my requirements easily.

  • beside html, Can insert and edit predefined code snippet
  • upload images to servers.

I like ckeditor but the complexity isn't fit for my projects.

Don't know why I haven't get into squire before until now. Probably since it has not rails gem.

Can I ask how easy to _upload images_ and _insert code snippet in squire_

Request: Change the div to p tags for real paragraphs

Right now, when starting text or pressing ENTER, Squire inserts a new div tag for a new paragraph into the contentEditable. However, the semantically appropriate tag to use for any paragraph-style block of text would be p instead of div. Also, the initial element to type into should be a p. Screen readers for the blind use semantic tags to identify page elements such as headings, paragraphs, lists, block quotes etc. While other tags Squire uses are appropriate, I think div is too generic and should be replaced by p elements where possible.

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.

quickie

$("body").append("<textarea rows='60' cols='150'>"+$("iframe")[0].contentWindow.editor.getHTML()+"</textarea>")

Better Demo

  • demo should be online, perhaps hosted here as a github page
  • demo should be a bit more user friendly, it is sparse as it is

Pasting content with multiple lines doesn't work inside blockquote

Hi, first of all squire is awesome, I saw this one bug though .
1.I inserted a blockquote in the editor.
2.I copied some content from GEdit or notepad which has more than one lines.
3.When I pasted that inside that blockquote , it gets inserted after that blockquote.
Also please see that if I paste that in an empty blockquote , the blockquote gets removed.

Thanks neilj.

Documentation: Detecting current edit state

On the Squire demo, you can click the same button (e.g. bold) to both bold AND unbold.

From the API docs I can't tell the appropriate way to detect the text state (is it bold or not?) therefore, can't match this behavior easily...

Suggesting this be added to the doc ...

Undo history got cleared after Cmd key is pressed

Javascript doesn't keep information if meta key was pressed when keyup event happens. But it does when keydown event happens.
If you undo text changes and press Cmd key there is no way to redo changes.

I've prepared a simple demo for that case

function test(event) {
  console.log(event.metaKey);
}
document.addEventListener('keydown', test);
document.addEventListener('keyup', test);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.