ralvarez
Tera Guru

find_real_file.png

 

 

This can be achieved following these simple steps:

1- Convert the textarea of the journal field into a Tinymc rich editor, by calling the same function ServiceNow uses for this purpose.

You will need an onLoad Client Script on the table you have your journal field.

To convert the textarea just execute the following function

setupTinymceField(elementId, config);

Where elementId, in the Incident form, can be one of these: "activity-stream-textarea", "activity-stream-work_notes-textarea", "activity-stream-comments-textarea"

And the standard config from ServiceNow for tinymc editors is:

{
    toolbar1: "bold,italic,underline,undo,redo,|,fontselect,fontsizeselect,table,|,forecolor,backcolor,link,unlink,|,image,media,code,|,alignleft,aligncenter,alignright,|,bullist,numlist,fullscreen",
    toolbar2: "",
    font_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;Journal=journal;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;",
    remove_script_host: true,
    language: "en",
    relative_urls: true,
    convert_urls: false,
    remove_trailing_brs: true,
    enable_media_sites: "youtube.com,player.vimeo.com,vimeo.com",
    extended_valid_elements: ",sn-mention[class|table|sysid]",
    custom_elements: "~sn-mention",
    attachmentCanVie: true,
    attachmentCanPopup: true,
    plugins: "advlist anchor autolink charmap code colorpicker directionality emoticons fullscreen hr insertdatetime lists importcss nonbreaking noneditable pagebreak print searchreplace tabfocus table template textcolor textpattern visualblocks visualchars powerpaste snLink listitem_fix align_listitems a11y_fixes readonlynoborder data_uri_sanitize enable_iframe_media",
    powerpaste_word_import: "prompt",
    powerpaste_html_import: "clean",
    automatic_uploads: false,
    allow_script_urls: false
  }

But of course, you can change it as you wish or read it from the system directly instead of hardcode it here in the Client Script.

 

2- Move outside of the control the horizontal bar that is used as decoration to help users easily identify the journal field, i.e. the yellow bar that appears in the work notes.

If we don't do anything the bar will appear on top of the control, which is not a big deal, but better if we move it a bit to the left. We can do that in different ways. Personally, I have chosen to add the following lines to the same Client Script, right after the calls to the setupTinymceField function. 

var journalDecorators = document.getElementsByClassName("sn-stream-input-decorator");
  Array.from(journalDecorators).forEach(function (el) {
    el.style.left = "-10px";
});

 

3- Add an event to the post button to clean the content of the editor once the message is posted.

If we want the control to behave as before, we will need to tell the Post button to clean the content of our Tinymc editor, as it already does with normal journal inputs. For that, in the same Client Script, we need to add an event listener to execute the following line, when we hit the button:

tinymce.get(elementId).setContent("");

This is how I've done it.

window.onload = function () {
    document.getElementsByClassName("btn btn-default pull-right activity-submit")[0].addEventListener("click", function () {
      Array.from(journalFieldsIDs).forEach(function (el){
        tinymce.get(el).setContent("");
      })
    });
}

Please, notice that we can have several journal fields on our form. This way we are cleaning all of them when pressing the Post button.

This is the last thing we need to do in our Client Script.

 

4- Use an extra journal field to wrap the content of the original field between [code] tags, so that ServiceNow can render the HTML code instead of print it in the Activity stream.

Go to the dictionary definition of your journal field and just press Insert and stay to create a similar one.

Now create a Business Rule that gets executed before update and insert when the original journal field changes. Here an example:

 

find_real_file.png

 

Then you just add a similar line like this in the script field:

current.u_work_notes ="[code]"+current.work_notes+"[/code]";

Here we are copying the content of the Tinymc editor, wrapped by [code] tags, to the journal field we have just created.

 

5- Deselect (do not remove) the default journal field from the Filter Activity and add+select your new journal field instead

For that, use the funnel button at the right of the Activity stream. Deselect the journal field and then at the bottom of the list click on "Configure available fields" to add to this list the journal field you have created before. Select it and we are done!

find_real_file.png

 

Unfortunately, I wasn't able to make it work yet without this extra field, but there may be a trick for this too. Please let me know if you find it!

 

 

Comments
Scott139
Kilo Explorer

Has anyone implemented this? Eager to know.

Ihor
Giga Expert

Hi @ralvarez , looks interesting and smart, but having issues with implementing this.

So I found through DOM tree that my input has id #activity-stream-comments-textarea.

I created onLoad script how you mentioned, but in console I can see the error that:

"ReferenceError: setupTinymceField is not defined
at onLoad_d4b68c58879674503f597b9acebb359b"

Should this function be called somehow specifically?

roberto_alvarez
Tera Contributor

You are totally right Igor, a colleague of mine found out that the Tinymce library wasn't loaded unless the form already had an HTML field.

The solution to this is pretty simple though, you just need to add this at the beginning of your client script:

 

