\
');
}
}, 500 );
// setInterval( function () { console.log($fng.ui); }, 100);
function _fng_docReady(fn) {
// see if DOM is already available
if (document.readyState === "complete" || document.readyState === "interactive") {
// call on next available tick
setTimeout(fn, 10);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
/*
function _fng_loadjQueryUIAndExecute(callback)
{
// $fng('head').append($fng('').attr('href', '/_fng/jquery-ui/jquery-ui.min.css'));
if ($fng.ui != undefined && $fng.fn.tooltip != undefined) {
console.log( (new Date().getTime()-_fng_zerotime) + ' JM: jQueryUI already LOADED' );
return callback();
}
// console.log( (new Date().getTime()-_fng_zerotime) + ' JM: INJECTING LOADER FOR jQuery UI' );
// $fng.getScript('/_fng/jquery-ui/jquery-ui.min.js', callback);
console.log( (new Date().getTime()-_fng_zerotim) + ' JM: jQuery UI not yet loaded, wait and retry...' );
setTimeout( function () { _fng_loadjQueryUIAndExecute(callback) }, 100 );
}
*/
/*
var g_FNG_whenjQueryUIReady_count = 0;
function _fng_whenjQueryUIReady(fn)
{
g_FNG_whenjQueryUIReady_count++;
if (g_FNG_whenjQueryUIReady_count>100) {
console.log( (new Date().getTime()-_fng_zerotime) + ' JM: Too many iterations of _fng_whenjQueryUIReady. exiting...' );
return;
}
// see if jQueryUI is already available
if ( $fng.ui != undefined && $fng.fn.tooltip != undefined ) {
console.log( (new Date().getTime()-_fng_zerotime) + ' JM: jQueryUI LOADED !!!!' );
// call on next available tick
setTimeout(fn, 10);
} else {
console.log( new Date().getTime() + ' JM: WAIT FOR jQuery UI to be loaded !!!!' );
// call on next available tick
setTimeout( function() { _fng_whenjQueryUIReady(fn) }, 100 );
}
}
*/
// DOM is loaded and ready for manipulation here
_fng_docReady(function() {
//alert( "DOM Loaded!\nJM a injecté du JavaScript globalement sur le site" );
console.log((new Date().getTime()-_fng_zerotime) + ' JM: in _fng_main_inject.js => DOC READY !!!!');
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Do some DOM manipulation with jQuery');
// Add two useful functions to jQuery : https://stackoverflow.com/questions/11098257/jquery-move-dom-element-inside-parent
$fng.fn.moveUp = function() { $fng.each(this, function() { $fng(this).after($fng(this).prev()); }); };
$fng.fn.moveDown = function() { $fng.each(this, function() { $fng(this).before($fng(this).next()); }); };
// Add changeElementType function to jQuery : https://stackoverflow.com/questions/8584098/how-to-change-an-element-type-using-jquery/8584217
$fng.fn.changeElementType = function(newType) { var attrs = {}; $fng.each(this[0].attributes, function(idx, attr) { attrs[attr.nodeName] = attr.nodeValue; }); this.replaceWith(function() { return $fng("<" + newType + "/>", attrs).append($fng(this).contents()); }); };
// Extend jQuery.fn with our new method : https://stackoverflow.com/questions/2389540/jquery-hasparent
$fng.extend( $fng.fn, {
// Name of our method & one argument (the parent selector)
within: function( pSelector ) {
// Returns a subset of items using jQuery.filter
return this.filter(function(){
// Return truthy/falsey based on presence in parent
return $fng(this).closest( pSelector ).length;
});
}
});
// ------------------
// LOGIN PAGE (START)
// ------------------
if ( _fng_isLoginPage() )
{
console.log((new Date().getTime()-_fng_zerotime) + ' JM: LOGIN PAGE: $session_has_timed_out=');
console.log((new Date().getTime()-_fng_zerotime) + ' JM: LOGIN PAGE: $errormsg=');
if ( _fngIsIE() ) {
$fng('body').append("
Plateforme e-learning
Internet Explorer ne permet pas l'utilisation de votre espace formation.
Ce navigateur n'étant plus compatible avec la plupart des technologies actuelles, merci d'utiliser l'une des nombreuses alternatives disponibles parmi : Google Chrome, Microsoft Edge, Mozilla Firefox, Safari, etc...
");
}
var abortLoginProcessBlock = false;
// Determine if an orga, different from the current is requested for this login page.
// If it is the case, we immediatly redirect to the proper orga login page before going further
// It may come:
// - from an '_fng_user_orga' cookie (set from within the user's space or from
// the login page that was in logout confirm mode when a login with orga url param
// was requested while an active session was going on),
// - from Moodle's $SESSION->wantsurl session variable (when a direct course link including
// an orga url param was requested and we were redirected to login to sign in before accessing to the target course )
/*
// If the login page is a step before accessing a course page,
// attempts a capture eventual orga and username info from target course page
if ( $_fng_wantsurl.indexOf('/course/view.php')!=0 && $_fng_wantsurl.indexOf('orga=')!=0 ) {
wantsOrga = ''; // TODO getorga from wantsurl
document.location.search = '?orga='+wantsOrga;
abortLoginProcessBlock = true;
}
*/
if ( !abortLoginProcessBlock ) {
// Already active session : in logout confirm mode
if ( _fng_isLoginPageWithActiveSessionLogoutConfirmation() ) {
// Set the orga coming from url param
_fng_Cookies.set('_fng_user_orga', _fng_orga );
}
/*
// expired session mode (session échue)
else if ( _fng_isLoginPageWithExpiredSessionNotice() ) {
// TODO : PERFORM en AUTO LOGIN using username an pwd from cookie
// PREREQUIRISITE TODO : username an pwd must be saved in cookie at initial login page access
// ...............
// EN FAIT on ne peut rien faire car quand la session est échue, Moodle fait immédiatement un
// HTTP 303 redirect sans response coté client (donc aucune moyen d'executer du javascript)
// et donc pas de moyen de stocker username et pwd depuis les url params vers des cookies.
}
*/
else {
var orgaFromCookie = _fng_Cookies.get('_fng_user_orga');
if ( orgaFromCookie != undefined ) {
if ( orgaFromCookie != _fng_orga ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: LOGIN PAGE: Different orga "'+orgaFromCookie+'" detected in cookie => redirecting to orga\'s login page');
_fng_Cookies.remove('_fng_user_orga');
document.location.search = '?orga='+orgaFromCookie;
abortLoginProcessBlock = true;
}
}
}
}
if ( !abortLoginProcessBlock ) {
// Change logo image
// Cas spécial pour Square Habitat sqh.. all sqh-XYZ orga will use the same logo
var logo_login_img_suffix = _fng_orga.startsWith('sqh-') ? 'sqh-' : _fng_orga;
$fng('#page-login-index [role="main"] .row.justify-content-center .card-header .img-fluid').attr('src', '/_fng/img/logo_login_orga_'+logo_login_img_suffix+'.png' );
// Inject a DIV to used to display graphics/image to the left of the login form
$fng('').insertBefore('#page-login-index [role="main"] .row.justify-content-center:first');
if ( _fng_orga == 'racine' ) {
$fng( '.col-sm-8 .card-header').html( 'Identification pour l\'accès à vos formations en e-learning' );
}
if ( _fng_orga == 'racine-loginfng' ) {
// Inject the 3 image buttons
$fng('#page-login-index [role="main"]')
.prepend($fng(' \
\
'));
}
// Trim password value in case user selected extra spaces with copy-paste
$fng('#password').on( 'change', function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Password field value changed => trimming it in case user selected extra spaces with copy-paste');
$fng(this).val( $fng(this).val().trim() );
} );
// AUTO-LOGIN if url params are specified
if ( _fng_UrlParamsHasValue( 'username' ) ) {
$fng('#username').val( _fng_gURL_PARAMS.username );
}
if ( _fng_UrlParamsHasValue( 'pwd' ) ) {
$fng('#password').val( _fng_gURL_PARAMS.pwd );
// SUBMIT login form
$fng('form#login').submit();
}
else
if ( _fng_UrlParamsHasValue( 'otp' ) ) {
$fng('#password').val( _fng_gURL_PARAMS.otp );
// Save OTP in cookie for later retrieval in change passwordpage
_fng_Cookies.set( '_fng_otp', _fng_gURL_PARAMS.otp );
// SUBMIT login form
$fng('form#login').submit();
}
else {
setTimeout( function() { $fng('#username').focus(); }, 500 );
}
}
}
// ----------------
// LOGIN PAGE (END)
// ----------------
// ----------------------------
// CHANGE PASSWORD PAGE (START)
// ----------------------------
if ( _fng_isLoginPageChangePassword() ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: IN LOGIN-CHANGE-PASSWORD-PAGE');
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Check if OTP password in cookie...');
var otp = _fng_Cookies.get( '_fng_otp' );
if ( otp != undefined ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: ...Yes => prefill current password field + focus on new password field...');
$fng('#id_password').val( otp );
setTimeout( function() { $fng('#id_newpassword1').focus(); }, 1000 );
_fng_Cookies.remove( '_fng_otp' );
}
else {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: ...No => focus on current password field...');
setTimeout( function() { $fng('#id_password').focus(); }, 1000 );
}
}
// --------------------------
// CHANGE PASSWORD PAGE (END)
// --------------------------
// ----------------------------
// FORGOT PASSWORD PAGE (START)
// ----------------------------
if ( _fng_isForgotPasswordPage() ) {
// Insert le mot "OU" entre les deux champs
$fng( '
OU
' ).insertBefore( $fng('form.mform fieldset:eq(1)') );
// Déplace les bouton submit à droite de leur champs correspondants
$fng( '#id_submitbuttonusername' ).insertAfter( '#id_username' );
$fng( '#id_submitbuttonemail' ).insertAfter( '#id_email' );
// Vide l'autre champ que valeur d'un champ change
$fng('#id_username').on( 'change', function() { $fng( '#id_email' ).val( '' ); } );
$fng('#id_email').on( 'change', function() { $fng( '#id_username' ).val( '' ); } );
// Vide l'autre champ que on clique sur un des bouton submit
$fng( '#id_submitbuttonemail').on( 'click', function() { $fng( '#id_username' ).val( '' ); } );
$fng( '#id_submitbuttonusername').on( 'click', function() { $fng( '#id_email' ).val( '' ); } );
$fng('#page-login-forgot_password fieldset#id_searchbyemail legend')
.prepend('
Important : si cela concerne votre compte "MANAGER", veuillez faire votre demande de mot de passe "par identifiant" ➜ en cliquant ici...
');
$fng('#page-login-forgot_password fieldset#id_searchbyusername label[for="id_username"]').text('Veuillez renseigner votre identifiant');
}
// --------------------------
// FORGOT PASSWORD PAGE (END)
// --------------------------
// ------------------------------------------
// GLOBAL ALL PAGES (EXCEPT LOGIN!!) (START)
// ------------------------------------------
if ( ! _fng_isLoginPage() )
{
_fng_g_scrollBarWidth = _fng_scrollBarWidth();
//
$fng( window ).resize(function() {
// console.log( $fng( window ).width() + _fng_g_scrollBarWidth );
var mediaWidth = $fng( window ).width() + _fng_g_scrollBarWidth;
// Si la largeur de la fenetre est inférieure ou égale à 1000px, on replie le menu
if ( mediaWidth <= 1000 && _fng_isLeftMenuOpen() ) {
$fng('button[data-action="toggle-drawer"]').click();
}
});
// Do the following in all pages except course pages
if ( ! _fng_isCoursePages() ) {
// LEFT MENU: Put Accueil (Catalogue des cours) after Tableau de bord
var $catalogECommerceMenuItemEl = $fng('.list-group-item[data-key="home"]').parents('li');
$catalogECommerceMenuItemEl.addClass('_fng-access-catalog');
$catalogECommerceMenuItemEl.insertAfter($fng('.list-group-item[data-key="myhome"]').parents('li'));
$fng('.list-group-item[data-key="home"] .media-left .icon').removeClass('fa-home').addClass('fa-book');
// Clone menu item "tous les cours" to create an item pointing to moodle's internal catalog
var $catalogMoodleMenuItemEl = $catalogECommerceMenuItemEl.clone();
$catalogMoodleMenuItemEl.find('.list-group-item[data-key="home"]').attr('data-key','_fng-moodlecatalog').attr('href','/course');
$catalogMoodleMenuItemEl.find('.media .media-body').html('Catalogue des formations en IMMOBILIER');
$catalogMoodleMenuItemEl.insertAfter($catalogECommerceMenuItemEl);
$catalogECommerceMenuItemEl.addClass('_fng-catalog-type-ecommerce');
$catalogMoodleMenuItemEl.addClass('_fng-catalog-type-moodle');
}
// While in course pages, hide the catalog menu item.
else {
var $catalogECommerceMenuItemEl = $fng('.list-group-item[data-key="home"]').parents('li');
$catalogECommerceMenuItemEl.hide();
}
// TOP MENU: Insert a TOGGLE FULLSCREEN button
$fng(' \
\
').insertAfter($fng('.navbar-fhs [data-region="drawer-toggle"]'));
// TOP MENU: Insert un bouton "Visite guidée" UNIQUEMENT SUR LES PAGES QUI ONT DES VISITES GUIDEES
$fng(' \
\
\
\
').insertAfter($fng('#page-my-index #toggleFullscreen'));
// "BACK TO TOP" button: change chevron type
$fng('#back-to-top i.fa').removeClass('fa-chevron-circle-up').addClass('fa-chevron-up');
// WONDERBOX Grosses icones en haut de page (START)
// fix label of button of type "slider"
$fng('.fpwonderbox .iconset a[href="#fpslider"]').contents().filter(function() { return (this.nodeType === 3 && ($fng(this).text().trim().length != 0)); }).wrap('');
// Make click on Contact button show the contact form
$fng('.fpwonderbox .btn a[href="#_fng-contactform"]').on( 'click', function() {
$fng('#_fng-contactform-dashboard').toggle();
})
// 20220928 : We now hide the "contact" button for everyone to avoid people emailing us directly... They a encouraged to access to the Aide (FAQ) instead
.parents('.btn.btn-secondary').hide()
;
// Add a "_fng-wonderbox-button-tableaudebord" class to Tableau de bord button
$fng('.fpwonderbox .btn a[href$="/my/"]').parents('.btn').addClass('_fng-wonderbox-button-tableaudebord');
// Clone button Tous les cours to create a button pointing to moodle's internal catalog
var $catalogECommerceButtonEl = $fng('.fpwonderbox .btn a[href*="redirect=0"]').parents('.btn');
$catalogECommerceButtonEl.addClass('_fng-access-catalog');
var $catalogMoodleButtonEl = $catalogECommerceButtonEl.clone();
$catalogMoodleButtonEl.find('a[role="button"]').attr('href','/course').find('.link-text').html('Catalogue des formations en IMMOBILIER');
$catalogMoodleButtonEl.addClass('_fng-catalog-type-moodle');
$catalogECommerceButtonEl.addClass('_fng-catalog-type-ecommerce');
$catalogMoodleButtonEl.insertAfter($catalogECommerceButtonEl);
// WONDERBOX Grosses icones en haut de page (END)
}
// ------------------------------------------
// GLOBAL ALL PAGES (EXCEPT LOGIN!!) (END)
// ------------------------------------------
// ------------------------------------------
// PAGE "TABLEAU DE BORD - DASHBOARD" (START)
// ------------------------------------------
// // HOME PAGE : (body.path-site) add logo in navbar (because there's no logo displayed in home pages' nav bar)
// $fng('body.path-site .navbar-brand').prepend($fng(''));
// HOME PAGE (DASHBOARD - TABLEAU DE BORD)
if ( _fng_isDashboardPage() ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tableau de bord - dashboard"');
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Injecting Akuter history link if needed');
injectAkuterHistoryLinkInPageIfNeeded();
// $fng('.block_myoverview .card-body .card-title').text('Vue d\'ensemble des formations');
// $fng('.block_moofactory_course_progress .card-body .card-title').text('Progression des formations');
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Saving user\'s orga in cookie');
_fng_Cookies.set( '_fng_user_orga', _fng_orga );
// GENERATE VIP CATALOG LINK IF ALLOWED
var vipdata = _fngIsVIP();
console.log(vipdata);
if ( vipdata !== false ) {
$fng('._fng-catalog-type-moodle > a').attr( 'href', '/course/index.php?categoryid='+vipdata.catId+'&perpage=1000&browse=categories');
$fng('._fng-catalog-type-moodle').show();
}
}
// ----------------------------------------
// PAGE "TABLEAU DE BORD - DASHBOARD" (END)
// ----------------------------------------
// ---------------------------------------------------------
// PAGE "Liste des utilisateurs de mon organisation" (START)
// ---------------------------------------------------------
if ( $fng('body').is('#page-admin-local-moofactory_organisation-users-user') ) {
// Cache les suggestions de match sur d'autre Organisations
$fng( 'body#page-admin-local-moofactory_organisation-users-user [role="main"] table#filterusers' ).parent('div').hide().prev('h2').hide();
}
// ---------------------------------
// PAGE "Profil Utilisateur" (START)
// ---------------------------------
if ( _fng_isUserProfilePage() ) {
// https://elearning.essyca.fr/user/editadvanced.php?id=576&course=1&returnto=profile
// https://elearning.essyca.fr/local/moofactory_organisation/users/editadvanced.php?id=576&course=1
// Replace link "Modifier le profil" from the Moodle profile edit form to the MooFactory profile edit form so that we have no problem with
$fng( 'li.editprofile a' ).each( function (i,el) { $fng(this).attr( 'href', $fng(this).attr('href').replace( '/user/editadvanced.php', '/local/moofactory_organisation/users/editadvanced.php' ) ); } );
}
// -------------------------------
// PAGE "Profil Utilisateur" (END)
// -------------------------------
// -----------------------------------------------------
// PAGE USER UPLOAD "Importation d'utilisateurs" (START)
// -----------------------------------------------------
if ( _fng_isUserUploadPage() ) {
// Sur la première page de l'import :
$fng( '#id_delimiter_name option[value="tab"]' ).prop( 'selected', true ); // Format import => TSV
$fng( '#id_previewrows option[value="100000"]' ).prop( 'selected', true ); // Rangées de prévisualisation => 100000
// Sur la deuxieme page de l'import :
$fng('#id_profile_field_fng_naissance_date_enabled').prop( 'checked', false ); // Date de naissance par défaut => désactivée
$fng( '#id_uuforcepasswordchange' ).val( 0 ); // Imposer le changement du mot de passe => Aucun
$fng( '#id_uuallowsuspends' ).val( 0 ); // Permettre la suspension et l'activation de comptes => Non
$fng( '#id_uustandardusernames' ).val( 0 ); // Standardiser les noms d'utilisateur => Non
}
// ---------------------------------------------------
// PAGE USER UPLOAD "Importation d'utilisateurs" (END)
// ---------------------------------------------------
// ---------------------------------------------------------------
// PAGE MOOFACTORY CUSTOM DOCUMENT "Document personnalisé" (START)
// ---------------------------------------------------------------
if ( _fng_isCustomdocumentPage() ) {
// Change link in taab "Action en lot" to have 500 cert per page instead of 30
$fng('#region-main .nav-tabs .nav-item a[href*="tab=2"]').each( function (i,el) { $fng(this).attr( 'href', $fng(this).attr('href').replace( 'perpage=30', 'perpage=500' ) ); } );
}
// -------------------------------------------------------------
// PAGE MOOFACTORY CUSTOM DOCUMENT "Document personnalisé" (END)
// -------------------------------------------------------------
// -------------------------------------------------
// PAGE CATALOGUE VIP INDEX "TOUS LES COURS" (START)
// -------------------------------------------------
// CONTROL ACCESS TO CATALOGUE INDEX AND ENROL PAGE
if ( _fng_isCatalogVipIndexPage() || _fng_isCatalogVipEnrolPage() ) {
var vipdata = _fngIsVIP();
if ( vipdata==false ) {
document.location.href = '/';
return;
}
else {
$fng('body').show();
}
// ONLY IN CATALOGUE INDEX PAGE
if ( _fng_isCatalogVipIndexPage() ) {
/*
// Preload all course categories and detect those that are empty and hide them
$fng('.course_category_tree .subcategories .category.notloaded .categoryname').click();
setTimeout( function() { $fng('.course_category_tree .subcategories .category').addClass('collapsed'); }, 500 );
setTimeout( function() {
// $fng('.course_category_tree .subcategories .category.loaded').addClass('collapsed');
$fng('.course_category_tree .subcategories .category.notloaded .categoryname').click();
setTimeout( function() { $fng('.course_category_tree .subcategories .category').addClass('collapsed'); }, 500 );
setTimeout( function() {
// $fng('.course_category_tree .subcategories .category.loaded').addClass('collapsed');
$fng('.course_category_tree .subcategories .category').each( function() {
var topCatHasCourses = $fng(this).find('.content>.courses').length>0;
if (!topCatHasCourses)
$fng(this).hide();
} );
}, 1000) ;
}, 1000) ;
*/
// On Top categories page there is no class "category-???" in body
var isTopCategoriesPage = !($fng('body#page-course-index-category').is('[class*=" category-"]'));
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tous les cours": User in Orga other than Racine => hide course search and create controls');
// Hide dropdown list category picker + course search form
$fng('.categorypicker, .simplesearchform', 'body#page-course-index-category #page-content').hide();
/*
// Hide "ajouter un cours" button
$fng('body#page-course-index-category #page-content div[role=main] .buttons').hide();
*/
/* WE DON'T USE THIS ANYMORE
// Only if current user is part of an Orga other than racine
if ( !_fng_currentUserOrgaRacine() ) {
// Only in top-categories page
if ( isTopCategoriesPage ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tous les cours": In Top Category page => Only show course category corresponding to current user\'s organisation');
// Only show course category corresponding to current user's organisation
$fng('.course_category_tree .subcategories>.category').hide();
$fng('.course_category_tree .subcategories>.category[data-categoryid='+_fng_ORGA_COURSE_CATEGORIES[_fng_orga]+']').show();
}
}
*/
// Only in top-categories page
if ( isTopCategoriesPage ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": In Top Category page => Only show course category corresponding to VIP Catalogue allowed for user.');
// Only show course category corresponding to current user's organisation
$fng('.course_category_tree .subcategories>.category').hide();
$fng('.course_category_tree .subcategories>.category[data-categoryid='+vipdata.catId+']').show();
}
_fngCatalogVipIndexPageHideBabylonCoursesIfRequired();
// Auto-deploy top category and 1 level of sub category
setTimeout( function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tous les cours": Auto-deploy not-loaded category');
$fng('.course_category_tree .subcategories .category.notloaded .categoryname').click();
_fngCatalogVipIndexPageHideBabylonCoursesIfRequired();
setTimeout( function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tous les cours": Auto-deploy not-loaded category');
$fng('.course_category_tree .subcategories .category.notloaded .categoryname').click();
_fngCatalogVipIndexPageHideBabylonCoursesIfRequired();
setTimeout( function() {
_fngCatalogVipIndexPageHideBabylonCoursesIfRequired();
if (_fngdata!=undefined && _fngdata.enrol!=undefined && _fngdata.enrol.enrolled!=undefined) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Tous les cours": Detect already enrolled courses');
for (enrCourseId in _fngdata.enrol.enrolled) {
var $el = $fng('.courses.category-course-list-all figure.card .btn a[href$="id='+enrCourseId+'"]').parents('figure.card').addClass('fng-enrolled');
}
$fng('.card.fng-enrolled .btn.coursestyle2btn a').replaceText("S'inscrire", "Déjà inscrit");
$fng('.subcategories .paging-morelink a.btn')
.each( function (i, el) {
$fng(this).attr('href', $fng(this).attr('href').replace('&page=1', '&perpage=1000') );
$fng(this).replaceText('Voir plus', ' Voir plus de formations dans cette catégorie...' );
} );
}
}, 2000) ;
}, 2000) ;
}, 1000) ;
}
else
// ONLY IN CATALOGUE COURSE ENROL PAGE
if ( _fng_isCatalogVipEnrolPage() ) {
// Hide
$fng('#page-enrol-index #page-content #region-main form #id_selfheader:has(#fitem_id_nokey)').addClass('_fng-hasnokey');
_fngCatalogVipEnrolPagePreventBabylonCoursesIfRequired();
}
}
// -----------------------------------------------
// PAGE CATALOGUE VIP INDEX "TOUS LES COURS" (END)
// -----------------------------------------------
// -------------------
// COURSE PAGES (START)
// -------------------
if ( _fng_isCoursePages() ) {
// Attempts to retrieve course option Element of type ""
// that we put in an etiquette in section 0
var $courseOptionsEl = $fng('#_fng_course-options');
if ( $courseOptionsEl.length == 0 )
$courseOptionsEl = $fng('');
else
$courseOptionsEl = $fng($courseOptionsEl.get(0)); // Keep only first match in case there are many
/*
info pour eventuelle mise en place de l'option "section-hide-access_restriction_list" a placer dans le champ "résumé" d'une section du cours
$fng('._fng_course-options', '.pagelayout-course .course-content');
*/
// Only in course pages, intercept click on hash link to scroll with added offset to account for the top fixec nav height. src : https://stackoverflow.com/questions/22182928/hash-location-with-offset
(function($fng){
if ( "onhashchange" in window ) {
var hashHandler = function(e){
e.preventDefault();
var hash = window.location.hash.substring( 1 );
if ( !hash )
return;
var offset = $fng('.navbar').outerHeight(true) + 5;
var sel = '[id="' + hash + '"], a[name="' + hash + '"]';
var currentOffset = $fng( sel ).offset().top;
$fng( window ).scrollTop( currentOffset - offset );
};
window.addEventListener("hashchange", hashHandler, false);
window.addEventListener("load", hashHandler, false);
}
})(window.$fng);
// LEFT MENU: Move course calendar to top menu
$fng('body.format-moofactory #nav-drawer .list-group-item[data-key="calendar"]').parents('li').insertBefore($fng('.list-group-item[data-key="grades"]').parents('li'));
// LEFT MENU: Hide items : Participants, Badges, Competences, Calendrier
$fng('.list-group-item[data-key="participants"], .list-group-item[data-key="badgesview"], .list-group-item[data-key="competencies"], .list-group-item[data-key="calendar"]', 'body.format-moofactory #nav-drawer').parents('li').hide();
if ( $courseOptionsEl.is('.menu-show-badge') )
$fng('.list-group-item[data-key="badgesview"]', 'body.format-moofactory #nav-drawer').parents('li').show();
if ( $courseOptionsEl.is('.menu-show-calendar') )
$fng('.list-group-item[data-key="calendar"]', 'body.format-moofactory #nav-drawer').parents('li').show();
// Move course image element inside #learningcontent element
$fng('.headerbkg').prependTo($fng('#learningcontent'));
// LEFT MENU: Insert un Item Tableau de bord du cours
$fng(' \
\
').insertAfter($fng('body.format-moofactory #nav-drawer .list-group-item[data-key="coursehome"]').parents('li'));
// Hide bouton course Dashboard tableau de bord de la barre du haut
$fng('div.nav-item.studentdash').hide();
// LEFT MENU: Change menu icons of course sections ([data-type="30"] mean it is a "section" item )
$fng('#nav-drawer .list-group-item[data-type="30"] .media-left .fa-folder-o').removeClass('fa-folder-o').addClass('fa-caret-right');
// IN LEFT MENU, INJECT SECTIONS THAT ARE RESTRICTED AND ADD A LITTLE "Accès restreint" LABEL TO THEM (START)
var allSectionsIds = [];
$fng('.section.main').map( function(i, el) { allSectionsIds.push( $fng(this).attr('id') ); } )
var allSectionsNames = [];
$fng('.section.main').map( function(i, el) { allSectionsNames.push( $fng(this).find('.sectiontitle .sectionname').text() ); } )
var restrictedSectionsIds = [];
$fng('.section .content .section_availability .availabilityinfo.isrestricted').parents('.section.main').map( function(i, el) { restrictedSectionsIds.push( $fng(this).attr('id') ); } );
allSectionsIds = _fngAlphanumSort( allSectionsIds );
restrictedSectionsIds = _fngAlphanumSort( restrictedSectionsIds );
var $firstSectionItemInMenu = $fng('#nav-drawer .list-group-item[data-type="30"]').parents('li:eq(0)');
var $restrictedSectionLinkItemTemplate = $firstSectionItemInMenu.clone()
.find('a.list-group-item').attr('href','').attr('_fng-title','').addClass('_fng-restricted-section-menu-item')
.find('.media').append('Accès restreint')
.find('.media-body').html('')
.parents('li');
for(var i=0; i
\
CONSEILS PRATIQUES
\
Avant de commencer votre formation, assurez-vous d’être au calme. Nous vous conseillons de vous identifier en indisponible, d’éteindre votre téléphone et de vous isoler dans un lieu confortable.
\
N\'oubliez pas de télécharger pour chacun de vos modules le programme ci-dessous qui sera à conserver avec votre attestation.
\
Nous vous invitons, également, à prendre de quoi noter.
\
Bonne formation !
\
\
');
// Insert course progression info box
$fng('.accordion.moofactory #section-0 .content .clearfix').first().removeClass('clearfix');
$fng('.accordion.moofactory #section-0 div.right.side').append('');
var $courseimageEL = $fng('.pagelayout-course .headerbkg .withimage');
$courseimageEL = ( ($courseimageEL.length==0) ? undefined : $courseimageEL );
if ( $courseimageEL != undefined ) {
var courseimageurl = $fng('.pagelayout-course .headerbkg .withimage').css('background-image').replace('url(', '').replace(')', '').replace(/\"/gi, "");
$fng('#_fng-coursedetails-block')
// Ajoute l'image du cours
.append('')
// Ajoute la barre de progression
.append($fng('.studentdashboard .studentprogress').clone());
}
// Supprime le mot "Complet" de la barre de progression
$fng('.pagelayout-course #_fng-coursedetails-block .studentprogress .progress-bar .small strong').each(function(el, i) { $fng(this).text($fng(this).text().replace('Complet', '')); });
$fng('.pagelayout-course #_fng-coursedetails-block')
// Move stat block vers le block to course detail
.append($fng('.course-content .statcontainer'))
// Move "Votre progression (?)" lien d'aide vers le block to course detail
.append($fng('.pagelayout-course #completionprogressid'));
// Si "0 ACTIVITES A VALIDER", on cache les stats stagiaire
if ( $fng('.statcontainer .stat.student .nombre').text() == '0' )
$fng('.statcontainer').hide();
// Remplace texte "Votre progression (?)" par "Aide sur Coches d'achèvement"
$fng('.pagelayout-course #completionprogressid').contents().first().replaceWith("Aide sur Coches d'achèvement");
// Finalement on cache cette portion puisqu'on réplique les (?) au niveau de chaque boite à cocher
$fng('.pagelayout-course #completionprogressid').hide();
// Remplace l'icone H5P par une icone basique
$fng('.pagelayout-course .activity.hvp.modtype_hvp a img.activityicon').each(function() { $fng(this).attr('src', '/theme/image.php/moofactory/core/1621353922/f/pdf'); });
// Correctif pour le POPIN d'activité qui ne se dimensionne pas correctement au chargement des activités H5P:
// Explication du probleme :
// le CSS height des élements .modal-dialog .modal-body et .modal-dialog .modal-body iframe#activityframe sont réglés dynamiquement au chargement basé sur le height du document chargé dans la iframe.
// Si le height du doc contenu dans la iframe change plus tard, cette valeur n'est pas répercutée sur les heights des deux éléments cités plus haut.
// On note que nous avons le même problème sur d’autres contenus H5P qui sont directement « grands » dès le départ.
// Mon analyse est que les docs H5P doivent se charger en plusieurs phases et déclenchent un event « loaded » alors que leur contenu n’est pas encore affiché en pleine hauteur. Si le script du popin se
// base sur l’event « loaded » de la iframe alors il récup une mauvaise hauteur non finale dans ce cas.
// J’ai remarqué qu’un simple redimensionnement de la largeur de la fenêtre du navigateur déclenchait une correction des height du popin. Donc en déclenchant programmatiquement un event window resize
// (de type : window.dispatchEvent(new Event('resize')); ) cela déclenche la correction de la taille du popin.
// En programmant ce déclanchement à répétition une fois par toutes les secondes (par exemple) et pendant 1 minute quand un stagiaire clique sur un lien d’activité H5P on règle les problèmes :
// - du chargement du contenu qui se dimensionne en plusieurs phases
// - d’un écran d’intro « petit » en donnant le temps au stagiaire de cliquer sur le bouton « démarrer »
$fng('.pagelayout-course .activity.hvp.modtype_hvp a').on( 'click', function() {
_fng_setIntervalX( function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: H5P Activity was clicked, monitoring H5P content\'s height to adjust popin modal height (each 2 sec for 1 min).');
_fng_triggerWindowResizeEvent();
} , 2000/*ms*/, 30/*repetitions*/ );/* toutes les 2 secondes pendant 1 minute */
} );
// CORRECTIF POPIN pour affichage inline des Custom Certificate
$fng('.pagelayout-course .activity.customcert.modtype_customcert a').on( 'click', function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Custom Cert : Button "Afficher le certificat" was clicked...');
_fng_setIntervalX( function() {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Custom Cert : ...resizing popin contents\' height to match Windows\'s inner height (each 2 sec for 30 sec).');
$fng('body#page-course-view-moofactory.modal-open #activityframe').css('height', 'calc('+$fng(window).innerHeight()+'px - 6rem)');
$fng('body#page-course-view-moofactory.modal-open div.modal-body').css('height', 'calc('+$fng(window).innerHeight()+'px - 4.5rem)');
} , 2000/*ms*/, 15/*repetitions*/ );/* toutes les 2 secondes pendant 30 secondes */
} );
/* NOT NEEDED ANYMORE SINCE MOODLE 3.11 (les cases à cocher ont été remplacée par des boutons)
// PERSONALISATION DES CASES à COCHER (START)
// Remplace le graphique pour les cases auto non remplies
$fng('img[src*="completion-auto-n"], img[src*="completion-auto-enabled"]', '.pagelayout-course .course-content .section .activity .actions').attr( 'src', '/_fng/img/completion-auto-n.png' );
// After each coche d'achèvement, ajoute un texte "Marquer cette étape comme terminée"
$fng('img[src*="completion-manual"]').within('.pagelayout-course .course-content .section .activity .actions').parents('.pagelayout-course .course-content .section .activity .actions').append(' Marquer cette étape comme terminée');
// Append the ?HELP button (ONLY WORKS IN STAGIAIRE MODE because '#completionprogressid a.btn' does not exist in admin mode)
$fng('.pagelayout-course .course-content .section .activity .actions').append( $fng('#completionprogressid a.btn').clone( true ) );
// Déplace le carré à cocher tout en bas de l'activité (après les éventuelles div.contentafterlink)
$fng('.activity .actions').each(function (i, el) { $fng(this).moveDown(); $fng(this).moveDown(); } );
// PERSONALISATION DES CASES à COCHER (END)
*/
// Emulation de restriction d'accès du Custom Certificate
/*
$fng('.activity.customcert').each( function () {
var $certLinkEl = $fng('.activityinstance a.aalink', $fng(this) );
var $newEl = undefined;
// If Cert Link is active
if ( $certLinkEl.length > 0 ) {
$fng('.activityinstance a.aalink', $fng(this) ).attr( 'href', '#' ).removeAttr( 'href' ).removeAttr( 'onclick' ).addClass('dimmed dimmed_text').removeClass('aalink').changeElementType('div');
}
$newEl = $fng('.activityinstance div.dimmed', $fng(this) );
var $parentParentDiv = $newEl.parent('.activityinstance').parent('div');
var dureeMinStr = '3h 30min';
var timespent = $fng('#_fng-coursedetails-block .stat #timespent').text();
$parentParentDiv.append( $fng('
Accès restreint Non disponible à moins que : Votre temps passé dans cette formation soit d\'au moins '+dureeMinStr+' (vous avez passé '+timespent+').
') );
} );
*/
}
// In Test activity, close the left pane that is open by default
/*
if ($fng('body').is('#page-mod-quiz-attempt')) {
$fng('body').removeClass('drawer-open-right');
}
*/
/*
$fng('body').append( $fng(''));
$(document).on("keypress", function(e) {
if ( e.ctrlKey && ( e.which === 29 ) ) { // Ctrl+$
$fng('#_fng-debug-timing').toggle();
}
});
setInterval( function() {
var sBuf = '';
if ( document.hidden != _fng_gPageHidden ) {
_fng_gPageHidden = !_fng_gPageHidden;
sBuf+='Visible:'+!_fng_gPageHidden+' ';
}
if ( document.hasFocus() != _fng_gPageFocused ) {
_fng_gPageFocused = !_fng_gPageFocused;
sBuf+='Focused:'+_fng_gPageFocused;
}
if (sBuf != '') {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Win vis state changed: ' + sBuf);
}
$fng('#_fng-debug-timing').html(
'Visible:'+!_fng_gPageHidden+' Focused:'+_fng_gPageFocused+' '
+' intelliboardTime:'+intelliboardTime+''
+' intelliboardCounter:'+intelliboardCounter+' '
+'intelliboardAjaxCounter:'+intelliboardAjaxCounter+''
+' intelliboardAjax:'+intelliboardAjax+' '
+' intelliboardPeriod:'+intelliboardPeriod+''
+' intelliboardMedia():'+intelliboardMedia()
);
}, 1000);
*/
}
// -------------------
// COURSE PAGE (END)
// -------------------
// -------------------------------------
// COURSE COMPLETION REPORT PAGE (START)
// -------------------------------------
// PATCH the Excel export link by pointing it to our patched version of report/completion/index.php located in /_fng/moodlepatches/
$fng('body#page-report-completion-index .export-actions a[href*="format=excelcsv"]')
.each( function() {
$fng(this).attr( 'href', $fng(this).attr( 'href' ).replace( '/report/completion/', '/_fng/moodlepatches/report/completion/' ) );
} );
// -----------------------------------
// COURSE COMPLETION REPORT PAGE (END)
// -----------------------------------
console.log((new Date().getTime()-_fng_zerotime) + ' JM: Executing jQueryUI related instructions...');
// Add tooltip to menu's elements and mark them for applying jQury UI (by adding ._fng-addtooltip class)
$fng('a.list-group-item-action').each(function(i, el) {
$fng(this).addClass('_fng-addtooltip');
$fng(this).attr('title', '');
$fng(this).attr('_fng-title', $fng('.media-body', this).text());
});
// Setup tooltips
$fng('._fng-addtooltip').tooltip();
$fng('._fng-addtooltip').tooltip('option', 'content', function() { return $fng(this).attr('_fng-title'); });
// Add handle to menu button to enable/disable tooltip
$fng('button[aria-controls="nav-drawer"]').on('click', function() { setTimeout(_fng_handleMenuTooltipState, 100); });
_fng_handleMenuTooltipState();
$fng('#toggleFullscreen a').on('click', function() {
$fng('#toggleFullscreen').toggleClass('collapsefs');
_fng_toggleFullscreen();
});
});
function injectAkuterHistoryLinkInPageIfNeeded()
{
if ( _fngdata.profile.fng_akuterid == 0 )
return;
var akuterHistoryButtonHtml = '';
$fng('.card-text:first .footer', '.block_moofactory_course_progress, .block_moofactoryfng_course_progress').append( akuterHistoryButtonHtml );
$fng('#_fng-akuterhistorybutton').click(function() {
$fng('FERMER [X] \
')
.appendTo('body');
$fng('body').css({overflow: 'hidden'});
return false;
});
}
function _fng_openstudentcoursedashboard() {
// Must use native $ and not $fng because click event is bound to native jQuery lib
window.jQuery('a[href="#studentdashslider"]').click();
}
function _fng_handleMenuTooltipState() {
var $b = $fng('button[aria-controls="nav-drawer"]');
var menuIsExpanded = ($b.attr('aria-expanded') == 'true');
// console.log( (new Date().getTime()-_fng_zerotime) + ' JM: expanded? ' + menuIsExpanded );
if (menuIsExpanded)
$fng('._fng-addtooltip')
.not($fng('a.list-group-item-action[data-key="home"], a.list-group-item-action[data-key="myhome"]', '#nav-drawer .mt-1, #nav-drawer .my-1'))
.tooltip('disable');
else
$fng('._fng-addtooltip')
.attr('title', '').tooltip('enable');
}
/**
* Toggle fullscreen function who work with webkit and firefox.
*/
function _fng_toggleFullscreen(event) {
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)
document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen ? document.webkitExitFullscreen() : document.msExitFullscreen && document.msExitFullscreen();
else {
var t = $fng('html')[0];
t.requestFullscreen ? t.requestFullscreen() : t.mozRequestFullScreen ? t.mozRequestFullScreen() : t.webkitRequestFullscreen ? t.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT) : t.msRequestFullscreen && t.msRequestFullscreen();
}
}
function _fng_setIntervalX(callback, delay, repetitions)
{
var x = 0;
var intervalID = window.setInterval(function () {
callback();
if (++x === repetitions) {
window.clearInterval(intervalID);
}
}, delay);
}
function _fng_UrlParamsHasValue( paramName )
{
return _fng_gURL_PARAMS[paramName] != undefined && _fng_gURL_PARAMS[paramName] != "";
}
function _fng_triggerWindowResizeEvent()
{
if (typeof(Event) === 'function') {
// modern browsers
window.dispatchEvent(new Event('resize'));
} else {
// for IE and other old browsers
// causes deprecation warning on modern browsers
var evt = window.document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(evt);
}
}
function _fng_scrollBarWidth()
{
var originalOverflow = $fng("html").css("overflow");
$fng("html").css("overflow", 'hidden');
var width = $fng("html").width();
$fng("html").css("overflow", 'scroll');
width -= $fng("html").width();
if ( !width ) {
width = document.body.offsetWidth - document.body.clientWidth;
$fng("body").css("overflow", '');
}
$fng("html").css( 'overflow', originalOverflow );
return width;
}
function _fng_isLeftMenuOpen()
{
return ! $fng('#nav-drawer').is('.closed');
}
function _fng_isLoginPage()
{
return $fng('body').is('#page-login-index') || $fng('body').is('#page-login-signup');
}
function _fng_isLoginPageChangePassword()
{
return $fng('body').is('#page-login-change_password');
}
function _fng_isForgotPasswordPage()
{
return $fng('body').is('#page-login-forgot_password');
}
function _fng_isUserProfilePage()
{
return $fng('body').is('#page-user-profile');
}
function _fng_isLoginPageWithActiveSessionLogoutConfirmation()
{
return _fng_isLoginPage() && $fng( '#notice .singlebutton form[action*="logout.php"]' ).length > 0;
}
function _fng_isLoginPageWithExpiredSessionNotice()
{
// Check for presence of notice saying
// "Votre session est échue. Veuillez vous reconnecter."
// or "Your session has timed out. Please log in again."
return _fng_isLoginPage()
&& $fng( '[role="alert"]:contains("échue"), [role="alert"]:contains("timed out")', 'body.notloggedin .loginerrors' ).length > 0;
}
function _fng_isDashboardPage()
{
return $fng('body').is('#page-my-index');
}
function _fng_isSitePage()
{
return $fng('body').is('#page-site-index');
}
function _fng_isCoursePages()
{
return $fng('body').is('.format-moofactory:not(#page-enrol-index)');
}
function _fng_isCourseMainPage()
{
return $fng('body').is('#page-course-view-moofactory');
}
function _fng_isCatalogVipIndexPage()
{
return $fng('body').is('#page-course-index-category');
}
function _fng_isCatalogVipEnrolPage()
{
return $fng('body').is('#page-enrol-index');
}
function _fng_isUserUploadPage()
{
return $fng('body').is('#page-admin-tool-uploaduser-index') || $fng('body').is('#page-admin-local-moofactory_organisation-users-uploaduser-index');
}
function _fng_isCustomdocumentPage()
{
return $fng('body').is('#page-mod-customdocument-view');
}
function _fng_currentUserOrgaRacine()
{
return _fng_orga == 'racine';
}
// Convert a string with format "1j 3h 5min 35sec" to number of seconds
function _fngParseDureeStrToSec( dureeStr )
{
var ar = dureeStr.split(' ');
var sec = 0;
for (var i=0; i=48 && i <= 57));
if (m !== n) {
this[z][++y] = "";
n = m;
}
this[z][y] += j;
}
}
this.sort(function(a, b) {
for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
if (caseInsensitive) {
aa = aa.toLowerCase();
bb = bb.toLowerCase();
}
if (aa !== bb) {
var c = Number(aa), d = Number(bb);
if (c == aa && d == bb) {
return c - d;
} else return (aa > bb) ? 1 : -1;
}
}
return a.length - b.length;
});
for (var z = 0; z < this.length; z++)
this[z] = this[z].join("");
}
*/
function _fngAlphanumSort( theArray, caseInsensitive )
{
for (var z = 0, t; t = theArray[z]; z++) {
theArray[z] = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >=48 && i <= 57));
if (m !== n) {
theArray[z][++y] = "";
n = m;
}
theArray[z][y] += j;
}
}
theArray.sort(function(a, b) {
for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
if (caseInsensitive) {
aa = aa.toLowerCase();
bb = bb.toLowerCase();
}
if (aa !== bb) {
var c = Number(aa), d = Number(bb);
if (c == aa && d == bb) {
return c - d;
} else return (aa > bb) ? 1 : -1;
}
}
return a.length - b.length;
});
for (var z = 0; z < theArray.length; z++)
theArray[z] = theArray[z].join("");
return theArray;
}
function _fngIsIE()
{
const ua = window.navigator.userAgent; //Check the userAgent property of the window.navigator object
const msie = ua.indexOf('MSIE '); // IE 10 or older
const trident = ua.indexOf('Trident/'); //IE 11
return (msie > 0 || trident > 0);
}
/*
Takes as param a "yyyy-mm-dd" string or a long value (unix timestamp in millis)
*/
function _fngGetDateDebut( dateStringOrLong )
{
return new XDate( dateStringOrLong ).setHours(0).setMinutes(0).setSeconds(0);
}
/*
Takes as param a "yyyy-mm-dd" string or a long value (unix timestamp in millis)
*/
function _fngGetDateFin( dateStringOrLong )
{
return new XDate( dateStringOrLong ).setHours(23).setMinutes(59).setSeconds(59);
}
function _fngGetOrgaFromUserSession()
{
if ( _fngdata!=undefined && _fngdata.profile!=undefined && _fngdata.profile.Organisation!=undefined )
return _fngdata.profile.Organisation.toLowerCase();
return undefined;
}
function _fngInitVIP_ORGA()
{
// For each orga defined in _fng_VIP_ORGA, transform "yyyy-mm-jj" to real date object and set time to appropriate values
for ( viporg in _fng_VIP_ORGA ) {
if ( _fng_VIP_ORGA[viporg].fng_vip1datedebut == undefined || _fng_VIP_ORGA[viporg].fng_vip1datedebut == 0 )
_fng_VIP_ORGA[viporg].fng_vip1datedebut = 0;
else
_fng_VIP_ORGA[viporg].fng_vip1datedebut = _fngGetDateDebut( _fng_VIP_ORGA[viporg].fng_vip1datedebut );
if ( _fng_VIP_ORGA[viporg].fng_vip1datefin == undefined || _fng_VIP_ORGA[viporg].fng_vip1datefin == 0 )
_fng_VIP_ORGA[viporg].fng_vip1datefin = 0;
else
_fng_VIP_ORGA[viporg].fng_vip1datefin = _fngGetDateFin( _fng_VIP_ORGA[viporg].fng_vip1datefin );
}
}
function _fngIsVIP()
{
/*
if ( _fngdata.profile==undefined || _fngdata.profile.fng_attributs==undefined )
return false;
// Retrieve user attribute data
var a = _fngdata.profile.fng_attributs;
// Clean and normalize attribute string before spliting
a = a.replace(/}(.[^{}]*){/gi, '}{');
// Split and clean each attribute
a = a.split('}{');
a = a.map(item => {
return item.replace(/}$/gi, '').replace(/^{/gi, '');
})
// We now have an array like ['VIP#2022-01-31#2022-01-06', 'permission2', 'permission3']
var vip_permissions = a.filter(element => { if (element.startsWith('VIP') ) { return true; } });
if (vip_permissions.length != 0 ) {
// PARSE VIP PERMISSION (ONLY THE FIRST INSTANCE)
var vip_els = vip_permissions[0].split('#');
vip_els.enddate = vip_els[1];
vip_els.startdate = vip_els[2];
if ( vip_els.enddate == undefined )
vip_els.enddate = '3000-12-31';
if ( vip_els.startdate == undefined )
vip_els.startdate = '1970-01-01';
vip_els.enddate = new XDate( vip_els.enddate ).setHours(23).setMinutes(59).setSecondes(59);
vip_els.startdate = new XDate( vip_els.startdate ).setHours(0).setMinutes(0).setSecondes(0);
console.log(vip_els.enddate);
}
*/
/*
var now = new XDate();
var p = _fngdata.profile;
var vipdata = {};
if ( p==undefined || p.vip==undefined )
return false;
if ( p.vip!="1" )
return false;
if ( p.vipenddate!=undefined ) {
vipdata.vipenddate = new XDate( p.vipenddate*1000 ).setHours(23).setMinutes(59).setSeconds(59);
if ( now.getTime() > vipdata.vipenddate.getTime() )
return false;
}
if ( p.vipstartdate!=undefined ) {
vipdata.vipstartdate = new XDate( p.vipstartdate*1000 ).setHours(0).setMinutes(0).setSeconds(0);
if ( now.getTime() < vipdata.vipstartdate.getTime() )
return false;
}
vipdata.vipcatalog = p.vipcatalog;
// console.log(p.vip, p.vipenddate, p.vipstartdate );
return vipdata;
*/
var now = new XDate();
const orgaFromSession = _fngGetOrgaFromUserSession(); /* Don't use _fng_orga because it may contain orga from URL param (ex: on login page where we specify an orga url) */
var vipdata = undefined;
/* Build vipdata object by merging rights from _fng_VIP_ORGA and _fngdata.profile.vip*** data */
/* Gather data at orga level... */
if ( _fng_VIP_ORGA[orgaFromSession] != undefined && _fng_VIP_ORGA[orgaFromSession].fng_vip1acces != undefined ) {
var p = _fng_VIP_ORGA[orgaFromSession];
if ( p.fng_vip1acces == _FNG_VIPACCESS_NOTALLOWED )
return false;
if ( p.fng_vip1acces != _FNG_VIPACCESS_NOTDEFINED ) {
vipdata = {};
vipdata.catName = p.fng_vip1acces;
vipdata.catId = _fng_VIP_CATALOG_COURSE_CATEGORIES[vipdata.catName];
vipdata.vip1datedebut = p.fng_vip1datedebut;
vipdata.vip1datefin = p.fng_vip1datefin;
}
}
p = _fngdata.profile;
/* If nothing allowed was defined at orga level AND nothing allowed is defined at user level => return false*/
if ( vipdata==undefined )
if ( p==undefined || p.fng_vip1acces==undefined || p.fng_vip1acces == _FNG_VIPACCESS_NOTDEFINED || p.fng_vip1acces == _FNG_VIPACCESS_NOTALLOWED )
return false;
/* If at user level, vip is not allowed => return false */
if ( p!=undefined && p.fng_vip1acces == _FNG_VIPACCESS_NOTALLOWED )
return false;
/* If a vip catalog is defined at user level, override with it*/
if ( p.fng_vip1acces != _FNG_VIPACCESS_NOTDEFINED ) {
if ( vipdata==undefined)
vipdata = {};
vipdata.catName = p.fng_vip1acces;
vipdata.catId = _fng_VIP_CATALOG_COURSE_CATEGORIES[vipdata.catName];
/* If a vip date debut is defined at user level, override with it*/
if ( p.fng_vip1datedebut!=undefined && p.fng_vip1datedebut!=0 )
vipdata.vip1datedebut = _fngGetDateDebut( p.fng_vip1datedebut*1000 );
/* If a vip date fin is defined at user level, override with it*/
if ( p.fng_vip1datefin!=undefined && p.fng_vip1datefin!=0 )
vipdata.vip1datefin = _fngGetDateFin( p.fng_vip1datefin*1000 );
}
/* Now, check access rights based on merged vipdata data */
if ( vipdata.vip1datedebut!=undefined && vipdata.vip1datedebut!=0 ) {
if ( now.getTime() < vipdata.vip1datedebut.getTime() )
return false;
}
if ( vipdata.vip1datefin!=undefined && vipdata.vip1datefin!=0 ) {
if ( now.getTime() > vipdata.vip1datefin.getTime() )
return false;
}
return vipdata;
}
/* 20230809: In VIP Catalog Index page, this will hide courses that are of type BABYLON for users that have
their custom field "fng_vip1_interdire_formations_bab" checked
20240906: Changed behaviour: Instead of allowing/disallowing Babylon courses based on a single flag,
we now use VIP Modes to determine course visibility:
- VIP2023 mode: Hides all Babylon courses (similar to previous behavior)
- VIP2024 mode: Shows specific Babylon courses (defined in _fng_VIP_IDS_OF_BABYLON_COURSES_TO_ALLOW_IN_VIP2024)
and hides the rest
- VIP2025 mode: Shows all Babylon courses except some specific ESSOR & BABYLON courses
(defined in _fng_VIP_IDS_OF_ESSOR_AND_BABYLON_COURSES_TO_PREVENT_IN_VIP2025)
This new approach allows for more flexible and year-specific course visibility rules.
*/
function _fngCatalogVipIndexPageHideBabylonCoursesIfRequired()
{
const vipMode = _fngdata.profile.fng_vip1mode;
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": Applying VIP mode ' + vipMode);
$fng('#page-course-index-category .category-course-list-all figure.card .card-footer .btn.coursestyle2btn a').each(function(el, i) {
const courseId = _fngGetUrlVars($fng(this).attr('href')).id * 1;//convert string to int
const $cardWrapper = $fng(this).parents('.card-container').parent('div');
$cardWrapper.attr('data-fng_courseid', courseId);
let shouldHide = false;
switch(vipMode) {
case "2023":
shouldHide = _fng_VIP_IDS_OF_BABYLON_COURSES.includes(courseId);
break;
case "2024":
shouldHide = _fng_VIP_IDS_OF_BABYLON_COURSES.includes(courseId) &&
!_fng_VIP_IDS_OF_BABYLON_COURSES_TO_ALLOW_IN_VIP2024.includes(courseId);
break;
case "2025":
shouldHide = _fng_VIP_IDS_OF_ESSOR_AND_BABYLON_COURSES_TO_PREVENT_IN_VIP2025.includes(courseId);
break;
}
if (shouldHide) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": ...hiding [' + courseId + '] ' + $fng('.card-title', $cardWrapper).text());
$cardWrapper.hide();
}
});
}
/*function _fngCatalogVipIndexPageHideBabylonCoursesIfRequired()
{
// If user has vip option "interdire_formations_babylon" checked, we hide
if (_fngdata.profile.fng_vip1_interdire_formations_bab=="1") {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": _fngCatalogVipIndexPageHideBabylonCoursesIfRequired() User not eligible for Babylon courses. Hiding them...');
$fng('#page-course-index-category .category-course-list-all figure.card .card-footer .btn.coursestyle2btn a').each( function(el, i) {
var courseId = _fngGetUrlVars( $fng(this).attr('href') ).id*1; //convert string to int
var $cardWrapper = $fng(this).parents('.card-container').parent('div');
$cardWrapper.attr( 'data-fng_courseid', courseId );
if ( _fng_VIP_IDS_OF_BABYLON_COURSES.includes( courseId ) ) {
if ( $cardWrapper.is(":visible") ) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": ...hiding ' + $fng('.card-title', $cardWrapper).text() );
$cardWrapper.hide();
}
}
} );
} else {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP": _fngCatalogVipIndexPageHideBabylonCoursesIfRequired() User eligible for Babylon courses. We keep them.');
}
}*/
/* 20230809: In VIP Catalog course enrol page, if this is a course of type BABYLON and current user has its
custom field "fng_vip1_interdire_formations_bab" checked, this will prevent access to the enrol page
by redirecting to the dashboard
20240906: Changed behaviour: Instead of allowing/disallowing Babylon courses based on a single flag,
we now use VIP Modes to determine course enrollment access:
- VIP2023 mode: Prevents enrollment in all Babylon courses (similar to previous behavior)
- VIP2024 mode: Allows enrollment in specific Babylon courses
(defined in _fng_VIP_IDS_OF_BABYLON_COURSES_TO_ALLOW_IN_VIP2024) and prevents the rest
- VIP2025 mode: Allows enrollment in all Babylon courses but prevents enrollment in specific ESSOR courses
(defined in _fng_VIP_IDS_OF_ESSOR_AND_BABYLON_COURSES_TO_PREVENT_IN_VIP2025)
This new approach aligns with the catalog visibility rules and provides consistent access control
*/
function _fngCatalogVipEnrolPagePreventBabylonCoursesIfRequired()
{
const vipMode = _fngdata.profile.fng_vip1mode;
const courseId = _fngGetUrlVars(document.location.href).id * 1; //convert string to int
let shouldPrevent = false;
switch(vipMode) {
case "2023":
shouldPrevent = _fng_VIP_IDS_OF_BABYLON_COURSES.includes(courseId);
break;
case "2024":
shouldPrevent = _fng_VIP_IDS_OF_BABYLON_COURSES.includes(courseId) &&
!_fng_VIP_IDS_OF_BABYLON_COURSES_TO_ALLOW_IN_VIP2024.includes(courseId);
break;
case "2025":
shouldPrevent = _fng_VIP_IDS_OF_ESSOR_AND_BABYLON_COURSES_TO_PREVENT_IN_VIP2025.includes(courseId);
break;
}
if (shouldPrevent) {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP Enrol": Preventing access to course ' + courseId);
document.location.href = '/';
} else {
console.log((new Date().getTime()-_fng_zerotime) + ' JM: In page "Catalogue VIP Enrol": Allowing access to course ' + courseId);
}
}
/*function _fngCatalogVipEnrolPagePreventBabylonCoursesIfRequired()
{
if (_fngdata.profile.fng_vip1_interdire_formations_bab=="1") {
var courseId = _fngGetUrlVars(document.location.href).id*1; //convert string to int
if (_fng_VIP_IDS_OF_BABYLON_COURSES.includes( courseId ))
document.location.href = '/';
}
}*/
window.g_FNG_SCRIPT_LOADED = true;
console.log((new Date().getTime()-_fng_zerotime) + ' JM: END OF included script _fng_main_inject.js');