Skip to content

Commit 8c3d2a9

Browse files
Josh-Cenabsmth
andauthored
Internalize execCommand() editor example (#324)
* Internalize execCommand() editor example * chore: minor edits --------- Co-authored-by: Brian Smith <[email protected]>
1 parent dc9e360 commit 8c3d2a9

File tree

4 files changed

+421
-0
lines changed

4 files changed

+421
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto

execcommand/index.html

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<script defer src="script.js"></script>
5+
<link
6+
rel="stylesheet"
7+
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
8+
<link
9+
rel="stylesheet"
10+
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
11+
<link rel="stylesheet" href="style.css" />
12+
<title>execCommands supported in your browser</title>
13+
</head>
14+
<body>
15+
<div class="container">
16+
<div class="jumbotron">
17+
<div class="container">
18+
<h2>execCommands supported in your browser</h2>
19+
<div class="row">
20+
<div class="col-md-6">
21+
The <small class="btn btn-success btn-xs">Green</small> commands
22+
are supported by your browser, where as the
23+
<small class="btn btn-error btn-xs">Grey</small> ones, these are
24+
not supported. <br />Try to select contents below and click
25+
<small class="btn btn-success btn-xs">commands</small> to execute
26+
the commands on it. <br />I use the HTML attribute
27+
<code>contenteditable=true</code> to allow modifications to the
28+
content. <code>Updated</code>: Added
29+
<a href="https://fortawesome.github.io/Font-Awesome/icons/"
30+
>font awesome icons</a
31+
>. <br />
32+
<br />Inspired by
33+
<a href="https://css-tricks.com/cut-and-copy-from-javascript/"
34+
>Cut and Copy (from JavaScript)</a
35+
>
36+
</div>
37+
<div class="col-md-6">
38+
<code>2017-06-04 updated:</code><br />
39+
<em
40+
>As pointed out by
41+
<a href="https://twitter.com/Robvanhe">@Robvanhe</a> the pen did
42+
not actually work in Safari. It was due to selection being
43+
cleared after click, so no selection to apply command existed.
44+
Fixed now. Rewritten also to vanilla javascript (no use for
45+
Angular).</em
46+
><br /><br />
47+
<code>2018-04-17 updated:</code><br />
48+
<em
49+
>Forked by Chris Mills to create a version of this demo with
50+
clean content.</em
51+
>
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
<div class="container">
57+
<div class="row">
58+
<div class="col-md-12 tags buttons"></div>
59+
</div>
60+
<div class="row" contenteditable="true">
61+
<div class="col-md-3">
62+
<img
63+
src="https://mdn.github.io/shared-assets/images/examples/mdn.svg"
64+
alt="abstract dinosaur head"
65+
class="img-responsive" />
66+
</div>
67+
<div class="col-md-9">
68+
<div class="row" contenteditable="true">
69+
<div class="col-md-12">
70+
<h3>
71+
Try to alter this text using the execCommands buttons above
72+
</h3>
73+
<p>
74+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
75+
Praesent semper in nunc at mattis. Suspendisse metus augue,
76+
pellentesque finibus luctus dictum, tempor id nunc. Phasellus
77+
semper magna ac interdum scelerisque. Vestibulum laoreet
78+
sapien a nisi ullamcorper, nec luctus neque eleifend. Aliquam
79+
vel tortor justo. Nam aliquam dapibus mi ut volutpat. Donec
80+
eros turpis, gravida et neque nec, interdum pulvinar nibh. Ut
81+
vel sodales nulla, a tempus sem. Nunc facilisis pretium
82+
aliquam. Proin nulla ante, congue at purus sit amet, commodo
83+
placerat erat. Sed malesuada eros nulla, in cursus urna
84+
elementum finibus. Suspendisse posuere purus pellentesque
85+
rutrum tempor. Nunc nec tincidunt est. Sed convallis ligula
86+
quis dui laoreet maximus. Nulla pharetra placerat quam ut
87+
rutrum. Nullam sit amet vehicula nisi.
88+
</p>
89+
</div>
90+
91+
<div class="col-md-8">
92+
<p>
93+
Pellentesque feugiat posuere fermentum. In ut varius odio, nec
94+
venenatis lorem. Pellentesque interdum odio tortor, ac
95+
hendrerit mauris venenatis nec. Maecenas finibus dapibus
96+
eleifend. Nulla rhoncus metus non nisi rutrum tempor. Cras
97+
luctus lacinia eros sed volutpat. Duis accumsan quam libero,
98+
non accumsan nisl faucibus sit amet.
99+
</p>
100+
</div>
101+
102+
<div class="col-md-4">
103+
<p>
104+
Cras tincidunt magna malesuada maximus tristique. Sed a
105+
fringilla ipsum. Nam malesuada gravida commodo. In ut
106+
convallis neque. Nulla ut consequat nisi, a imperdiet ante.
107+
</p>
108+
</div>
109+
</div>
110+
<div class="row" contenteditable="true">
111+
<div class="col-md-12">
112+
Pellentesque feugiat posuere fermentum. In ut varius odio, nec
113+
venenatis lorem. Pellentesque interdum odio tortor, ac hendrerit
114+
mauris venenatis nec. Maecenas finibus dapibus eleifend. Nulla
115+
rhoncus metus non nisi rutrum tempor. Cras luctus lacinia eros
116+
sed volutpat. Duis accumsan quam libero, non accumsan nisl
117+
faucibus sit amet.
118+
</div>
119+
</div>
120+
</div>
121+
</div>
122+
</div>
123+
</div>
124+
</body>
125+
</html>

execcommand/script.js

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
const commands = [
2+
{
3+
name: "backColor",
4+
val: "red",
5+
desc: "Changes the document background color. In styleWithCss mode, it affects the background color of the containing block instead. This requires a <color> value string to be passed in as a value argument.",
6+
},
7+
{
8+
name: "bold",
9+
icon: "bold",
10+
desc: "Toggles bold on/off for the selection or at the insertion point.",
11+
},
12+
{
13+
name: "contentReadOnly",
14+
desc: "Makes the content document either read-only or editable. This requires a boolean true/false as the value argument.",
15+
},
16+
{
17+
name: "copy",
18+
icon: "clipboard",
19+
desc: "Copies the current selection to the clipboard. Conditions of having this behavior enabled vary from one browser to another, and have evolved over time.",
20+
},
21+
{
22+
name: "createLink",
23+
val: "https://developer.mozilla.org/",
24+
icon: "link",
25+
desc: "Creates an hyperlink from the selection, but only if there is a selection. Requires a URI string as a value argument for the hyperlink's href. The URI must contain at least a single character, which may be whitespace.",
26+
},
27+
{
28+
name: "cut",
29+
icon: "scissors",
30+
desc: "Removes the current selection and copies it to the clipboard. When this behavior is enabled varies between browsers, and its conditions have evolved over time.",
31+
},
32+
{
33+
name: "decreaseFontSize",
34+
desc: "Adds a <small> tag around the selection or at the insertion point.",
35+
},
36+
{
37+
name: "defaultParagraphSeparator",
38+
desc: "Changes the paragraph separator used when new paragraphs are created in editable text regions.",
39+
},
40+
{
41+
name: "delete",
42+
icon: "scissors",
43+
desc: "Deletes the current selection.",
44+
},
45+
{
46+
name: "enableAbsolutePositionEditor",
47+
desc: "Enables or disables the grabber that allows absolutely-positioned elements to be moved around.",
48+
},
49+
{
50+
name: "enableInlineTableEditing",
51+
desc: "Enables or disables the table row/column insertion and deletion controls.",
52+
},
53+
{
54+
name: "enableObjectResizing",
55+
desc: "Enables or disables the resize handles on images, tables, and absolutely-positioned elements and other resizable objects.",
56+
},
57+
{
58+
name: "fontName",
59+
val: "'Inconsolata', monospace",
60+
desc: 'Changes the font name for the selection or at the insertion point. This requires a font name string (like "Arial") as a value argument.',
61+
},
62+
{
63+
name: "fontSize",
64+
val: "7",
65+
icon: "text-height",
66+
desc: "Changes the font size for the selection or at the insertion point. This requires an integer from 1 - 7 as a value argument.",
67+
},
68+
{
69+
name: "foreColor",
70+
val: "rgba(0,0,0,.5)",
71+
desc: "Changes a font color for the selection or at the insertion point. This requires a hexadecimal color value string as a value argument.",
72+
},
73+
{
74+
name: "formatBlock",
75+
val: "<blockquote>",
76+
desc: "Adds an HTML block-level element around the line containing the current selection, replacing the block element containing the line if one exists (in Firefox, <blockquote> is the exception — it will wrap any containing block element). Requires a tag-name string as a value argument. Virtually all block-level elements can be used.",
77+
},
78+
{
79+
name: "forwardDelete",
80+
desc: "Deletes the character ahead of the cursor's position, identical to hitting the Delete key on a Windows keyboard.",
81+
},
82+
{
83+
name: "heading",
84+
val: "h3",
85+
icon: "header",
86+
desc: 'Adds a heading element around a selection or insertion point line. Requires the tag-name string as a value argument (i.e., "H1", "H6").',
87+
},
88+
{
89+
name: "hiliteColor",
90+
val: "Orange",
91+
desc: "Changes the background color for the selection or at the insertion point. Requires a color value string as a value argument. useCSS must be true for this to function.",
92+
},
93+
{
94+
name: "increaseFontSize",
95+
desc: "Adds a <big> tag around the selection or at the insertion point.",
96+
},
97+
{
98+
name: "indent",
99+
icon: "indent",
100+
desc: "Indents the line containing the selection or insertion point. In Firefox, if the selection spans multiple lines at different levels of indentation, only the least indented lines in the selection will be indented.",
101+
},
102+
{
103+
name: "insertBrOnReturn",
104+
desc: "Controls whether the Enter key inserts a <br> element, or splits the current block element into two.",
105+
},
106+
{
107+
name: "insertHorizontalRule",
108+
desc: "Inserts a <hr> element at the insertion point, or replaces the selection with it.",
109+
},
110+
{
111+
name: "insertHTML",
112+
val: "&lt;h3&gt;Life is great!&lt;/h3&gt;",
113+
icon: "code",
114+
desc: "Inserts an HTML string at the insertion point (deletes selection). Requires a valid HTML string as a value argument.",
115+
},
116+
{
117+
name: "insertImage",
118+
val: "http://dummyimage.com/160x90",
119+
icon: "picture-o",
120+
desc: "Inserts an image at the insertion point (deletes selection). Requires a URL string for the image's src as a value argument. The requirements for this string are the same as createLink.",
121+
},
122+
{
123+
name: "insertOrderedList",
124+
icon: "list-ol",
125+
desc: "Creates a numbered ordered list for the selection or at the insertion point.",
126+
},
127+
{
128+
name: "insertUnorderedList",
129+
icon: "list-ul",
130+
desc: "Creates a bulleted unordered list for the selection or at the insertion point.",
131+
},
132+
{
133+
name: "insertParagraph",
134+
icon: "paragraph",
135+
desc: "Inserts a paragraph around the selection or the current line.",
136+
},
137+
{
138+
name: "insertText",
139+
val: new Date().toString(),
140+
icon: "file-text-o",
141+
desc: "Inserts the given plain text at the insertion point (deletes selection).",
142+
},
143+
{
144+
name: "italic",
145+
icon: "italic",
146+
desc: "Toggles italics on/off for the selection or at the insertion point.",
147+
},
148+
{
149+
name: "justifyCenter",
150+
icon: "align-center",
151+
desc: "Centers the selection or insertion point.",
152+
},
153+
{
154+
name: "justifyFull",
155+
icon: "align-justify",
156+
desc: "Justifies the selection or insertion point.",
157+
},
158+
{
159+
name: "justifyLeft",
160+
icon: "align-left",
161+
desc: "Justifies the selection or insertion point to the left.",
162+
},
163+
{
164+
name: "justifyRight",
165+
icon: "align-right",
166+
desc: "Right-justifies the selection or the insertion point.",
167+
},
168+
{
169+
name: "outdent",
170+
icon: "outdent",
171+
desc: "Outdents the line containing the selection or insertion point.",
172+
},
173+
{
174+
name: "paste",
175+
icon: "clipboard",
176+
desc: "Pastes the clipboard contents at the insertion point (replaces current selection). Disabled for web content.",
177+
},
178+
{
179+
name: "redo",
180+
icon: "repeat",
181+
desc: "Redoes the previous undo command.",
182+
},
183+
{
184+
name: "removeFormat",
185+
desc: "Removes all formatting from the current selection.",
186+
},
187+
{
188+
name: "selectAll",
189+
desc: "Selects all of the content of the editable region.",
190+
},
191+
{
192+
name: "strikeThrough",
193+
icon: "strikethrough",
194+
desc: "Toggles strikethrough on/off for the selection or at the insertion point.",
195+
},
196+
{
197+
name: "subscript",
198+
icon: "subscript",
199+
desc: "Toggles subscript on/off for the selection or at the insertion point.",
200+
},
201+
{
202+
name: "superscript",
203+
icon: "superscript",
204+
desc: "Toggles superscript on/off for the selection or at the insertion point.",
205+
},
206+
{
207+
name: "underline",
208+
icon: "underline",
209+
desc: "Toggles underline on/off for the selection or at the insertion point.",
210+
},
211+
{
212+
name: "undo",
213+
icon: "undo",
214+
desc: "Undoes the last executed command.",
215+
},
216+
{
217+
name: "unlink",
218+
icon: "chain-broken",
219+
desc: "Removes the anchor tag from a selected anchor link.",
220+
},
221+
{
222+
name: "useCSS",
223+
desc: "Toggles the use of HTML tags or CSS for the generated markup. Requires a boolean true/false as a value argument. NOTE: This argument is logically backwards (i.e., use false to use CSS, true to use HTML). This has been deprecated in favor of styleWithCSS.",
224+
},
225+
{
226+
name: "styleWithCSS",
227+
desc: "Replaces the useCSS command. true modifies/generates style attributes in markup, false generates presentational elements.",
228+
},
229+
{
230+
name: "AutoUrlDetect",
231+
desc: "Changes the browser auto-link behavior.",
232+
},
233+
];
234+
235+
const buttons = document.querySelector(".buttons");
236+
237+
commands.forEach((command) => {
238+
const button = document.createElement("button");
239+
const supported = document.queryCommandSupported(command.name);
240+
button.className = `btn btn-xs btn-${supported ? "success" : "error"}`;
241+
242+
button.addEventListener("mousedown", (e) => e.preventDefault());
243+
if (supported) {
244+
button.addEventListener("click", () => {
245+
const val = command.val
246+
? prompt(`Value for ${command.name}?`, command.val) || ""
247+
: "";
248+
document.execCommand(command.name, false, val);
249+
});
250+
} else {
251+
button.setAttribute("disabled", "true");
252+
}
253+
button.innerHTML = `<i class="${
254+
command.icon ? `fa fa-${command.icon}` : ""
255+
}"></i> ${command.name}`;
256+
buttons.appendChild(button);
257+
});

0 commit comments

Comments
 (0)