MediaWiki:Common.js: Difference between revisions
From MaRDI portal
m 1 revision imported |
No edit summary |
||
(108 intermediate revisions by 2 users not shown) | |||
Line 11: | Line 11: | ||
* dependency hasn't arrived yet it'll make sure those are loaded before this. | * dependency hasn't arrived yet it'll make sure those are loaded before this. | ||
*/ | */ | ||
jQuery(document).ready(function() { | |||
var chartContainers = jQuery('.wikiChartContainer'); | |||
if (chartContainers.length > 0) { | |||
var loadChartJs = function(callback) { | |||
var script = document.createElement('script'); | |||
script.type = 'text/javascript'; | |||
script.src = 'https://cdn.jsdelivr.net/npm/chart.js'; | |||
script.onload = callback; | |||
document.head.appendChild(script); | |||
}; | |||
var initCharts = function() { | |||
chartContainers.each(function() { | |||
var chartContainer = jQuery(this); | |||
var chartData = JSON.parse(chartContainer.attr('data-chartdata')); | |||
var canvas = document.createElement('canvas'); | |||
chartContainer.append(canvas); | |||
var ctx = canvas.getContext('2d'); | |||
new Chart(ctx, chartData); | |||
}); | |||
}; | |||
loadChartJs(initCharts); | |||
} | |||
}); | |||
/* global mw, $ */ | /* global mw, $ */ | ||
/* jshint strict:false, browser:true */ | /* jshint strict:false, browser:true */ | ||
/* Load Popper.js and Tippy.js */ | |||
$.getScript('https://unpkg.com/@popperjs/core@2', function() { | |||
$.getScript('https://unpkg.com/tippy.js@6', function() { | |||
// Initialize Tippy.js tooltips after both libraries are loaded | |||
tippy('[data-tippy-content]', { | |||
placement: 'top', | |||
theme: 'dark', | |||
arrow: true, | |||
animation: 'shift-away', | |||
}); | |||
}); | |||
}); | |||
mw.loader.using( [ 'mediawiki.util' ] ).done( function () { | mw.loader.using( [ 'mediawiki.util' ] ).done( function () { | ||
Line 31: | Line 71: | ||
} ); | } ); | ||
} | } | ||
/* Hides top search bar if user is not logged in */ | |||
mw.loader.using(['mediawiki.user']).done(function () { | |||
if (mw.user.isAnon()) { | |||
mw.util.addCSS('#searchform .input-group { display: none !important; }'); | |||
} | |||
}); | |||
/** | /** | ||
Line 203: | Line 251: | ||
} ); | } ); | ||
} | } | ||
/* For adding userid to a hidden element */ | |||
mw.loader.using( ['mediawiki.util', 'mediawiki.user'] ).done(function () { | |||
// Create a hidden div to store the User ID | |||
var userIdStorage = document.createElement("div"); | |||
userIdStorage.id = "user-id-storage"; | |||
userIdStorage.style.display = "none"; // Keep it hidden | |||
// Get User ID and store it as a data attribute | |||
var userId = mw.user.getId(); | |||
if (userId) { | |||
userIdStorage.dataset.userid = userId; // Store in a data attribute | |||
} | |||
// Append it to the <body> so other scripts can access it | |||
document.body.appendChild(userIdStorage); | |||
}); | |||
/* End of mw.loader.using callback */ | /* End of mw.loader.using callback */ | ||
} ); | } ); | ||
/* Matomo Tracking Code */ | |||
var _paq = window._paq = window._paq || []; | |||
_paq.push(['trackPageView']); | |||
_paq.push(['enableLinkTracking']); | |||
(function() { | |||
var u="//matomo.portal.mardi4nfdi.de/"; | |||
_paq.push(['setTrackerUrl', u+'matomo.php']); | |||
_paq.push(['setSiteId', '1']); | |||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; | |||
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); | |||
})(); | |||
/* End Matomo Code */ | |||
/* ======================================================== */ | |||
function initializeDeepChat() { | |||
console.log("Initializing Deep Chat..."); | |||
const chatMarker = document.querySelector(".DeepChat"); | |||
if (chatMarker) { | |||
// Get the currently logged-in user's name | |||
const username = mw.config.get('wgUserName') || "Anonymous"; | |||
// console.log("Logged-in user:", username); | |||
// Stop execution if the user is anonymous | |||
if (username === "Anonymous") { | |||
// console.log("Deep Chat not initialized: Anonymous users are not allowed."); | |||
return; | |||
} | |||
console.log("Deep Chat marker detected."); | |||
// Read page-specific configuration | |||
const data_config_raw = chatMarker.getAttribute("data-config") || "{}"; | |||
const data_config_sanitized = data_config_raw.replace(/\\([^"\\/bfnrtu])/g, ""); | |||
let config; | |||
try { | |||
config = JSON.parse(data_config_sanitized); | |||
} catch (e) { | |||
console.error("Failed to parse JSON after sanitization:", e); | |||
console.error("Sanitized JSON string:", data_config_sanitized); // Debugging output | |||
config = {}; // Provide a fallback | |||
} | |||
const pagename = config.pagename || "Unknown Page"; | |||
const namespace = config.namespace || "Unknown Namespace"; | |||
const pagetitle = config.pagetitle || "Unknown Title"; | |||
// Global connect configuration | |||
const globalConnect = { | |||
url: "https://flask.staging.mardi4nfdi.org/chat-stream", // Your backend server URL | |||
method: "POST", | |||
stream: true, | |||
headers: { | |||
"customName": "customHeaderValue" | |||
}, | |||
additionalBodyProps: { | |||
customBodyField: "customBodyValue", | |||
pagename: pagename, | |||
pagetitle: pagetitle, | |||
namespace: namespace | |||
} | |||
}; | |||
// Log the globalConnect configuration for debugging | |||
console.log("Global Connect Configuration:", globalConnect); | |||
// Create a container for the Deep Chat component | |||
const chatContainer = document.createElement("div"); | |||
chatContainer.style.borderRadius = "10px"; | |||
chatContainer.style.position = "fixed"; | |||
chatContainer.style.bottom = "0px"; | |||
chatContainer.style.right = "7%"; | |||
chatContainer.style.zIndex = "1"; | |||
chatContainer.innerHTML = ` | |||
<deep-chat id="chat-element" | |||
history='${JSON.stringify(config.history || [])}' | |||
connect='${JSON.stringify(globalConnect)}' | |||
style="border-radius: 10px; border-color: #dcdcdc; background-color: #f3f6fc" | |||
textInput='{ | |||
"styles": { | |||
"container": { | |||
"borderRadius": "20px", "border": "1px solid #969696", "boxShadow": "unset", | |||
"width": "78%", "marginLeft": "-15px" | |||
}, | |||
"text": {"padding": "10px", "paddingLeft": "15px", "paddingRight": "34px"} | |||
}, | |||
"placeholder": {"text": "Enter your question here", "style": {"color": "#bcbcbc"}} | |||
}' | |||
messageStyles='{ | |||
"default": { | |||
"shared": { | |||
"bubble": {"maxWidth": "100%", "backgroundColor": "unset", "marginTop": "10px", | |||
"marginBottom": "10px"} | |||
}, | |||
"user": {"bubble": {"marginLeft": "0px", "color": "black"}}, | |||
"ai": {"innerContainer": {"borderRadius": "15px", "backgroundColor": "white"}} | |||
} | |||
}' | |||
avatars='{ | |||
"default": { | |||
"styles": {"position": "left", | |||
"container": {"marginLeft": "12px", "marginRight": "5px"}} | |||
}, | |||
"ai": { | |||
"src": "/w/images_repo/favicon.png", | |||
"styles": {"position": "left", "avatar": {"paddingTop": "6px"}} | |||
} | |||
}' | |||
speechToText='{ | |||
"button": { | |||
"default": { | |||
"container": { | |||
"default": {"bottom": "1em", "right": "0.6em", "borderRadius": "20px", | |||
"width": "1.9em", "height": "1.9em"} | |||
}, | |||
"svg": {"styles": {"default": {"bottom": "0.35em", "left": "0.35em"}}} | |||
}, | |||
"position": "inside-right" | |||
} | |||
}' | |||
introPanelStyle='{"backgroundColor": "#fffeec"}' | |||
submitButtonStyles='{ | |||
"position": "outside-right", | |||
"submit": { | |||
"container": { | |||
"default": {"bottom": "0.9em", "borderRadius": "25px", "padding": "6px 5px 4px", | |||
"backgroundColor": "#f3f6fc"}, | |||
"hover": {"backgroundColor": "#b0deff4f"}, | |||
"click": {"backgroundColor": "#b0deffb5"} | |||
}, | |||
"svg": { | |||
"content": "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?> <svg viewBox=\\"0 0 24 24\\" | |||
xmlns=\\"http://www.w3.org/2000/svg\\"><path d=\\"m21.426 11.095-17-8A.999.999 | |||
0 0 0 3.03 4.242L4.969 12 3.03 19.758a.998.998 0 0 0 1.396 1.147l17-8a1 1 0 | |||
0 0 0-1.81zM5.481 18.197l.839-3.357L12 12 6.32 9.16l-.839-3.357L18.651 12l-13.17 | |||
6.197z\\"/></svg>", | |||
"styles": { | |||
"default": { | |||
"width": "1.5em", | |||
"filter": "brightness(0) saturate(100%) invert(10%) sepia(86%) saturate(6044%) | |||
hue-rotate(205deg) brightness(100%) contrast(100%)" | |||
} | |||
} | |||
} | |||
}, | |||
"loading": { | |||
"svg": { | |||
"styles": { | |||
"default": { | |||
"filter": "brightness(0) saturate(100%) invert(72%) sepia(0%) saturate(3044%) | |||
hue-rotate(322deg) brightness(100%) contrast(96%)" | |||
} | |||
} | |||
} | |||
}, | |||
"stop": { | |||
"container": {"hover": {"backgroundColor": "#ededed"}}, | |||
"svg": { | |||
"styles": { | |||
"default": { | |||
"filter": "brightness(0) saturate(100%) invert(59%) sepia(0%) saturate(0%) | |||
hue-rotate(348deg) brightness(96%) contrast(93%)" | |||
} | |||
} | |||
} | |||
} | |||
}' | |||
> | |||
<div style="display: block"> | |||
<div class="custom-button"> | |||
<div class="custom-button-text">"Explain this."</div> | |||
</div> | |||
<div class="custom-button" style="margin-top: 15px"> | |||
<div class="custom-button-text">"What is this research area about?"</div> | |||
</div> | |||
</div> | |||
</deep-chat> | |||
`; | |||
// Add close button | |||
const minimizeButton = document.createElement("button"); | |||
minimizeButton.innerHTML = "✕"; // Unicode "x" as an icon | |||
minimizeButton.style.position = "absolute"; | |||
minimizeButton.style.top = "5px"; | |||
minimizeButton.style.right = "10px"; | |||
minimizeButton.style.border = "none"; | |||
minimizeButton.style.background = "none"; | |||
minimizeButton.style.cursor = "pointer"; | |||
minimizeButton.style.fontSize = "20px"; | |||
minimizeButton.style.color = "#666"; | |||
minimizeButton.onclick = () => { | |||
if (chatContainer.style.opacity === "0") { | |||
chatContainer.style.opacity = "1"; | |||
chatContainer.style.transform = "scale(1)"; | |||
} else { | |||
chatContainer.style.opacity = "0"; | |||
chatContainer.style.transform = "scale(0.9)"; | |||
} | |||
}; | |||
chatContainer.appendChild(minimizeButton); | |||
// Append the container to the body | |||
document.body.appendChild(chatContainer); | |||
// Dynamically load the Deep Chat library as a module | |||
const script = document.createElement("script"); | |||
script.type = "module"; | |||
script.src = "https://unpkg.com/deep-chat@2.1.1/dist/deepChat.bundle.js"; | |||
script.onload = () => { | |||
console.log("Deep Chat library loaded successfully."); | |||
// Setup event handling for quick response buttons | |||
const chatElementRef = document.getElementById("chat-element"); | |||
chatElementRef.htmlClassUtilities = { | |||
["custom-button"]: { | |||
events: { | |||
click: (event) => { | |||
const text = event.target.children[0].innerText; | |||
chatElementRef.submitUserMessage(text.substring(1, text.length - 1)); | |||
}, | |||
}, | |||
styles: { | |||
default: { backgroundColor: "#f2f2f2", borderRadius: "10px", padding: "10px", cursor: "pointer", textAlign: "center" }, | |||
hover: { backgroundColor: "#ebebeb" }, | |||
click: { backgroundColor: "#e4e4e4" }, | |||
}, | |||
}, | |||
["custom-button-text"]: { styles: { default: { pointerEvents: "none" } } }, | |||
}; | |||
chatElementRef.connect = globalConnect; | |||
chatElementRef.history.push( | |||
{ | |||
html: ` | |||
<div class="deep-chat-temporary-message"> | |||
<button class="deep-chat-button deep-chat-suggestion-button" style="margin-top: 6px">What is this page about?</button> | |||
<button class="deep-chat-button deep-chat-suggestion-button" style="margin-top: 6px">Which math areas are relevant?</button> | |||
</div>`, | |||
role: 'ai', | |||
}); | |||
chatElementRef.messageStyles = {html: {shared: {bubble: {backgroundColor: 'unset', padding: '0px'}}}}; | |||
Object.assign(chatElementRef.style, {height: '370px', borderRadius: '8px'}); | |||
}; | |||
script.onerror = () => console.error("Failed to load the Deep Chat library."); | |||
document.head.appendChild(script); | |||
} else { | |||
console.log("Deep Chat not initialized: No marker found."); | |||
} | |||
} | |||
// Ensure DOM is ready before running the initialization | |||
if (document.readyState === "loading") { | |||
document.addEventListener("DOMContentLoaded", initializeDeepChat); | |||
} else { | |||
initializeDeepChat(); | |||
} | |||
/* DO NOT ADD CODE BELOW THIS LINE */ | /* DO NOT ADD CODE BELOW THIS LINE */ |
Latest revision as of 20:09, 24 February 2025
/**
* Keep code in MediaWiki:Common.js to a minimum as it is unconditionally
* loaded for all users on every wiki page. If possible create a gadget that is
* enabled by default instead of adding it here (since gadgets are fully
* optimized ResourceLoader modules with possibility to add dependencies etc.)
*
* Since Common.js isn't a gadget, there is no place to declare its
* dependencies, so we have to lazy load them with mw.loader.using on demand and
* then execute the rest in the callback. In most cases these dependencies will
* be loaded (or loading) already and the callback will not be delayed. In case a
* dependency hasn't arrived yet it'll make sure those are loaded before this.
*/
jQuery(document).ready(function() {
var chartContainers = jQuery('.wikiChartContainer');
if (chartContainers.length > 0) {
var loadChartJs = function(callback) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
script.onload = callback;
document.head.appendChild(script);
};
var initCharts = function() {
chartContainers.each(function() {
var chartContainer = jQuery(this);
var chartData = JSON.parse(chartContainer.attr('data-chartdata'));
var canvas = document.createElement('canvas');
chartContainer.append(canvas);
var ctx = canvas.getContext('2d');
new Chart(ctx, chartData);
});
};
loadChartJs(initCharts);
}
});
/* global mw, $ */
/* jshint strict:false, browser:true */
/* Load Popper.js and Tippy.js */
$.getScript('https://unpkg.com/@popperjs/core@2', function() {
$.getScript('https://unpkg.com/tippy.js@6', function() {
// Initialize Tippy.js tooltips after both libraries are loaded
tippy('[data-tippy-content]', {
placement: 'top',
theme: 'dark',
arrow: true,
animation: 'shift-away',
});
});
});
mw.loader.using( [ 'mediawiki.util' ] ).done( function () {
/* Begin of mw.loader.using callback */
/**
* Main Page layout fixes
*
* Description: Adds an additional link to the complete list of languages available.
* Should T18962 be completed this can be removed along with associated CSS in common.css
* Maintainers: [[User:AzaToth]]
*/
if ( mw.config.get( 'wgPageName' ) === 'Main_Page' || mw.config.get( 'wgPageName' ) === 'Talk:Main_Page' ) {
$( function () {
mw.util.addPortletLink( 'p-lang', '//meta.wikimedia.org/wiki/List_of_Wikipedias',
'Complete list', 'interwiki-completelist', 'Complete list of Wikipedias' );
} );
}
/* Hides top search bar if user is not logged in */
mw.loader.using(['mediawiki.user']).done(function () {
if (mw.user.isAnon()) {
mw.util.addCSS('#searchform .input-group { display: none !important; }');
}
});
/**
* Map addPortletLink to mw.util
* @deprecated: Use mw.util.addPortletLink instead.
*/
mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink, 'Use mw.util.addPortletLink instead' );
/**
* Test if an element has a certain class
* @deprecated: Use $(element).hasClass() instead.
*/
mw.log.deprecate( window, 'hasClass', function ( element, className ) {
return $( element ).hasClass( className );
}, 'Use jQuery.hasClass() instead' );
/**
* @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
* @rev 6
*/
var extraCSS = mw.util.getParamValue( 'withCSS' ),
extraJS = mw.util.getParamValue( 'withJS' );
if ( extraCSS ) {
if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) {
mw.loader.load( '/w/index.php?title=' + extraCSS + '&action=raw&ctype=text/css', 'text/css' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } );
}
}
if ( extraJS ) {
if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) {
mw.loader.load( '/w/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } );
}
}
/**
* WikiMiniAtlas
*
* Description: WikiMiniAtlas is a popup click and drag world map.
* This script causes all of our coordinate links to display the WikiMiniAtlas popup button.
* The script itself is located on meta because it is used by many projects.
* See [[Meta:WikiMiniAtlas]] for more information.
* Note - use of this service is recommended to be replaced with mw:Help:Extension:Kartographer
*/
$( function () {
var requireWikiminiatlas = $( 'a.external.text[href*="geohack"]' ).length || $( 'div.kmldata' ).length;
if ( requireWikiminiatlas ) {
mw.loader.load( '//meta.wikimedia.org/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript' );
}
} );
/**
* Collapsible tables; reimplemented with mw-collapsible
* Styling is also in place to avoid FOUC
*
* Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
* @version 3.0.0 (2018-05-20)
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
* @author [[User:R. Koot]]
* @author [[User:Krinkle]]
* @author [[User:TheDJ]]
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
* is supported in MediaWiki core. Shimmable since MediaWiki 1.32
*
* @param {jQuery} $content
*/
function makeCollapsibleMwCollapsible( $content ) {
var $tables = $content
.find( 'table.collapsible:not(.mw-collapsible)' )
.addClass( 'mw-collapsible' );
$.each( $tables, function ( index, table ) {
// mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
if ( $( table ).hasClass( 'collapsed' ) ) {
$( table ).addClass( 'mw-collapsed' );
// mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
}
} );
if ( $tables.length > 0 ) {
mw.loader.using( 'jquery.makeCollapsible' ).then( function () {
$tables.makeCollapsible();
} );
}
}
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible );
/**
* Add support to mw-collapsible for autocollapse, innercollapse and outercollapse
*
* Maintainers: TheDJ
*/
function mwCollapsibleSetup( $collapsibleContent ) {
var $element,
$toggle,
autoCollapseThreshold = 2;
$.each( $collapsibleContent, function ( index, element ) {
$element = $( element );
if ( $element.hasClass( 'collapsible' ) ) {
$element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) );
}
if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) {
$element.data( 'mw-collapsible' ).collapse();
} else if ( $element.hasClass( 'innercollapse' ) ) {
if ( $element.parents( '.outercollapse' ).length > 0 ) {
$element.data( 'mw-collapsible' ).collapse();
}
}
// because of colored backgrounds, style the link in the text color
// to ensure accessible contrast
$toggle = $element.find( '.mw-collapsible-toggle' );
if ( $toggle.length ) {
// Make the toggle inherit text color
if ( $toggle.parent()[ 0 ].style.color ) {
$toggle.find( 'a' ).css( 'color', 'inherit' );
}
}
} );
}
mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup );
/**
* Magic editintros ****************************************************
*
* Description: Adds editintros on disambiguation pages and BLP pages.
* Maintainers: [[User:RockMFR]]
*
* @param {string} name
*/
function addEditIntro( name ) {
$( '.mw-editsection, #ca-edit, #ca-ve-edit' ).find( 'a' ).each( function ( i, el ) {
el.href = $( this ).attr( 'href' ) + '&editintro=' + name;
} );
}
if ( mw.config.get( 'wgNamespaceNumber' ) === 0 ) {
$( function () {
if ( document.getElementById( 'disambigbox' ) ) {
addEditIntro( 'Template:Disambig_editintro' );
}
} );
$( function () {
var cats = mw.config.get( 'wgCategories' );
if ( !cats ) {
return;
}
if ( $.inArray( 'Living people', cats ) !== -1 || $.inArray( 'Possibly living people', cats ) !== -1 ) {
addEditIntro( 'Template:BLP_editintro' );
}
} );
}
/* Actions specific to the edit page */
if ( mw.config.get( 'wgAction' ) === 'edit' || mw.config.get( 'wgAction' ) === 'submit' ) {
/**
* Fix edit summary prompt for undo
*
* Fixes the fact that the undo function combined with the "no edit summary prompter"
* complains about missing editsummary, if leaving the edit summary unchanged.
* Added by [[User:Deskana]], code by [[User:Tra]].
* See also [[phab:T10912]].
*/
$( function () {
if ( document.location.search.indexOf( 'undo=' ) !== -1 && document.getElementsByName( 'wpAutoSummary' )[ 0 ] ) {
document.getElementsByName( 'wpAutoSummary' )[ 0 ].value = '1';
}
} );
}
/* For adding userid to a hidden element */
mw.loader.using( ['mediawiki.util', 'mediawiki.user'] ).done(function () {
// Create a hidden div to store the User ID
var userIdStorage = document.createElement("div");
userIdStorage.id = "user-id-storage";
userIdStorage.style.display = "none"; // Keep it hidden
// Get User ID and store it as a data attribute
var userId = mw.user.getId();
if (userId) {
userIdStorage.dataset.userid = userId; // Store in a data attribute
}
// Append it to the <body> so other scripts can access it
document.body.appendChild(userIdStorage);
});
/* End of mw.loader.using callback */
} );
/* Matomo Tracking Code */
var _paq = window._paq = window._paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//matomo.portal.mardi4nfdi.de/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
/* End Matomo Code */
/* ======================================================== */
function initializeDeepChat() {
console.log("Initializing Deep Chat...");
const chatMarker = document.querySelector(".DeepChat");
if (chatMarker) {
// Get the currently logged-in user's name
const username = mw.config.get('wgUserName') || "Anonymous";
// console.log("Logged-in user:", username);
// Stop execution if the user is anonymous
if (username === "Anonymous") {
// console.log("Deep Chat not initialized: Anonymous users are not allowed.");
return;
}
console.log("Deep Chat marker detected.");
// Read page-specific configuration
const data_config_raw = chatMarker.getAttribute("data-config") || "{}";
const data_config_sanitized = data_config_raw.replace(/\\([^"\\/bfnrtu])/g, "");
let config;
try {
config = JSON.parse(data_config_sanitized);
} catch (e) {
console.error("Failed to parse JSON after sanitization:", e);
console.error("Sanitized JSON string:", data_config_sanitized); // Debugging output
config = {}; // Provide a fallback
}
const pagename = config.pagename || "Unknown Page";
const namespace = config.namespace || "Unknown Namespace";
const pagetitle = config.pagetitle || "Unknown Title";
// Global connect configuration
const globalConnect = {
url: "https://flask.staging.mardi4nfdi.org/chat-stream", // Your backend server URL
method: "POST",
stream: true,
headers: {
"customName": "customHeaderValue"
},
additionalBodyProps: {
customBodyField: "customBodyValue",
pagename: pagename,
pagetitle: pagetitle,
namespace: namespace
}
};
// Log the globalConnect configuration for debugging
console.log("Global Connect Configuration:", globalConnect);
// Create a container for the Deep Chat component
const chatContainer = document.createElement("div");
chatContainer.style.borderRadius = "10px";
chatContainer.style.position = "fixed";
chatContainer.style.bottom = "0px";
chatContainer.style.right = "7%";
chatContainer.style.zIndex = "1";
chatContainer.innerHTML = `
<deep-chat id="chat-element"
history='${JSON.stringify(config.history || [])}'
connect='${JSON.stringify(globalConnect)}'
style="border-radius: 10px; border-color: #dcdcdc; background-color: #f3f6fc"
textInput='{
"styles": {
"container": {
"borderRadius": "20px", "border": "1px solid #969696", "boxShadow": "unset",
"width": "78%", "marginLeft": "-15px"
},
"text": {"padding": "10px", "paddingLeft": "15px", "paddingRight": "34px"}
},
"placeholder": {"text": "Enter your question here", "style": {"color": "#bcbcbc"}}
}'
messageStyles='{
"default": {
"shared": {
"bubble": {"maxWidth": "100%", "backgroundColor": "unset", "marginTop": "10px",
"marginBottom": "10px"}
},
"user": {"bubble": {"marginLeft": "0px", "color": "black"}},
"ai": {"innerContainer": {"borderRadius": "15px", "backgroundColor": "white"}}
}
}'
avatars='{
"default": {
"styles": {"position": "left",
"container": {"marginLeft": "12px", "marginRight": "5px"}}
},
"ai": {
"src": "/w/images_repo/favicon.png",
"styles": {"position": "left", "avatar": {"paddingTop": "6px"}}
}
}'
speechToText='{
"button": {
"default": {
"container": {
"default": {"bottom": "1em", "right": "0.6em", "borderRadius": "20px",
"width": "1.9em", "height": "1.9em"}
},
"svg": {"styles": {"default": {"bottom": "0.35em", "left": "0.35em"}}}
},
"position": "inside-right"
}
}'
introPanelStyle='{"backgroundColor": "#fffeec"}'
submitButtonStyles='{
"position": "outside-right",
"submit": {
"container": {
"default": {"bottom": "0.9em", "borderRadius": "25px", "padding": "6px 5px 4px",
"backgroundColor": "#f3f6fc"},
"hover": {"backgroundColor": "#b0deff4f"},
"click": {"backgroundColor": "#b0deffb5"}
},
"svg": {
"content": "<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?> <svg viewBox=\\"0 0 24 24\\"
xmlns=\\"http://www.w3.org/2000/svg\\"><path d=\\"m21.426 11.095-17-8A.999.999
0 0 0 3.03 4.242L4.969 12 3.03 19.758a.998.998 0 0 0 1.396 1.147l17-8a1 1 0
0 0 0-1.81zM5.481 18.197l.839-3.357L12 12 6.32 9.16l-.839-3.357L18.651 12l-13.17
6.197z\\"/></svg>",
"styles": {
"default": {
"width": "1.5em",
"filter": "brightness(0) saturate(100%) invert(10%) sepia(86%) saturate(6044%)
hue-rotate(205deg) brightness(100%) contrast(100%)"
}
}
}
},
"loading": {
"svg": {
"styles": {
"default": {
"filter": "brightness(0) saturate(100%) invert(72%) sepia(0%) saturate(3044%)
hue-rotate(322deg) brightness(100%) contrast(96%)"
}
}
}
},
"stop": {
"container": {"hover": {"backgroundColor": "#ededed"}},
"svg": {
"styles": {
"default": {
"filter": "brightness(0) saturate(100%) invert(59%) sepia(0%) saturate(0%)
hue-rotate(348deg) brightness(96%) contrast(93%)"
}
}
}
}
}'
>
<div style="display: block">
<div class="custom-button">
<div class="custom-button-text">"Explain this."</div>
</div>
<div class="custom-button" style="margin-top: 15px">
<div class="custom-button-text">"What is this research area about?"</div>
</div>
</div>
</deep-chat>
`;
// Add close button
const minimizeButton = document.createElement("button");
minimizeButton.innerHTML = "✕"; // Unicode "x" as an icon
minimizeButton.style.position = "absolute";
minimizeButton.style.top = "5px";
minimizeButton.style.right = "10px";
minimizeButton.style.border = "none";
minimizeButton.style.background = "none";
minimizeButton.style.cursor = "pointer";
minimizeButton.style.fontSize = "20px";
minimizeButton.style.color = "#666";
minimizeButton.onclick = () => {
if (chatContainer.style.opacity === "0") {
chatContainer.style.opacity = "1";
chatContainer.style.transform = "scale(1)";
} else {
chatContainer.style.opacity = "0";
chatContainer.style.transform = "scale(0.9)";
}
};
chatContainer.appendChild(minimizeButton);
// Append the container to the body
document.body.appendChild(chatContainer);
// Dynamically load the Deep Chat library as a module
const script = document.createElement("script");
script.type = "module";
script.src = "https://unpkg.com/deep-chat@2.1.1/dist/deepChat.bundle.js";
script.onload = () => {
console.log("Deep Chat library loaded successfully.");
// Setup event handling for quick response buttons
const chatElementRef = document.getElementById("chat-element");
chatElementRef.htmlClassUtilities = {
["custom-button"]: {
events: {
click: (event) => {
const text = event.target.children[0].innerText;
chatElementRef.submitUserMessage(text.substring(1, text.length - 1));
},
},
styles: {
default: { backgroundColor: "#f2f2f2", borderRadius: "10px", padding: "10px", cursor: "pointer", textAlign: "center" },
hover: { backgroundColor: "#ebebeb" },
click: { backgroundColor: "#e4e4e4" },
},
},
["custom-button-text"]: { styles: { default: { pointerEvents: "none" } } },
};
chatElementRef.connect = globalConnect;
chatElementRef.history.push(
{
html: `
<div class="deep-chat-temporary-message">
<button class="deep-chat-button deep-chat-suggestion-button" style="margin-top: 6px">What is this page about?</button>
<button class="deep-chat-button deep-chat-suggestion-button" style="margin-top: 6px">Which math areas are relevant?</button>
</div>`,
role: 'ai',
});
chatElementRef.messageStyles = {html: {shared: {bubble: {backgroundColor: 'unset', padding: '0px'}}}};
Object.assign(chatElementRef.style, {height: '370px', borderRadius: '8px'});
};
script.onerror = () => console.error("Failed to load the Deep Chat library.");
document.head.appendChild(script);
} else {
console.log("Deep Chat not initialized: No marker found.");
}
}
// Ensure DOM is ready before running the initialization
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeDeepChat);
} else {
initializeDeepChat();
}
/* DO NOT ADD CODE BELOW THIS LINE */