Skip to content

Instantly share code, notes, and snippets.

@thisnameissoclever
Last active April 6, 2024 08:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thisnameissoclever/03cb5aa05a12d7cec8fb4e979fc47b35 to your computer and use it in GitHub Desktop.
Save thisnameissoclever/03cb5aa05a12d7cec8fb4e979fc47b35 to your computer and use it in GitHub Desktop.
Get ServiceNow Journal Entries, optionally parse and convert HTML control-characters and line-breaks, and return an array of the last N journal entries.
/**
* Get the journal entries from a given record, and optionally parse and convert line breaks and
* HTML and wokkas (< and >) to HTML (<br />\n and HTML-ized character codes).
* @param {GlideRecord} current - A GlideRecord object positioned to the record you want to get the
* journal entries from.
* @param {String} journalFieldName - The journal field name (e.g. "work_notes", "comments",
* "comments_and_work_notes", etc.).
* @param {Boolean} [convertLineBreaksToHTML=false] - Set this to true, to convert line-breaks
* (\r\n) to HTML (<br />\n).
* @param {Boolean} [convertWokkasToHTML=false] - Set this to true, to convert wokkas ("<" and ">")
* to HTML ("&#[char_code];").
* @param {Number} [getLastNEntries=-1] - Specify the number of journal entries you'd like to
* retrieve. If not specified, the default is -1.
* Set this to -1 (or leave undefined) to retrieve ALL entries from the specified journal field.
* @param {function} [filterFunction=] - Optionally, specify a function that can be used to filter
* the results. This function will be called for each individual journal entry AFTER any other
* processing (such as HTML conversion). The function must accept one argument (the individual
* journal entry, as a string) and return the boolean value true if the journal entry passed
* into it matches your filter.
* For example:
* function checkJournalEntryContainsString(journalEntry) {
* return journalEntry.includes('SOME_STRING') || journalEntry.length < 100;
* }
* Passing the above checkJournalEntryContainsString function into getJournalEntries() as the last
* argument will cause getJournalEntries() to ONLY include journal entries that contain the
* text "SOME_STRING", *or* which are less than 100 characters in length. NOTE: When PASSING a
* function into another function as an argument, just pass it in by name. Do NOT include the
* "()" after the function name.
* If you DON'T want to filter the returned results, then simply do not specify this argument.
* @returns {String[]} - An array of journal entries from the specified journal field on the
* specified record, with the specified parsing done.
*
* @example
* var arrWorkNotes;
* var grInc = new GlideRecord('incident');
* grInc.setLimit(1);
* grInc.query();
* if (grInc.next()) {
* arrWorkNotes = getJournalEntries(
* grInc,
* 'work_notes',
* true,
* true,
* 2
* );
* gs.info(JSON.stringify(arrWorkNotes, null, 2));
* }
* //Output:
* //['2022-08-16 10:31:11 - Admin (Work notes)\nThis is an example journal entry <br />\n<br />\nwith a lot of<br />\nextraneous<br />\n<br />\n<br />\nline breaks.', '2022-08-16 10:30:58 - Admin (Work notes)\nThis is an example journal entry with <br />\nline breaks, and &#60;HTML wokkas that&#62; need to be converted to HTML.'];
*
* //Example 2:
* function myFilterFunction(strJournalEntry) {
* //Filter results: only include entries including this text, or less than 100 chars long
* return (
* strJournalEntry.includes('Some text to check for') ||
* strJournalEntry.length < 100
* );
* }
*
* var arrCommentsAndWorknotes = getJournalEntries(
* current,
* 'comments_and_work_notes',
* false,
* false,
* -1, //Get ALL journal entries
* myFilterFunction
* );
*/
function getJournalEntries(
current,
journalFieldName,
convertLineBreaksToHTML,
convertWokkasToHTML,
getLastNEntries,
filterFunction
) {
//Hoist declarations
var arrJournalEntries, strJournalEntries;
//Init default values for optional params
convertLineBreaksToHTML = (typeof convertLineBreaksToHTML == 'undefined') ? false : convertLineBreaksToHTML;
convertWokkasToHTML = (typeof convertWokkasToHTML == 'undefined') ? false : convertWokkasToHTML;
getLastNEntries = (typeof getLastNEntries == 'undefined') ? -1 : parseInt(getLastNEntries);
//Get all journal entries from the specified field as an array of strings.
strJournalEntries = current[journalFieldName] //Chain-call incoming...
//Arg -1 gets all journal entries in a string, delimited by "\n\n"
.getJournalEntry(getLastNEntries)
//Explicitly cast value to string to avoid unexpected type-coercion
.toString()
//Trim trailing whitespace (which would otherwise result is a trailing empty element)
.trim();
if (convertWokkasToHTML) {
if (strJournalEntries.includes('<') || strJournalEntries.includes('>')) {
strJournalEntries = strJournalEntries.replaceAll(
'<',
('&#' + '<'.charCodeAt(0) + ';')
);
strJournalEntries = strJournalEntries.replaceAll(
'>',
('&#' + '>'.charCodeAt(0) + ';')
);
}
}
if (convertLineBreaksToHTML) {
//Replace embedded returns in journal entry with HTML break if necessary
strJournalEntries = strJournalEntries.replaceAll(
'\r\n', (convertLineBreaksToHTML ? '<br />\n' : '\r\n')
);
}
//Split the string on double-new-line-character to get unique journal entries
arrJournalEntries = strJournalEntries.split('\n\n');
/*
NOTE: Splitting on the double-new-line-character may seem risky. What if a user creates
a journal entry with a double-return in it, for example? -- However, this is not the
case. New-lines inside of journal entries are converted to "\r\n" for each new line.
For example, the following journal entry:
"This
is a test"
Will be converted to:
"This\r\n\r\nis a test"
Note that each line-return in the original entry is converted to "\r\n". Therefore, when
splitting on "\n\n", we should expect no conflict.
*/
//Fail early: If no journal entries are found, bail out here.
if (!arrJournalEntries || arrJournalEntries.length < 1) {
return []; //No journal entries found. Halt and return, but throw no error or warning.
}
//If filterFunction arg is provided, filter journal entries using that function.
if (typeof filterFunction == 'function') {
arrJournalEntries = arrJournalEntries.filter(filterFunction);
}
return arrJournalEntries;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment