Skip to content

Commit 9de7639

Browse files
authored
Tinymce journal editor modal bookmarklet (#1938)
* Create Open tinymce editor in modal for journal fields.js * Create README.md * Update README.md * Add files via upload * Update README.md
1 parent 353ae10 commit 9de7639

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
javascript:!function(){const e={attachmentCanPopup:"true",attachmentCanView:"true",canReadDbImage:!0,canReadDbVideo:!0,allowedExtensions:"",videoExtensions:"webm|mov|swf|avi|mp4",convert_urls:!1,custom_elements:"sn-toc,~sn-mention",link_default_target:"",enable_media_sites:"youtube.com,player.vimeo.com,vimeo.com,players.brightcove.net,brightcove.net",extended_valid_elements:"now-illustration-custom[token-id|src|alt|width|height],sn-toc,sn-mention[class|table|sysid]",font_family_formats:"Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;",language:"en",plugins:"powerpaste accordion advlist align_listitems anchor autolink charmap codemirror directionality editimage emoticons fullscreen help image insertdatetime link lists media nonbreaking pagebreak preview readonlynoborder searchreplace table visualblocks visualchars",powerpaste_html_import:"clean",powerpaste_word_import:"prompt",powerpaste_clean_filtered_inline_elements:"strong, b",relative_urls:!0,remove_script_host:!0,contextmenu:"link image table",toolbar:["bold italic underline undo redo | fontfamily fontsize table | forecolor backcolor link unlink | image media code | alignleft aligncenter alignright | bullist numlist fullscreen"],menubar:!1,menu:{file:{title:"File",items:"newdocument restoredraft | preview | export print | deleteallconversations"},edit:{title:"Edit",items:"undo redo | cut copy paste pastetext | selectall | searchreplace"},view:{title:"View",items:"code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments"},insert:{title:"Insert",items:"image link media addcomment pageembed template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime"},format:{title:"Format",items:"bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat"},tools:{title:"Tools",items:"spellchecker spellcheckerlanguage | a11ycheck code wordcount"},table:{title:"Table",items:"inserttable | cell row column | advtablesort | tableprops deletetable"},help:{title:"Help",items:"help"}},style_formats:[{title:"Headings",items:[{title:"Heading 1",format:"h1"},{title:"Heading 2",format:"h2"},{title:"Heading 3",format:"h3"},{title:"Heading 4",format:"h4"},{title:"Heading 5",format:"h5"},{title:"Heading 6",format:"h6"}]},{title:"Inline",items:[{title:"Bold",format:"bold"},{title:"Italic",format:"italic"},{title:"Underline",format:"underline"},{title:"Strikethrough",format:"strikethrough"},{title:"Superscript",format:"superscript"},{title:"Subscript",format:"subscript"},{title:"Code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Align",items:[{title:"Left",format:"alignleft"},{title:"Center",format:"aligncenter"},{title:"Right",format:"alignright"},{title:"Justify",format:"alignjustify"}]}],text_patterns:!1,promotion:!1,help_tabs:["shortcuts","keyboardnav","versions"],automatic_uploads:!1,allow_script_urls:!1},t=window.gsft_main?window.gsft_main.document:top.document;if(t.getElementById("drc-overlay"))return;(i=>{const a=()=>{if(void 0===window.gsft_main.setupTinymceField){const t=setInterval((()=>{const i=window.gsft_main.setupTinymceField;"function"==typeof i&&(clearInterval(t),i("iidee",e))}),100)}else window.gsft_main.setupTinymceField("iidee",e)};if(t.getElementById("tinymcedeps"))a();else{const e=t.createElement("script");e.id="tinymcedeps",e.src="/scripts/tinymce_default/js_includes_tinymce.jsx?sysparm_substitute=false",e.onload=()=>{a()},window.gsft_main.document.head.appendChild(e)}const n=t.createElement("div");n.style.overflowY="auto",n.style.overflowX="hidden",n.style.maxHeight="60vh";const l=t.createElement("textarea");l.id="iidee";t.createElement("div");const o=window.gsft_main.g_form,s=o.elements.filter((e=>"journal_input"===e.type));n.appendChild(l);const r=t.createElement("div");s.forEach((e=>{const i=t.createElement("button");i.textContent=e.fieldName,r.appendChild(i),i.onclick=()=>{const t=window.gsft_main.tinymce.get("iidee").getContent();o.setValue(e.fieldName,`[code]${t}[/code]`)}})),n.appendChild(r),i.appendChild(n)})((()=>{const e=t.createElement("div");e.id="drc-overlay",e.style.position="fixed",e.style.top=0,e.style.left=0,e.style.width="100vw",e.style.height="100vh",e.style.backgroundColor="rgba(0, 0, 0, 0.6)",e.style.zIndex=9999,e.style.display="flex",e.style.justifyContent="center",e.style.alignItems="center";const i=t.createElement("div");i.id="modal-container",i.style.background="#fff",i.style.padding="20px",i.style.borderRadius="8px",i.style.boxShadow="0 0 10px rgba(0,0,0,0.3)",i.style.maxWidth="1000px",i.style.textAlign="center",i.style.maxHeight="70vh",i.style.position="absolute";const a=t.createElement("div");a.style.cursor="move",a.style.height="20px",a.style.marginBottom="10px",a.style.background="rgba(100, 100, 100, 0.3)",a.style.borderRadius="8px";const n=((e,i)=>{let a=!1,n=0,l=0;const o=e=>{a&&(i.style.left=e.clientX-n+"px",i.style.top=e.clientY-l+"px")},s=()=>{a=!1,t.body.style.userSelect=""};e.addEventListener("mousedown",(e=>{a=!0,n=e.clientX-i.offsetLeft,l=e.clientY-i.offsetTop,t.body.style.userSelect="none"})),t.addEventListener("mousemove",o),t.addEventListener("mouseup",s);const r=[];return r.push((()=>{t.removeEventListener("mousemove",o),t.removeEventListener("mouseup",s)})),r})(a,i);i.append(a),e.appendChild(i),t.body.appendChild(e);return e.addEventListener("click",(a=>{i.contains(a.target)||(t.body.removeChild(e),n.forEach((e=>e())))})),i})())}();
2+
3+
/*
4+
(function () {
5+
const tinyMceConfig = {
6+
attachmentCanPopup: "true",
7+
attachmentCanView: "true",
8+
canReadDbImage: true,
9+
canReadDbVideo: true,
10+
allowedExtensions: "",
11+
videoExtensions: "webm|mov|swf|avi|mp4",
12+
convert_urls: false,
13+
custom_elements: "sn-toc,~sn-mention",
14+
link_default_target: "",
15+
enable_media_sites: "youtube.com,player.vimeo.com,vimeo.com,players.brightcove.net,brightcove.net",
16+
extended_valid_elements: "now-illustration-custom[token-id|src|alt|width|height],sn-toc,sn-mention[class|table|sysid]",
17+
font_family_formats: "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;",
18+
language: "en",
19+
plugins: "powerpaste accordion advlist align_listitems anchor autolink charmap codemirror directionality editimage emoticons fullscreen help image insertdatetime link lists media nonbreaking pagebreak preview readonlynoborder searchreplace table visualblocks visualchars",
20+
powerpaste_html_import: "clean",
21+
powerpaste_word_import: "prompt",
22+
powerpaste_clean_filtered_inline_elements: "strong, b",
23+
relative_urls: true,
24+
remove_script_host: true,
25+
contextmenu: "link image table",
26+
toolbar: [
27+
"bold italic underline undo redo | fontfamily fontsize table | forecolor backcolor link unlink | image media code | alignleft aligncenter alignright | bullist numlist fullscreen"
28+
],
29+
menubar: false,
30+
menu: {
31+
file: { title: "File", items: "newdocument restoredraft | preview | export print | deleteallconversations" },
32+
edit: { title: "Edit", items: "undo redo | cut copy paste pastetext | selectall | searchreplace" },
33+
view: { title: "View", items: "code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments" },
34+
insert: { title: "Insert", items: "image link media addcomment pageembed template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime" },
35+
format: { title: "Format", items: "bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat" },
36+
tools: { title: "Tools", items: "spellchecker spellcheckerlanguage | a11ycheck code wordcount" },
37+
table: { title: "Table", items: "inserttable | cell row column | advtablesort | tableprops deletetable" },
38+
help: { title: "Help", items: "help" }
39+
},
40+
style_formats: [
41+
{
42+
title: "Headings",
43+
items: [
44+
{ title: "Heading 1", format: "h1" },
45+
{ title: "Heading 2", format: "h2" },
46+
{ title: "Heading 3", format: "h3" },
47+
{ title: "Heading 4", format: "h4" },
48+
{ title: "Heading 5", format: "h5" },
49+
{ title: "Heading 6", format: "h6" }
50+
]
51+
},
52+
{
53+
title: "Inline",
54+
items: [
55+
{ title: "Bold", format: "bold" },
56+
{ title: "Italic", format: "italic" },
57+
{ title: "Underline", format: "underline" },
58+
{ title: "Strikethrough", format: "strikethrough" },
59+
{ title: "Superscript", format: "superscript" },
60+
{ title: "Subscript", format: "subscript" },
61+
{ title: "Code", format: "code" }
62+
]
63+
},
64+
{
65+
title: "Blocks",
66+
items: [
67+
{ title: "Paragraph", format: "p" },
68+
{ title: "Blockquote", format: "blockquote" },
69+
{ title: "Div", format: "div" },
70+
{ title: "Pre", format: "pre" }
71+
]
72+
},
73+
{
74+
title: "Align",
75+
items: [
76+
{ title: "Left", format: "alignleft" },
77+
{ title: "Center", format: "aligncenter" },
78+
{ title: "Right", format: "alignright" },
79+
{ title: "Justify", format: "alignjustify" }
80+
]
81+
}
82+
],
83+
text_patterns: false,
84+
promotion: false,
85+
help_tabs: ["shortcuts", "keyboardnav", "versions"],
86+
automatic_uploads: false,
87+
allow_script_urls: false
88+
};
89+
90+
const makeModalMovable = (headerElement, modalElement) => {
91+
let isDragging = false,
92+
offsetX = 0,
93+
offsetY = 0;
94+
95+
const mouseMoveHandler = (event) => {
96+
if (isDragging) {
97+
modalElement.style.left = `${event.clientX - offsetX}px`
98+
modalElement.style.top = `${event.clientY - offsetY}px`
99+
}
100+
}
101+
const mouseUpHandler = () => {
102+
isDragging = false;
103+
document.body.style.userSelect = "";
104+
};
105+
const mouseDownHandler = (e) => {
106+
isDragging = true;
107+
offsetX = e.clientX - modalElement.offsetLeft;
108+
offsetY = e.clientY - modalElement.offsetTop;
109+
document.body.style.userSelect = "none";
110+
};
111+
112+
headerElement.addEventListener("mousedown", mouseDownHandler);
113+
document.addEventListener("mousemove", mouseMoveHandler);
114+
document.addEventListener("mouseup", mouseUpHandler);
115+
116+
const cleanupHandlers = [];
117+
cleanupHandlers.push(() => {
118+
document.removeEventListener('mousemove', mouseMoveHandler);
119+
document.removeEventListener('mouseup', mouseUpHandler);
120+
});
121+
122+
return cleanupHandlers;
123+
}
124+
125+
const createOverlay = () => {
126+
const overlay = document.createElement("div")
127+
overlay.id = "drc-overlay";
128+
overlay.style.position = "fixed";
129+
overlay.style.top = 0;
130+
overlay.style.left = 0;
131+
overlay.style.width = "100vw";
132+
overlay.style.height = "100vh";
133+
overlay.style.backgroundColor = "rgba(0, 0, 0, 0.6)";
134+
overlay.style.zIndex = 9999;
135+
overlay.style.display = "flex";
136+
overlay.style.justifyContent = "center";
137+
overlay.style.alignItems = "center";
138+
139+
const modalContainer = document.createElement("div");
140+
modalContainer.id = "modal-container";
141+
modalContainer.style.background = "#fff";
142+
modalContainer.style.padding = "20px";
143+
modalContainer.style.borderRadius = "8px";
144+
modalContainer.style.boxShadow = "0 0 10px rgba(0,0,0,0.3)";
145+
modalContainer.style.maxWidth = "1000px";
146+
modalContainer.style.textAlign = "center";
147+
modalContainer.style.maxHeight = "70vh";
148+
modalContainer.style.position = 'absolute';
149+
150+
const modalHeader = document.createElement("div");
151+
modalHeader.style.cursor = "move";
152+
modalHeader.style.height = "20px";
153+
modalHeader.style.marginBottom = "10px";
154+
modalHeader.style.background = "rgba(100, 100, 100, 0.3)";
155+
modalHeader.style.borderRadius = "8px";
156+
157+
const cleanupHandlers = makeModalMovable(modalHeader, modalContainer);
158+
modalContainer.append(modalHeader)
159+
overlay.appendChild(modalContainer);
160+
document.body.appendChild(overlay);
161+
162+
const onOverlayClick = (event) => {
163+
if (!modalContainer.contains(event.target)) {
164+
document.body.removeChild(overlay);
165+
cleanupHandlers.forEach(fn => fn());
166+
}
167+
}
168+
overlay.addEventListener("click", onOverlayClick);
169+
170+
return modalContainer;
171+
}
172+
173+
const addModalContent = (modalContainer) => {
174+
const createEditor = () => {
175+
if (typeof window.gsft_main.setupTinymceField === 'undefined') {
176+
const interval = setInterval(() => {
177+
const fn = window.gsft_main.setupTinymceField;
178+
if (typeof fn === 'function') {
179+
clearInterval(interval);
180+
fn("iidee", tinyMceConfig);
181+
}
182+
}, 100);
183+
} else {
184+
window.gsft_main.setupTinymceField("iidee", tinyMceConfig);
185+
}
186+
187+
}
188+
if (!document.getElementById("tinymcedeps")) {
189+
const tinymceScript = document.createElement('script');
190+
tinymceScript.id = "tinymcedeps"
191+
tinymceScript.src = '/scripts/tinymce_default/js_includes_tinymce.jsx?sysparm_substitute=false';
192+
tinymceScript.onload = () => {
193+
createEditor()
194+
};
195+
window.gsft_main.document.head.appendChild(tinymceScript)
196+
} else {
197+
createEditor()
198+
}
199+
200+
const modalContent = document.createElement("div");
201+
modalContent.style.overflowY = "auto";
202+
modalContent.style.overflowX = "hidden";
203+
modalContent.style.maxHeight = "60vh";
204+
const textArea = document.createElement("textarea");
205+
textArea.id = "iidee";
206+
const buttons = document.createElement("div");
207+
const g_form = window.gsft_main.g_form;
208+
const journalInputs = g_form.elements.filter(e => e.type === "journal_input");
209+
210+
modalContent.appendChild(textArea)
211+
const buttonContainer = document.createElement("div");
212+
journalInputs.forEach(journalInput => {
213+
const button = document.createElement("button");
214+
button.textContent = journalInput.fieldName;
215+
buttonContainer.appendChild(button)
216+
button.onclick = () => {
217+
const content = window.gsft_main.tinymce.get('iidee').getContent();
218+
g_form.setValue(journalInput.fieldName, `[code]${content}[/code]`)
219+
}
220+
});
221+
modalContent.appendChild(buttonContainer)
222+
modalContainer.appendChild(modalContent)
223+
}
224+
const document = window.gsft_main ? window.gsft_main.document : top.document;
225+
226+
if (document.getElementById("drc-overlay")) return;
227+
228+
const modalContainer = createOverlay();
229+
addModalContent(modalContainer);
230+
})();
231+
/*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# tinymce journal editor Bookmarklet Modal
2+
3+
This script is a bookmarklet that injects a draggable modal into a form with a tiny mce editor and buttons to insert the html to the journal fields on the form.
4+
5+
The dependency for tinymce is loaded from the instance itself and a html field does not need to be present on the form.
6+
7+
---
8+
9+
## 📸 Screenshots
10+
11+
### Modal Overview
12+
![Modal Overview](image.png)
13+
14+
---
15+
16+
## 🔧 How to Use
17+
18+
1. **Copy the minified script** on the first line of the *Open tinymce editor in modal for journal fields.js* file
19+
2. **Create a bookmark** in your browser.
20+
3. Paste the script into the bookmark's URL field.
21+
4. Navigate to a ServiceNow form and click the bookmarklet.
22+
5. Input formatted text into editor and click a button from the bottom to set the html to the corresponding journal field with the [code] tags
172 KB
Loading

0 commit comments

Comments
 (0)