if ($j.isFunction(this.setupTinymceField)) {
    // All is good, so you can directly call your function that transforms your journal field to TinyMCE
    ...
} else {
    var scriptFiles = [
        '/scripts/tinymce_default/tinymce.full.js'
    ];

    ScriptLoader.getScripts(scriptFiles, function() {
        // Now that we have loaded the missing script, you can call your function that transforms your journal field to TinyMCE
        ...
    });
}
ralvarez
Tera Guru

You are totally right Igor, a colleague of mine found out that the Tinymce library wasn't loaded unless the form already had an HTML field.

The solution to this is pretty simple though, you just need to add this at the beginning of your client script: 

if ($j.isFunction(this.setupTinymceField)) {
    // All is good, so you can directly call your function that transforms your journal field to TinyMCE
    ...
} else {
    var scriptFiles = [
        '/scripts/tinymce_default/tinymce.full.js'
    ];

    ScriptLoader.getScripts(scriptFiles, function() {
        // Now that we have loaded the missing script, you can call your function that transforms your journal field to TinyMCE
        ...
    });
}
Ihor
Giga Expert

Hi @ralvarez  Thank you for comments, unfortunately this approach didn't help me.

Not sure what's going on there, I even added HTML field to the form, and set Order of my onLoad script to 10k, but this didn't help).

However, your comment gave me another idea - try it with setTimeout, and this approach works. Another thing that I don't like timeouts, so if you have something else to try - please let me know.

In general, even with setTimeout it looks good, I like you work, interesting approach and looks pretty and flexible.

P.S.: Wondering will I have to fix all my notifications now to cut off [code] [/code] ?

 

This is my script now:

function onLoad() {
	setTimeout(function(){
		var config = {
			toolbar1: "bold,italic,underline,undo,redo,|,fontselect,fontsizeselect,table,|,forecolor,backcolor,link,unlink,|,image,media,code,|,alignleft,aligncenter,alignright,|,bullist,numlist,fullscreen",
			toolbar2: "",
			font_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;Journal=journal;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;",
			remove_script_host: true,
			language: "en",
			relative_urls: true,
			convert_urls: false,
			remove_trailing_brs: true,
			enable_media_sites: "youtube.com,player.vimeo.com,vimeo.com",
			extended_valid_elements: ",sn-mention[class|table|sysid]",
			custom_elements: "~sn-mention",
			attachmentCanVie: true,
			attachmentCanPopup: true,
			plugins: "advlist anchor autolink charmap code colorpicker directionality emoticons fullscreen hr insertdatetime lists importcss nonbreaking noneditable pagebreak print searchreplace tabfocus table template textcolor textpattern visualblocks visualchars powerpaste snLink listitem_fix align_listitems a11y_fixes readonlynoborder data_uri_sanitize enable_iframe_media",
			powerpaste_word_import: "prompt",
			powerpaste_html_import: "clean",
			automatic_uploads: false,
			allow_script_urls: false
		};
		var elementId = 'activity-stream-comments-textarea';

		if ($j.isFunction(this.setupTinymceField)) {
			setupTinymceField(elementId, config);
		} else {
			var scriptFiles = [
				'/scripts/tinymce_default/tinymce.full.js'
			];

			ScriptLoader.getScripts(scriptFiles, function() {
				setupTinymceField(elementId, config);
			});
		}

		window.onload = function () {
			document.getElementsByClassName("btn btn-default pull-right activity-submit")[0].addEventListener("click", function () {
				tinymce.activeEditor.setContent("");
			});
		};
	},1000);
}
ralvarez
Tera Guru

Hi Igor, this is how I would recommend building this script.

function onLoad() {
    if ($j.isFunction(this.setupTinymceField)) {
        // All is good, so you can directly call your function that transforms your journal field to TinyMCE
        transformJournalToTinyMCE();
    } else {
        var scriptFiles = [
            '/scripts/tinymce_default/tinymce.full.js'
        ];
    
        ScriptLoader.getScripts(scriptFiles, function() {
            // Now that we have loaded the missing script, you can call your function that transforms your journal field to TinyMCE
            transformJournalToTinyMCE();
        });
    }

    function transformJournalToTinyMCE() {
        // 1. Initiate variables and config
        // 2. Call setupTinymceField function
        // 3. Define window.onload function
    }
}

Just in case, be sure that your client script is not getting cached and that the browser is loading your latest modified version.

tsylte
Tera Contributor

Thank you for sharing your solution! Very interesting!

Wondering if you learned anything about how the work notes fared in notifications after you made this change? Did you need to make any changes there? 

Ihor
Giga Expert

I had to replace everywhere ${comments} to ${mail_script:comments}, to get them rendered properly. This was my script, I will share it, but I've seen couple of bugs in some emails during couple of days when I used this in prod, then I reverted back fields to original comments because I faced with issue on service portal input form. When I removed from form comment activity my comments input has gone also, so my customers (I used it for CSM cases) were not able to put comments, or if I added field to layout back - they were able to see both entries (with tags and duplicated without). So possible solution for my bug is to modify the original widget, maybe I will give it a chance later someday...


var formattedComments = formatComments(current.comments.getJournalEntry(-1));
template.print(formattedComments);

function formatComments (allComments, type){
		var styler = type =='work_note'?"background-color:LightGoldenRodYellow;": '' ;
		var sup = type =='work_note'?'Work notes':'Additional comments';
		var formattedComments = allComments.replaceAll('[code]','');
		formattedComments = formattedComments.replaceAll('[/code]','');
		var commentArray = formattedComments.split('\n\n');
		var text = '<div>';
		commentArray.forEach(function(comment){
			if(comment){
				var commentValue = comment.split('\n')[1];
				var commentTimeAndName = comment.split('(')[0];
				text+='<div><span></span><hr></div>';
				text+='<div style='+styler+'><span class="tdwrap"><strong>'+commentTimeAndName+'</strong></span><span style="float:right;"><sup> '+sup+'</sup></span></div>';
				text+='<div style='+styler+'><span><span style="word-wrap:break-word;display:block;">'+commentValue+'</span></span></div>';
			}
		});
		text+='</div>';
		return text;
}
ralvarez
Tera Guru

Indeed, notifications are to be taken into consideration when planning to use HTML in the comments, and together with that, we should consider the mobile web interface, the mobile apps, and the workspaces as well. Unfortunately, there isn't much we can do in these cases, so I would suggest to carefully analyze all that before going forward with this customization.

Solrael2021
Kilo Explorer

Did you set this as another client script? Or part of your tinyMCE enabling one?

Ihor
Giga Expert

What I lined above it's email script, which can be used in notifications to get proper comments

svanto
Tera Contributor

Has somebody managed to make this work on Tokyo?

I have the following code as a client script:

 

function onLoad() {
    var scriptFiles = [
        '/scripts/tinymce_default/tinymce.full.js'
    ];

    jslog("before");
    ScriptLoader.getScripts(scriptFiles, function() {
        transformJournalToTinyMCE();
    });

    function transformJournalToTinyMCE() {

        var config = {
            toolbar1: "bold,italic,underline,undo,redo,|,fontselect,fontsizeselect,table,|,forecolor,backcolor,link,unlink,|,image,media,code,|,alignleft,aligncenter,alignright,|,bullist,numlist,fullscreen",
            toolbar2: "",
            font_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;Journal=journal;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;",
            remove_script_host: true,
            language: "en",
            relative_urls: true,
            convert_urls: false,
            remove_trailing_brs: true,
            enable_media_sites: "youtube.com,player.vimeo.com,vimeo.com",
            extended_valid_elements: ",sn-mention[class|table|sysid]",
            custom_elements: "~sn-mention",
            attachmentCanVie: true,
            attachmentCanPopup: true,
            plugins: "advlist anchor autolink charmap code colorpicker directionality emoticons fullscreen hr insertdatetime lists importcss nonbreaking noneditable pagebreak print searchreplace tabfocus table template textcolor textpattern visualblocks visualchars powerpaste snLink listitem_fix align_listitems a11y_fixes readonlynoborder data_uri_sanitize enable_iframe_media",
            powerpaste_word_import: "prompt",
            powerpaste_html_import: "clean",
            automatic_uploads: false,
            allow_script_urls: false
        };

        var elementId = 'activity-stream-comments-textarea';
        setupTinymceField(elementId, config);

        var journalDecorators = document.getElementsByClassName("sn-stream-input-decorator");
        Array.from(journalDecorators).forEach(function(el) {
            el.style.left = "-10px";
        });
    }
    jslog("after");
}​

 

However, nothing happens to the additional comments field. I tried changing the "elemntId" to be one of the other 2 and the effect is the same.

 

The console gives no error. A few things:

1. I had to remove the $j, as the console was giving me error "$j is null"
2. I had to remove the "window.onload" part as well, because the console was erroring with "window is null"

Anyway, I don't see the above 2 points being responsible for how the field shou

ralvarez
Tera Guru

Hi @svanto, because of the mentioned console errors, it seems your client script is flagged as isolated.

 

Just make sure the option Isolate script of your Client script is deactivated. Maybe you need to add it to your form or list layout if it's not visible by default.

desertmoxie1
Tera Expert

Hola - has anyone successfully tried this in Yokohama?

User547339
Tera Contributor

Hii ,

I have tried the suggested method . But I had to have a HTML type field already present on the form . But I cannot see the toolbar even though it was configured in config

User547339_0-1756800949467.png

 

Can anyone pls help me with this

Version history
Last update:
‎06-10-2021 08:20 AM
Updated by: