All JavaScript snippets provided on this page are designed to work with the eLearning Magic Toolkit plugin - they will not work on their own with Articulate Storyline 360.
JavaScript To Transfer Custom Variables From Storyline Into WordPress
let player = GetPlayer(); player.SetVar("SL_ID",document.title); let fields = { STORYLINE_VARIABLE_NAME: '', }; let data = {}; handleForm(data, fields, player); } function handleForm(data, fields, player) { for (let [key, val] of Object.entries(fields)) { let value = player.GetVar(key); if( value ) { data[key] = value; } } data.action = 'save_user_data_json'; data.title = document.title; var pathArray = window.location.pathname.split('/'); data.sl_name = pathArray[3]; let url = window.location.origin + '/wp-admin/admin-ajax.php'; fetch(url, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Cache-Control': 'no-cache', }, body: new URLSearchParams( data ) }).then(response => response.json()) .then(response => console.log(response.message)) .catch(err => console.log(err));
JavaScript To Transfer Stored User Variables From WordPress Into Storyline
var sluser = window.parent.userCode; fetch ('/wp-content/uploads/jsons/results_' + sluser + '.json'). then (response => { return response.json (); }).then (data => { var player = GetPlayer(); player.SetVar("STORYLINE_VARIABLE_NAME", data.SL##_VARIABLENAME); }). catch (err => { console.log ("No Data Available.") });
Shortcode For Displaying User Variables On Any WordPress Post/Page
Make sure to remove the spaces before and after the opening and closing square brackets:
[ storyline_user_data options="VARIABLE-NAME" ]
Optional: Add an additional user=”USERNAME” value to your shortcode if you wish to display the stored variable for a particular user.
E.g.
[ storyline_user_data user="johnsmith" options="VARIABLE-NAME" ]
Shortcode For Creating A Leaderboard Using Any Stored Numeric Variable
[ sl_leaderboard variable="VARIABLE-NAME" ]
JavaScript To Send And Receive A Single Question Response From The Create Chat Completion API (ChatGPT)
NOTE FOR TIN CANNY REPORTING PLUGIN USERS – Replace the word ‘parent’ with ‘window.top’ in all places in the script below if you intend to upload your content using the Tin Canny uploader, if you find the script below is not working for your project:
var player = GetPlayer(); var prompt_text = player.GetVar("StorylineTextVariable"); var messages = [] var system_message = { role: "system", content: "You are a helpful and knowledgeable AI chatbot." }; var user_prompt00 = {role: "user", content: "Please answer the following question: " + prompt_text }; messages.push(system_message); messages.push(user_prompt00); var sendData = { 'nonce': parent.storylineMagicNonce, 'value': JSON.stringify( messages ), 'api': 'chatCompletion', 'jsonresponse': 'false', 'contextfile': 'ABC123', }; //The contextfile line above is OPTIONAL. Remove this line entirely if you don't want to use eLM Toolkit's Context Document functionality. sendData = JSON.stringify( sendData ); const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); myHeaders.append("X-WP-Nonce", parent.storylineMagicRestNonce); async function openai_req() { fetch(parent.storylineMagicEndpoint, { method:'POST', headers: myHeaders, body: sendData }) .then(res => res.json()) .then(data => { if ( Object.prototype.hasOwnProperty.call(data.data, 'data') ) { var gpt_content = data.data.data.choices[0].message.content; gpt_content = gpt_content.trim(); player.SetVar("StorylineAnswerTextVariable",gpt_content); }else{ console.error('Error fetching data:', error); } }) .catch(error => { console.error('Error fetching data:', error); }) }; openai_req();
Note: Context Document prompting requires a minimum of eLearning Magic Toolkit version 2.3. Inclusion of a context file is completely optional within your prompt, simply remove the line entirely from the var sendData section if not needed.
JavaScript To Continue Conversation With The Create Chat Completion API (ChatGPT) Using Previous Messages Thread
Store and receive each typed user request and ChatGPT API response as a variable in your SL360 project, and load them back into the next prompt request to the API by adding additional User and Assistant messages like so:
var player = GetPlayer(); var prompt_text_01 = player.GetVar("StorylineTextVariable01"); var gpt_response_01 = player.GetVar("StorylineAnswerVariable01"); var prompt_text_02 = player.GetVar("StorylineTextVariable02"); var gpt_response_02 = player.GetVar("StorylineAnswerVariable02"); var prompt_text_03 = player.GetVar("StorylineTextVariable03"); var messages = [] var system_message = { role: "system", content: "You are a helpful and knowledgeable AI chatbot." }; var user_prompt01 = {role: "user", content: "Please answer the following question: " + prompt_text_01 }; var gpt_response01 = {role: "assistant", content: `${gpt_response_01}`} var user_prompt02 = {role: "user", content: `${prompt_text_02}` }; var gpt_response02 = {role: "assistant", content: `${gpt_response_02}`} var user_prompt03 = {role: "user", content: `${prompt_text_03}` }; messages.push(system_message); messages.push(user_prompt01); messages.push(gpt_response01); messages.push(user_prompt02); messages.push(gpt_response02); messages.push(user_prompt03); var sendData = { 'nonce': parent.storylineMagicNonce, 'value': JSON.stringify( messages ), 'api': 'chatCompletion', 'jsonresponse': 'false', 'contextfile': 'ABC123', }; //The contextfile line above is OPTIONAL. Remove this line entirely if you don't want to use eLM Toolkit's Context Document functionality. sendData = JSON.stringify( sendData ); const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); myHeaders.append("X-WP-Nonce", parent.storylineMagicRestNonce); async function openai_req() { fetch(parent.storylineMagicEndpoint, { method:'POST', headers: myHeaders, body: sendData }) .then(res => res.json()) .then(data => { if ( Object.prototype.hasOwnProperty.call(data.data, 'data') ) { var gpt_content = data.data.data.choices[0].message.content; gpt_content = gpt_content.trim(); player.SetVar("StorylineAnswerVariable03",gpt_content); }else{ console.error('Error fetching data:', error); } }) .catch(error => { console.error('Error fetching data:', error); }) }; openai_req();
Generate An Image Using The Create Image API (Dall-E)
Important – As of version release 2.3.2, all image generation requests must include a ‘size’ value within the sendData block. Refer to the OpenAI website for what sizes are available for each model (and their associated costs).
Store and receive each typed user request and ChatGPT API response as a variable in your SL360 project, and load them back into the next prompt request to the API by adding additional User and Assistant messages like so:
var player = GetPlayer(); const userpromptvalue = "Create a photographic image of: " + player.GetVar('StorylineTextVariable'); var sendData = { 'nonce': parent.storylineMagicNonce, 'value': userpromptvalue, 'api': 'imageGeneration', 'size': '1024x1024' }; sendData = JSON.stringify( sendData ); const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); myHeaders.append("X-WP-Nonce", parent.storylineMagicRestNonce); async function openai_req() { fetch(parent.storylineMagicEndpoint, { method:'POST', headers: myHeaders, body: sendData }) .then(res => res.json()) .then(data => { if ( Object.prototype.hasOwnProperty.call(data.data, 'data') && Object.prototype.hasOwnProperty.call(data.data.data, 'data') ) { var apiReturnedImage = data.data.data.data[0].url; apiReturnedImage = apiReturnedImage.trim(); player.SetVar("StorylineVariableToStoreImgURL",apiReturnedImage); }else{ console.error('Error fetching data:', error); } }) .catch(error => { console.error('Error fetching data:', error); }) }; openai_req();
JavaScript To Generate A Natural Voice Audio Track Using ElevenLabs
var script = getVar("MYTEXT"); var messages = [] var sendData = { 'nonce': parent.storylineMagicNonce, 'api': 'textToSpeech', 'modelId': 'eleven_multilingual_v2', 'text': script, 'id': 'bVMeCyTHy58xNoL34h3p' }; //The voice id can be found and chosen from elevenLabs.io sendData = JSON.stringify(sendData); const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); myHeaders.append("X-WP-Nonce", parent.storylineMagicRestNonce); async function elevenlabs_req() { try { console.log('Sending Request To ElevenLabs...'); const response = await fetch(parent.storylineMagicEndpointElevenLabs, { method:'POST', headers: myHeaders, body: sendData }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } else { console.log('ElevenLabs Response Returned.'); const data = await response.json(); const base64Audio = data.audio; const audioBytes = atob(base64Audio); const audioArray = new Uint8Array(audioBytes.length); for (let i = 0; i < audioBytes.length; i++) { audioArray[i] = audioBytes.charCodeAt(i); } const audioBlob = new Blob([audioArray], { type: 'audio/mpeg' }); const audiodataUrl = URL.createObjectURL(audioBlob); // Store audio data URL for use by Storyline later setVar("ElevenLabsAudioURL", audiodataUrl); // Create a new audio object and set its source to the Object URL const audio = new Audio(audiodataUrl); // Play the audio console.log("Audio is playing"); audio.play(); } } catch (error) { console.error('An error occurred:', error); } } elevenlabs_req();
JavaScript To Generate An Image Using The Stability AI Platform (With or Without Background Transparency)
let userTypedValue = getVar("UserRequest"); const imageRatioSetting = "16:9"; //Choices are 16:9, 1:1, 21:9, 2:3, 3:2, 4:5, 5:4, 9:16, 9:21 const removeBackground = "NO"; // YES or NO let sendData = { 'nonce': parent.storylineMagicNonce, 'prompt': UserRequest, 'aspect_ratio': imageRatioSetting, 'remove_background': removeBackground }; sendData = JSON.stringify(sendData); const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); myHeaders.append("X-WP-Nonce", parent.storylineMagicRestNonce); async function stability_req() { try { const response = await fetch(parent.storylineMagicEndpointStability, { method: 'POST', headers: myHeaders, body: sendData }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); //console.log('Image URL:', data); setVar("ReturnedImageURL", data); } catch (error) { console.error('Error fetching data:', error); } } stability_req();
Store Values To A Custom Database for Storyline (v2.5 update – Example contains 4 columns)
var db_name = "MY_STORYLINE_DB"; var data1 = getVar("Variable1"); var data2 = getVar("Variable2"); var data3 = getVar("Variable3"); var data4 = getVar("Variable4"); function insertRowIntoTable(tableName, rowData) { const pathParts = window.location.pathname.replace(/^\/|\/$/g, '').split('/'); let subdirectory = ''; if (pathParts.length > 0 && pathParts[0] !== 'wp-json' && pathParts[0] !== 'wp-content') { subdirectory = pathParts[0]; } // Construct the endpoint const endpoint = subdirectory ? `${window.location.origin}/${subdirectory}/wp-json/my-custom-databases/v1/insert_row` : `${window.location.origin}/wp-json/my-custom-databases/v1/insert_row`; fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': parent.myCustomDatabasesAjax.nonce }, body: JSON.stringify({ table_name: tableName, row_data: rowData }) }) .then(response => { if (!response.ok) { return response.json().then(error => { throw new Error(error.Error_Response); }); } return response.text(); }) .then(data => { console.log(data); }) .catch(error => { console.error('There has been a problem with your fetch operation:', error); }); } insertRowIntoTable(db_name, [data1, data2, data3, data4]);
Recall Values From A Custom Database for Storyline (v2.5 update)
var db_name = "MY_STORYLINE_DB"; function getTableData(tableName) { const pathParts = window.location.pathname.replace(/^\/|\/$/g, '').split('/'); let subdirectory = ''; if (pathParts.length > 0 && pathParts[0] !== 'wp-json' && pathParts[0] !== 'wp-content') { subdirectory = pathParts[0]; } const url = new URL( subdirectory ? `${window.location.origin}/${subdirectory}/wp-json/my-custom-databases/v1/get_table_data` : `${window.location.origin}/wp-json/my-custom-databases/v1/get_table_data` ); url.searchParams.append('table_name', tableName); fetch(url, { method: 'GET', headers: { 'X-WP-Nonce': parent.myCustomDatabasesAjax.nonce } }) .then(response => { if (!response.ok) { return response.json().then(error => { throw new Error(error.Error_Response); }); } return response.json(); }) .then(data => { // console.log(data); // Use this block to process the returned JSON data from your database table how you wish for your project. }) .catch((error) => { console.error('Error:', error); }); } // Call the function with the name of the table you want to get data from getTableData('MY_STORYLINE_DB');