Browse Source

merge master

raphael 3 years ago
parent
commit
d03554c310
100 changed files with 5439 additions and 1443 deletions
  1. 19
    5
      .env.example
  2. 10
    4
      .env.test
  3. 65
    18
      .gitignore
  4. 2
    2
      .vscode/settings.json
  5. 97
    2
      README.md
  6. 98
    121
      assets/exclusive/js/back-office/form_library_utility.js
  7. 0
    18
      assets/exclusive/js/back-office/init_back_office.js
  8. 1
    0
      assets/exclusive/js/back-office/init_back_office_forum.js
  9. 277
    0
      assets/exclusive/js/back-office/init_diary.js
  10. 6
    1
      assets/exclusive/js/back-office/learning_path/learning_path_edit.js
  11. 130
    135
      assets/exclusive/js/back-office/learning_path/learning_path_editor.js
  12. 373
    0
      assets/exclusive/js/back-office/learning_path/learning_path_editor_sequence_summary.js
  13. 45
    2
      assets/exclusive/js/back-office/offer/menu_offer.js
  14. 108
    34
      assets/exclusive/js/back-office/offer/offer_edit.js
  15. 9
    0
      assets/exclusive/js/back-office/offer/offer_import_learning_path.js
  16. 59
    0
      assets/exclusive/js/back-office/offer/offer_import_session.js
  17. 165
    0
      assets/exclusive/js/back-office/offer/offer_utility.js
  18. 0
    1
      assets/exclusive/js/back-office/person/tab/notices.js
  19. 31
    12
      assets/exclusive/js/back-office/session/create/menu_session.js
  20. 267
    254
      assets/exclusive/js/back-office/session/create/session_edit.js
  21. 137
    0
      assets/exclusive/js/back-office/session/create/session_place.js
  22. 135
    40
      assets/exclusive/js/back-office/session/create/session_utility.js
  23. 45
    60
      assets/exclusive/js/back-office/session/follow/edit.js
  24. 14
    17
      assets/exclusive/js/back-office/setting/user/create.js
  25. 19
    19
      assets/exclusive/js/back-office/utilities/coworker.js
  26. 19
    19
      assets/exclusive/js/back-office/utilities/person.js
  27. 229
    0
      assets/exclusive/js/back-office/utilities/program.js
  28. 59
    7
      assets/exclusive/js/back-office/utilities/utility.js
  29. 178
    0
      assets/exclusive/js/catalog/init_catalog_payment.js
  30. 56
    8
      assets/exclusive/js/catalog/login_subscribe.js
  31. 24
    5
      assets/exclusive/js/init_activity-player.js
  32. 24
    17
      assets/exclusive/js/init_catalog_offer.js
  33. 2
    2
      assets/exclusive/js/init_learning_space.js
  34. 1
    0
      assets/exclusive/js/init_learning_space_forum.js
  35. 3
    1
      assets/exclusive/js/init_learning_space_session_page.js
  36. 0
    190
      assets/exclusive/js/init_program.js
  37. 76
    106
      assets/exclusive/js/scorm12-api.js
  38. 53
    0
      assets/exclusive/js/scormEngine/ajax_callback.js
  39. 1
    0
      assets/exclusive/js/utilities/dropzone.js
  40. 13
    1
      assets/shared/build/global/build_global-images.js
  41. 15
    0
      assets/shared/images/statics/email_check.svg
  42. 21
    0
      assets/shared/images/statics/error.svg
  43. 19
    0
      assets/shared/images/statics/icon-session-fixed.svg
  44. 25
    0
      assets/shared/images/statics/icon-session-open.svg
  45. 39
    0
      assets/shared/images/statics/icons/follow-diary.svg
  46. 57
    0
      assets/shared/images/statics/icons/home-follow-diary.svg
  47. 4
    4
      assets/shared/images/statics/rules-comming.svg
  48. 6
    6
      assets/shared/images/statics/rules-completed.svg
  49. 7
    2
      assets/shared/images/statics/rules-worked.svg
  50. 43
    0
      assets/shared/images/statics/session-fixe.svg
  51. 49
    0
      assets/shared/images/statics/session-permanente.svg
  52. 17
    0
      assets/shared/images/statics/source_catalog.svg
  53. 22
    0
      assets/shared/images/statics/success.svg
  54. 18
    25
      assets/shared/js/classes/PHXRemoteSelect.js
  55. 27
    129
      assets/shared/js/init/init.js
  56. 11
    7
      assets/shared/js/init/init_coworker-search.js
  57. 13
    18
      assets/shared/js/init/init_create-from-library.js
  58. 3
    34
      assets/shared/js/init/init_modals.js
  59. 25
    0
      assets/shared/js/plugins/phxPlugin.js
  60. 11
    0
      assets/shared/scss/back-office/import-back-office.scss
  61. 5
    1
      assets/shared/scss/back-office/import-global-back-office.scss
  62. 1
    0
      assets/shared/scss/back-office/variables-back-office.scss
  63. 2
    1
      assets/shared/scss/import-catalog.scss
  64. 1
    1
      assets/shared/scss/import-learning-space.scss
  65. 32
    0
      assets/shared/scss/theme-phx/back-office/compare.scss
  66. 169
    0
      assets/shared/scss/theme-phx/back-office/custom-diary.scss
  67. 71
    0
      assets/shared/scss/theme-phx/back-office/follow-session.scss
  68. 4
    0
      assets/shared/scss/theme-phx/back-office/forum-session.scss
  69. 308
    10
      assets/shared/scss/theme-phx/back-office/global.scss
  70. 225
    25
      assets/shared/scss/theme-phx/back-office/learning-path-editor.scss
  71. 2
    1
      assets/shared/scss/theme-phx/back-office/login-page.scss
  72. 43
    0
      assets/shared/scss/theme-phx/back-office/note.scss
  73. 38
    1
      assets/shared/scss/theme-phx/back-office/offer.scss
  74. 1
    1
      assets/shared/scss/theme-phx/back-office/program-training.scss
  75. 77
    6
      assets/shared/scss/theme-phx/back-office/session.scss
  76. 459
    42
      assets/shared/scss/theme-phx/catalog/global.scss
  77. 215
    0
      assets/shared/scss/theme-phx/catalog/toastr.scss
  78. 2
    1
      assets/shared/scss/theme-phx/components/button.scss
  79. 78
    4
      assets/shared/scss/theme-phx/learning-space/activity-page.scss
  80. 1
    1
      assets/shared/scss/theme-phx/learning-space/forum.scss
  81. 91
    2
      assets/shared/scss/theme-phx/learning-space/global.scss
  82. 2
    2
      assets/shared/scss/theme-phx/learning-space/login-page.scss
  83. 10
    4
      assets/shared/scss/theme-phx/learning-space/nav.scss
  84. 13
    4
      assets/shared/scss/theme-phx/learning-space/session-page.scss
  85. 122
    1
      assets/shared/scss/theme-phx/learning-space/sessions-page.scss
  86. 6
    0
      assets/shared/scss/theme-phx/modules/forms.scss
  87. 47
    9
      assets/shared/scss/variables-catalog.scss
  88. 16
    0
      assets/shared/scss/variables-learning-space.scss
  89. 6
    0
      bin/dev/.settings
  90. 5
    0
      bin/dev/docker-compose-local/clearCache.sh
  91. 5
    0
      bin/dev/docker-compose-local/composerInstall.sh
  92. 18
    0
      bin/dev/docker-compose-local/composerUpdate.sh
  93. 11
    0
      bin/dev/docker-compose-local/setup.sh
  94. 16
    0
      bin/dev/docker-compose-local/setupData.sh
  95. 5
    0
      bin/dev/docker-compose/clearCache.sh
  96. 5
    0
      bin/dev/docker-compose/composerInstall.sh
  97. 18
    0
      bin/dev/docker-compose/composerUpdate.sh
  98. 11
    0
      bin/dev/docker-compose/setup.sh
  99. 16
    0
      bin/dev/docker-compose/setupData.sh
  100. 0
    0
      bin/dev/docker-local/.settings

+ 19
- 5
.env.example View File

@@ -1,18 +1,32 @@
1 1
 
2
+# environnement de travail
2 3
 APP_ENV=dev
3 4
 APP_DEBUG=1
4 5
 APP_SECRET="@TODO Choisir une valeur secrète pour ce projet"
5 6
 
6
-APP_URL_PREFIX="/phoenix"
7
+# base de donnée
8
+DATABASE_URL="mysql://root:logipro@mysql/[nom_de_la_bd]"
7 9
 
8
-APP_HOST="localhost"
10
+# compositions des urls
11
+APP_URL_PREFIX="/phoenix"
12
+APP_HOST="vm"
9 13
 
10
-DATABASE_URL="mysql://root:@localhost/phoenix"
14
+# chemin de compilation des assets
15
+WEBPACK_DEV_PUBLIC_PATH="http://192.168.240.[ip_vm_docker]:3000/phoenix/build"
11 16
 
12
-WEBPACK_DEV_PUBLIC_PATH="/phoenix/build"
17
+# convertisseur pdf distant
18
+DOCX_TO_PDF_CONVERTER_URL="https://unoconv.logipro.com/unoconv/pdf"
13 19
 
20
+# mailer
14 21
 MAILER_HOST="isp15.logipro.com"
15 22
 MAILER_USERNAME="phoenix@logipro.com"
16 23
 MAILER_PASSWORD="phoenix43;"
24
+MAILER_DEV_DESTINARY="example@logipro.com"
25
+MAILER_PORT="25"
26
+MAILER_ENCRYPTION="tls"
17 27
 
18
-MAILER_DEV_DESTINARY="example@logipro.com"
28
+# bundle jupyter
29
+#JUPYTER_URL="http[|s]://[ip/domaine]"
30
+#JUPYTER_API_URL="http[|s]://[ip/domaine]:5000"
31
+#JUPYTER_API_TOKEN="[token_admin_jupyter]"
32
+#JUPYTER_UPLOAD_SIZE_MO=100

+ 10
- 4
.env.test View File

@@ -1,4 +1,10 @@
1
-# define your env variables for the test env here
2
-KERNEL_CLASS='App\Kernel'
3
-APP_SECRET='s$cretf0rt3st'
4
-SYMFONY_DEPRECATIONS_HELPER=999999
1
+    APP_ENV=test
2
+    APP_URL_PREFIX="/phoenix"
3
+    APP_LANGUAGE="fr"
4
+
5
+    # define your env variables for the test env here
6
+    KERNEL_CLASS='Logipro\Phoenix\Kernel\AppKernel'
7
+    APP_SECRET='s$cretf0rt3st'
8
+    SYMFONY_DEPRECATIONS_HELPER=999999
9
+
10
+    DATABASE_TEST_URL="sqlite:///%kernel.project_dir%/var/app.db"

+ 65
- 18
.gitignore View File

@@ -1,30 +1,41 @@
1
+###> Fichiers racine
1 2
 /.env
2 3
 /.buildpath
3 4
 /.svn
4 5
 /.project
5 6
 /.history
6
-/composer.lock
7
+/.vscode/
7 8
 /yarn.lock
8 9
 /yarn-error.log
9 10
 /symfony.lock
10 11
 /package-lock.json
12
+/composer.local.json
13
+###> phpunit/phpunit ###
14
+/phpunit.xml
15
+.phpunit.result.cache
16
+###< phpunit/phpunit ###
17
+###> fin fichiers racine
11 18
 
12
-# tous le types de cache
13
-/var/cach*
14
-/var/log/
15
-/var/uploads/
16
-# fichier readme pour créer le dossier
17
-!/var/uploads/readme
19
+###> dossier bin
20
+bin/update.sh
21
+bin/cron.sh
22
+bin/.phpunit
23
+###< fin dossier bin
18 24
 
19
-/vendor/
25
+###> dossier node_modules
20 26
 /node_modules/
27
+###> fin dossier node_modules
21 28
 
29
+###> dossier config
22 30
 config/.routes.yaml.swp
31
+config/packages/Dev
32
+config/bundles.local.php
33
+###> fin dossier config
23 34
 
35
+###> dossiers public
24 36
 /public/.htaccess
25
-/public/bundles/bazingajstranslation
26
-/public/bundles/kmsfroalaeditor
27
-/public/bundles/fosjsrouting
37
+/public/bundles
38
+!/public/bundles/phx-custom.js
28 39
 
29 40
 # contenu du dossier upload
30 41
 /public/uploads/
@@ -36,20 +47,56 @@ config/.routes.yaml.swp
36 47
 /public/uploads/import/
37 48
 !/public/uploads/import/modeleImportContact.csv
38 49
 
39
-# fichier d'import des contacts
50
+# fichier des modèles de documents
40 51
 !/public/uploads/documents/
41 52
 
42
-# fichier îece jointe des mails
53
+# fichier pîece jointe des mails
43 54
 !/public/uploads/attachments/
44 55
 
56
+# ce dossier est ignoré car il est unique pour chaque plateforme
57
+/public/build/bundles
58
+
59
+###> liip/imagine-bundle ###
60
+/public/media/cache/
61
+###< liip/imagine-bundle ###
62
+
63
+# fichier SCORM
64
+/public/content/
65
+/private/
66
+
67
+###< fin dossier public
68
+
69
+###> dossier src/assets
70
+/assets/exclusive/css/custom-learning-space.css
71
+/assets/exclusive/css/custom-catalog.css
72
+###< fin dossier assets
73
+
74
+###> dossier src/command
75
+/Command/Dev
76
+###< fin dossier command
77
+
45 78
 # contenu du dossier templates/temp
46
-/templates/temp/
79
+/templates/temp/*
47 80
 # fichier readme pour créer le dossier
48 81
 !/templates/temp/readme
49 82
 
50
-/assets/exclusive/css/custom-learning-space.css
51
-/assets/exclusive/css/custom-catalog.css
83
+###> dossier var
84
+# tous le types de cache
85
+/var/
86
+# fichier readme pour créer le dossier
87
+!/var/uploads/readme
88
+###> fin var
52 89
 
53
-bin/update.sh
90
+###> dossier vendor
91
+/vendor/
92
+###> fin dossier vendor
93
+
94
+.phpunit
95
+##### dev
96
+# --- à supprimer en prod
97
+#/public/build
98
+# à supprimer en prod ---
54 99
 
55
-.phpunit
100
+# --- à ajouter en prod
101
+bin/dev
102
+# à ajouter en prod ---

+ 2
- 2
.vscode/settings.json View File

@@ -1,4 +1,4 @@
1 1
 {
2
-    "editor.insertSpaces": false,
3
-    "editor.tabSize": 4
2
+	"editor.tabSize": 4,
3
+    "files.eol": "\n",
4 4
 }

+ 97
- 2
README.md View File

@@ -1,3 +1,98 @@
1
-# Phoenix
1
+# Agora (Infinity)
2 2
 
3
-Projet Phoenix
3
+#Installation
4
+
5
+##Environnement de Dev pour Linux
6
+
7
+Pré-requis:
8
+* poste de travail Linux compatible docker LAMP PHP7.2
9
+* npm installé sur le poste local
10
+* environnement docker installé
11
+* editeur VSCodium
12
+* un répertoire de travail \[work\]
13
+
14
+Récuperer la dernière version sur le git
15
+	cd [work]
16
+	git clone [Url Agora]
17
+
18
+Création du docker NOMDUDOCKER avec :
19
+* volume partagé : \[work\] en local / dossier exposé au web (A partir de maintenant on appelera \[APP\] le chemin de ce dossié ou se trouve la racine de l'application Agora (ex. : /var/www/html/Phoenix/))
20
+
21
+Se connecter sous le docker avec une commande ressemblant à:
22
+
23
+	docker exec -ti NOMDUDOCKER /bin/bash
24
+
25
+
26
+Modifier le contenu du fichier de configuration apache ppur pointer vers le dossier APP/public
27
+
28
+	nano /etc/apache2/sites-enabled/default.conf
29
+
30
+	Alias /phoenix /var/www/html/Phoenix/public
31
+	<Directory /var/www/html/Phoenix/public>
32
+			Options Indexes FollowSymLinks MultiViews
33
+			AllowOverride All
34
+			Order allow,deny
35
+			allow from all
36
+	</Directory>
37
+
38
+Permettre l'affichage des erreurs php
39
+	nano /usr/local/etc/php/php.ini
40
+	ajouter (ou remplacer "display_errors = Off" par) "display_errors = On"  
41
+
42
+Relancer le serveur apache
43
+	service apache2 restart
44
+
45
+Créer le fichier APP/public/.htaccess avec le contenu:
46
+	Options +FollowSymlinks
47
+	RewriteEngine On
48
+	
49
+	RewriteCond %{REQUEST_FILENAME} !-f
50
+	RewriteRule ^(.*)$ /phoenix/index.php [QSA,L]
51
+    
52
+Changer les droit d'accès du répertoire de téléchargement
53
+    chmod 777 [APP]/var/uploads
54
+
55
+Lancer la mise à jour des paquets
56
+	cd APP
57
+	php -d memory_limit=3000M composer install --verbose --profile
58
+
59
+Verifier que les lignes suivantes sont présentes dans le fichier APP/.env avec le contenu suivant:
60
+	APP_ENV=dev
61
+	APP_DEBUG=1
62
+	APP_SECRET="@TODO Choisir une valeur secrète pour ce projet"	
63
+	APP_URL_PREFIX="/phoenix"
64
+	APP_HOST="localhost"
65
+	DATABASE_URL="mysql://root:logipro@[IPDOCKERMYSQL]/phoenix"
66
+	DATABASE_TEST_URL="mysql://root:logipro@[IPDOCKERMYSQL]/phoenixtest"
67
+	ASSETS_BASE_URL="phoenix"
68
+	WEBPACK_DEV_PUBLIC_PATH="/phoenix/build"	
69
+	MAILER_HOST="isp15.logipro.com"
70
+	MAILER_USERNAME="phoenix@logipro.com"
71
+	MAILER_PASSWORD="phoenix43;"	
72
+	MAILER_DEV_DESTINARY="[prenom].[nom]@logipro.com"
73
+
74
+Lancer les commandes dans APP:
75
+	cd APP
76
+	php bin/console doctrine:database:create
77
+	php bin/console doctrine:schema:create
78
+	php bin/console phoenix:setup
79
+	php bin/console phoenix:thematic:init
80
+
81
+Les commandes suivantes à LANCER DEPUIS EN LOCAL depuis WORK permettront de construire les liens à l'intérieur des pages
82
+	npm install
83
+	npm run dev
84
+
85
+Preparer les executions périodique avec le cron (crontab -e)
86
+
87
+    * * * * * /usr/local/bin/php /var/www/html/Phoenix/bin/console phoenix:cron:minute
88
+
89
+Pour vous connecter
90
+	dans le navigateur : [URL]/phoenix
91
+	login / mdp : admin@logipro.com / admin
92
+
93
+Ajouter le logo pour vous prévenir de comportement bizarre avec les emails (paramètres / informations générales)
94
+
95
+
96
+##Environnement de Dev pour Windows
97
+
98
+Une procédure d'installation est présente sur le réseau interne de Logipro [http://jira.logipro.com:8090/display/TLP/Installer+docker]

+ 98
- 121
assets/exclusive/js/back-office/form_library_utility.js View File

@@ -1,97 +1,85 @@
1 1
 /**
2 2
  * Ce fichier gère la partie formulaire des librairies
3 3
  */
4
- /**
5
- *
6
- * @param container
7
- * @returns
8
- */
9
-module.exports = function (container,options)
10
-{
4
+/**
5
+*
6
+* @param container
7
+* @returns
8
+*/
9
+module.exports = function (container, options) {
11 10
 	options = options || {};
12 11
 
13 12
 	let modal = container;
14 13
 	let body = modal.find('.ali-Content');
15
-	if (!modal.hasClass('modal'))
16
-	{
14
+	if (!modal.hasClass('modal')) {
17 15
 		modal = container.parents('.modal');
18 16
 	}
19 17
 
20
-	if (modal.length == 0)
21
-	{
18
+	if (modal.length == 0) {
22 19
 		modal = container;
23 20
 		body = container;
24 21
 	}
25
-	else
26
-	{
22
+	else {
27 23
 		body = modal.find('.modal-body');
28 24
 	}
29
-	
30
-	let defaultOptions = { 
31
-		postSucces: function(response)
32
-		{
33
-			if (!response.urlRedirect)
34
-			{
35
-				if (response.newContent && response.newContent != '')
36
-				{
25
+
26
+	let defaultOptions = {
27
+		postSucces: function (response) {
28
+			if (!response.urlRedirect) {
29
+				if (response.newContent && response.newContent != '') {
37 30
 					$('#modalCreateNewElementFromLibrary').find('.modal-content').html(response.newContent);
38 31
 				}
39
-				else
40
-				{
32
+				else {
41 33
 					// Fermeture de la modale
42
-					if (modal)
43
-					{
34
+					if (modal) {
44 35
 						modal.modal('hide');
45 36
 					}
46 37
 				}
47 38
 				// Affichage du message si les classes sont définis
48
-				if (response.message && response.messageType)
49
-				{
50
-					$.phoenix.addToast(response.message,response.messageType);
39
+				if (response.message && response.messageType) {
40
+					$.phoenix.addToast(response.message, response.messageType);
51 41
 				}
52 42
 			}
53
-			else
54
-			{
43
+			else {
55 44
 				// On est sur la liste on reactualise la page
56
-				window.parent.document.location = response.urlRedirect;
45
+				if (window.parent.document.location == response.urlRedirect) {
46
+					location.reload();
47
+				}
48
+				else {
49
+					window.parent.document.location = response.urlRedirect;
50
+				}
51
+
57 52
 			}
58 53
 		},
59
-		postError: function(response)
60
-		{
54
+		postError: function (response) {
61 55
 		},
62
-		beforeSubmit: function(formData)
63
-		{
56
+		beforeSubmit: function (formData) {
64 57
 			return formData;
65 58
 		}
66
-	 };
67
-	 $.extend(defaultOptions, options);
59
+	};
60
+	$.extend(defaultOptions, options);
68 61
 
69 62
 	// Soumission des formulaires en AJAX
70 63
 	let form = container;
71
-	if (form.phxGetTagName() != "form")
72
-	{
64
+	if (form.phxGetTagName() != "form") {
73 65
 		form = container.find('form');
74 66
 	}
75 67
 
76
-	form.on('submit', function()
77
-	{
68
+	form.on('submit', function () {
78 69
 		// traite les champs date spéciaux
79 70
 		let firstInvalid = null;
80
-		form.find('*[required][readonly]').each(function()
81
-		{
71
+		form.find('*[required][readonly]').each(function () {
82 72
 			let element = $(this);
83 73
 
84 74
 			element.removeAttr('readonly');
85 75
 
86 76
 			let native = element[0];
87
-			if (native.checkValidity() === false)
88
-			{
77
+			if (native.checkValidity() === false) {
89 78
 				firstInvalid = element;
90 79
 			}
91
-			element.attr('readonly','readonly');
80
+			element.attr('readonly', 'readonly');
92 81
 		});
93
-		if (firstInvalid)
94
-		{
82
+		if (firstInvalid) {
95 83
 			firstInvalid.focus();
96 84
 			return false;
97 85
 		}
@@ -108,88 +96,77 @@ module.exports = function (container,options)
108 96
 		formData = defaultOptions.beforeSubmit(formData);
109 97
 
110 98
 		$.ajax({
111
-			method: 'POST', 
112
-			url: action, 
99
+			method: 'POST',
100
+			url: action,
113 101
 			data: formData,
114 102
 			processData: false,
115 103
 			contentType: false
116 104
 		}).done
117
-		(
118
-			function(response)
119
-			{
120
-				$(document).phxUnlock();
121
-
122
-				if (response)
123
-				{
124
-					if (response.messageType == 'error')
125
-					{
126
-						if (response.formError)
127
-						{
128
-							let highter = body.find(':first-child').offset().top;
129
-							let minTop = 1000000;
130
-							let addError = function (field,value)
131
-                            {
132
-								let fieldContainer = field.parent();
133
-
134
-								// cas spécifique des autocompletes
135
-								if (field.attr('data-phx-remote-select-hidden'))
136
-								{
137
-									field = container.find(field.attr('data-phx-remote-select-hidden') + "_search");
138
-
139
-									fieldContainer = field.parents('.ali-InputSearch').parent();
140
-								}
141
-								let top = Math.abs(highter - field.offset().top);
142
-								if (minTop > top)
143
-                                {
144
-                                    minTop = top;
145
-							   }
146
-							   
147
-								 // ajoute les erreurs au formulaire
148
-								let events = ['change','keydown','paste','drop'];
149
-								events = events.join('.logipro.error ') + '.logipro.error';
150
-
151
-								field.off(events);
152
-
153
-                                field.addClass('ali-InputError');
154
-                                let span = $('<span>',{
155
-                                    class:'invalid-feedback d-block'
156
-                                }).text(value);
157
-                                fieldContainer.append(span);
158
-
159
-                                field.on(events,function()
160
-                                {
161
-                                    field.removeClass('ali-InputError');
162
-                                    span.remove();
163
-                                });
164
-                            }
165
-
166
-                            // erreur des champs
167
-							$.each(response.formError,function(key,value)
168
-							{
169
-								let field = container.find('#' + key);
170
-
171
-								// test car parfois le controleur remonte des erreurs sur aucun champ
172
-								// ces erreurs concernent le formulaire global
173
-								if (field.length > 0)
174
-								{
175
-									addError(field,value);
105
+			(
106
+				function (response) {
107
+					$(document).phxUnlock();
108
+
109
+					if (response) {
110
+						if (response.messageType == 'error') {
111
+							if (response.formError) {
112
+								let highter = body.find(':first-child').offset().top;
113
+								let minTop = 1000000;
114
+								let addError = function (field, value) {
115
+									let fieldContainer = field.parent();
116
+
117
+									// cas spécifique des autocompletes
118
+									if (field.attr('data-phx-remote-select-hidden')) {
119
+										field = container.find(field.attr('data-phx-remote-select-hidden') + "_search");
120
+
121
+										fieldContainer = field.parents('.ali-InputSearch').parent();
122
+									}
123
+									let top = Math.abs(highter - field.offset().top);
124
+									if (minTop > top) {
125
+										minTop = top;
126
+									}
127
+
128
+									// ajoute les erreurs au formulaire
129
+									let events = ['change', 'keydown', 'paste', 'drop'];
130
+									events = events.join('.logipro.error ') + '.logipro.error';
131
+
132
+									field.off(events);
133
+
134
+									field.addClass('ali-InputError');
135
+									let span = $('<span>', {
136
+										class: 'invalid-feedback d-block'
137
+									}).text(value);
138
+									fieldContainer.append(span);
139
+
140
+									field.on(events, function () {
141
+										field.removeClass('ali-InputError');
142
+										span.remove();
143
+									});
176 144
 								}
177
-							});
178 145
 
179
-							body.scrollTop(minTop - 20);
180
-						}
181
-						// erreur générale
182
-						$.phoenix.addToast(response.message,response.messageType);
146
+								// erreur des champs
147
+								$.each(response.formError, function (key, value) {
148
+									let field = container.find('#' + key);
183 149
 
184
-						defaultOptions.postError(response);
185
-					}
186
-					else
187
-					{
188
-						defaultOptions.postSucces(response);
150
+									// test car parfois le controleur remonte des erreurs sur aucun champ
151
+									// ces erreurs concernent le formulaire global
152
+									if (field.length > 0) {
153
+										addError(field, value);
154
+									}
155
+								});
156
+
157
+								body.scrollTop(minTop - 20);
158
+							}
159
+							// erreur générale
160
+							$.phoenix.addToast(response.message, response.messageType);
161
+
162
+							defaultOptions.postError(response);
163
+						}
164
+						else {
165
+							defaultOptions.postSucces(response);
166
+						}
189 167
 					}
190 168
 				}
191
-			}
192
-		);
169
+			);
193 170
 		return false;
194 171
 	});
195 172
 }

+ 0
- 18
assets/exclusive/js/back-office/init_back_office.js View File

@@ -33,24 +33,6 @@ $(document).ready(function ()
33 33
 	removeOutlineOnClick();
34 34
 });
35 35
 
36
-function initscrollDatepicker(container)
37
-{
38
-	// initialise les datepicker
39
-	var lastScrollTop = 0;
40
-	container.scroll(function (event)
41
-	{
42
-		container.find('[data-airpicker]').each(function()
43
-		{
44
-			let picker = $(this).data('datepicker');
45
-			if (picker)
46
-			{
47
-				picker.hide();
48
-			}
49
-		});
50
-	});
51
-}
52
-
53
-
54 36
 function initscrollDatepicker(container)
55 37
 {
56 38
 	// initialise les datepicker

+ 1
- 0
assets/exclusive/js/back-office/init_back_office_forum.js View File

@@ -366,6 +366,7 @@ function createQuestion(formQuestion) {
366 366
 				}
367 367
 				else
368 368
 				{
369
+					form.phxUnlock();
369 370
 					alert(response.error);
370 371
 				}
371 372
 

+ 277
- 0
assets/exclusive/js/back-office/init_diary.js View File

@@ -0,0 +1,277 @@
1
+"use strict";
2
+import { Calendar } from '@fullcalendar/core';
3
+import dayGridPlugin from '@fullcalendar/daygrid';
4
+import timeGridPlugin from '@fullcalendar/timegrid';
5
+import listPlugin from '@fullcalendar/list';
6
+import bootstrapPlugin from '@fullcalendar/bootstrap';
7
+import { initBtnPlace } from './session/create/session_place';
8
+
9
+$(document).ready(function()
10
+{
11
+	initDiary();
12
+});
13
+
14
+function initDiary()
15
+{
16
+	var eventClick = false;
17
+	var minRenderDate = null;
18
+	var maxRenderDate = null;
19
+	var calendarEl = document.getElementById('ali-calendar');
20
+	var nbLoading = 0;
21
+	
22
+	var calendar = new Calendar(calendarEl, {
23
+		plugins: [ dayGridPlugin, timeGridPlugin, listPlugin, bootstrapPlugin ],
24
+		themeSystem: 'bootstrap',
25
+		contentHeight: 900,
26
+		firstDay: 1,
27
+		buttonText : {
28
+			today: "Aujourd'hui",
29
+			month: 'Mois',
30
+			week:  'Semaine',
31
+			day:   'Jour'
32
+		},
33
+		allDaySlot: false,
34
+		bootstrapFontAwesome:{
35
+			close: 'ali-times',
36
+			prev: 'ali-chevron-left',
37
+			next: 'ali-chevron-right',
38
+			prevYear: 'ali-angle-double-left',
39
+			nextYear: 'ali-angle-double-right'
40
+		},
41
+		header: {
42
+			left:   'prev next today',
43
+			center: 'title',
44
+			right:  'dayGridMonth,timeGridWeek,timeGridDay'
45
+		},
46
+		columnHeaderFormat: { weekday: 'long' },
47
+		windowResize: function(view) {
48
+			var columnFormat = view.calendar.getOption('columnHeaderFormat');
49
+			if ($(window).width() < 900)
50
+			{
51
+				if (columnFormat.weekday == 'long')
52
+				{
53
+					columnFormat.weekday = "short";
54
+					calendar.setOption('columnHeaderFormat', columnFormat);
55
+				}
56
+			}
57
+			else
58
+			{
59
+				if (columnFormat.weekday == 'short')
60
+				{
61
+					columnFormat.weekday = "long";
62
+					calendar.setOption('columnHeaderFormat', columnFormat);
63
+				}
64
+			}
65
+		},
66
+		datesRender: function(info) {
67
+			// Variable qui permet de savoir si on doit charger les event de la plage affiché ou non
68
+			var loadEvents = false;
69
+
70
+			if (!minRenderDate && !maxRenderDate)
71
+			{
72
+				// S'il n'y a pas encore eu d'affichage de plage sauvegarder la plage afficher
73
+				minRenderDate = info.view.activeStart;
74
+				maxRenderDate = info.view.activeEnd;
75
+				// et autoriser le chargement des events de cette plage
76
+				var loadEvents = true;
77
+			}
78
+			else {
79
+				// Si la date de début est hors de la plage déjà charger
80
+				if (minRenderDate > info.view.activeStart)
81
+				{
82
+					// Etendre la plage sauvegarder
83
+					minRenderDate = info.view.activeStart;
84
+					// et autoriser le chargement des events de cette plage
85
+					loadEvents = true;
86
+				}
87
+				// Si la date de fin est hors de la plage déjà charger
88
+				if (maxRenderDate < info.view.activeEnd)
89
+				{
90
+					// Etendre la plage sauvegarder
91
+					maxRenderDate = info.view.activeEnd;
92
+					// et autoriser le chargement des events de cette plage
93
+					loadEvents = true;
94
+				}
95
+			}
96
+			
97
+			// Si le chargement deevent est autorisé
98
+			if (loadEvents)
99
+			{
100
+				nbLoading = nbLoading + 1;
101
+				$(".ali-DiaryLoading").show();
102
+
103
+				var viewCalendar = info.view.calendar;
104
+				// Définir la plage d'évent à charger (correspond à ce qui est affiché sur le calendrier)
105
+				var datas = {
106
+					"startDate": formatDate(info.view.activeStart),
107
+					"endDate": formatDate(info.view.activeEnd)
108
+				};
109
+
110
+				// Envoyer la requête pour récupérer les events
111
+				var url = $("#ali-calendar").data('get-events-action');
112
+				$.get(url, datas, function (reponse) {
113
+					// S'il y a une reponse 
114
+					if (reponse)
115
+					{
116
+						$.each(reponse, function(id, elem)
117
+						{
118
+							// Traiter les dates
119
+							elem.start = new Date(elem.start);
120
+							elem.end = new Date(elem.end);
121
+
122
+							var eventCalendar = viewCalendar.getEventById(elem.id);
123
+							if (eventCalendar)
124
+							{
125
+								// Si l'event et déjà dans le calendrier le metttre à jour
126
+								eventCalendar.setProp('title', elem.title);
127
+								eventCalendar.setDates(elem.start, elem.end);
128
+								eventCalendar.setDates(elem.start, elem.end);
129
+							}
130
+							else
131
+							{
132
+								// Sinon l'ajouter
133
+								viewCalendar.addEvent(elem);
134
+							}
135
+						});
136
+						
137
+						nbLoading = nbLoading - 1;
138
+						if (!nbLoading) {
139
+							$(".ali-DiaryLoading").hide();
140
+						}
141
+					}
142
+
143
+				});
144
+			}
145
+		},
146
+		eventClick: function(eventClickInfo) {
147
+			eventClick = true;
148
+			var aliCalendar = $("#ali-calendar");
149
+			var elem = $(eventClickInfo.el);
150
+			var event = eventClickInfo.event;
151
+			var toolTip = elem.find('.ali-DiaryToolTip');
152
+			var container = $(".fc-view-container .fc-scroller");
153
+
154
+			container.css('position', 'relative');
155
+
156
+			if (!toolTip.length)
157
+			{
158
+				toolTip = $('<div>', {class:"ali-DiaryToolTip", html:event.extendedProps.preview}).fadeOut(0).appendTo(container);
159
+				// Initialiser le bouton "Lieu de formation"
160
+				var placeBtn = toolTip.find('.ali-ClassroomPlace-btn');
161
+				if (placeBtn.length) {
162
+					initBtnPlace(placeBtn);
163
+				}
164
+				// Initialiser le bouton "Ouvrir la classe"
165
+				var virtualBtn = toolTip.find("a[name='create-virtual-class']");
166
+				if (virtualBtn.length) {
167
+					initVirtualClassButton(virtualBtn);
168
+				}
169
+			}
170
+
171
+			if (toolTip.is(":visible")) {
172
+				return;
173
+			}
174
+
175
+			$('.ali-DiaryToolTip').fadeOut(200);
176
+
177
+			// Position de la tooltip
178
+			var leftParent = aliCalendar.offset().left;
179
+			var leftEvent = elem.offset().left;
180
+			var leftEventInParent = leftEvent - leftParent;
181
+			var ratioLeft = leftEventInParent / aliCalendar.width();
182
+			var tooltipClass = "";
183
+			if (ratioLeft < 0.33) {
184
+				// à droite
185
+				tooltipClass = "ali-DiaryToolTip-right";
186
+			}
187
+			else if (ratioLeft > 0.55) {
188
+				// à gauche
189
+				tooltipClass = "ali-DiaryToolTip-left";
190
+			}
191
+			else {
192
+				// centre
193
+				tooltipClass = "ali-DiaryToolTip-center";
194
+			}
195
+
196
+			var topParent = aliCalendar.offset().top;
197
+			var topEvent = elem.offset().top;
198
+			var topEventInParent = topEvent - topParent;
199
+			var marge = 0;
200
+			if (topEventInParent + elem.height() + toolTip.height() > aliCalendar.height()) {
201
+				tooltipClass += ", ali-DiaryToolTip-top"
202
+			}
203
+			else {
204
+				marge = 20;
205
+			}
206
+			// Position dans le contenaire
207
+			toolTip.css({
208
+				top: elem.offset().top - container.offset().top  + container.scrollTop() + marge,
209
+				left: elem.offset().left - container.offset().left,
210
+			});
211
+			
212
+			toolTip.removeClass("ali-DiaryToolTip-right, ali-DiaryToolTip-left, ali-DiaryToolTip-center, ali-DiaryToolTip-top");
213
+			toolTip.addClass(tooltipClass).fadeIn(200);
214
+		}
215
+
216
+	});
217
+	calendar.setOption('locale', 'fr');
218
+	calendar.render();
219
+
220
+	// Si on clik en dehors des events, masquer les tooltips
221
+	$('body').click(function(){
222
+		if (eventClick) {
223
+			eventClick = false;
224
+		}
225
+		else {
226
+			$('.ali-DiaryToolTip').fadeOut(200);
227
+		}
228
+	});
229
+}
230
+
231
+/**
232
+ * Formate la date en texte
233
+ * @param Date formattedDate 
234
+ */
235
+function formatDate(formattedDate)
236
+{
237
+	var d = formattedDate.getDate();
238
+	var m =  formattedDate.getMonth();
239
+	m += 1;  // JavaScript months are 0-11
240
+	var y = formattedDate.getFullYear();
241
+	var hours = formattedDate.getHours();
242
+	var minutes = formattedDate.getMinutes();
243
+	var secondes = formattedDate.getSeconds();
244
+	
245
+	return y + "/" + m + "/" + d + ' ' + hours + ':' + minutes + ':' + secondes;
246
+}
247
+
248
+
249
+/**
250
+ * Initialise un boutons pour créer/rejoindre une classe virtuelle
251
+ * @param {dom} link lien de l'actiond de création de la classe virtuelle
252
+ */
253
+function initVirtualClassButton(link) {
254
+	if (typeof link == 'undefined' || link.length == 0) {
255
+		return;
256
+	}
257
+
258
+	link.off('click.logipro');
259
+	link.on('click.logipro', function (event) {
260
+		event.preventDefault();
261
+
262
+		$(document).phxLock();
263
+
264
+		$.post(link.attr('href'), '', function (response) {
265
+			$(document).phxUnlock();
266
+			if (response.result) {
267
+				link.next().removeClass('d-none');
268
+				link.remove();
269
+			}
270
+			else {
271
+				$.phoenix.addToast(Translator.trans('message_create_bbb_fail'), 'error');
272
+			}
273
+		}).fail(function () {
274
+			$(document).phxUnlock();
275
+		})
276
+	});
277
+}

+ 6
- 1
assets/exclusive/js/back-office/learning_path/learning_path_edit.js View File

@@ -1,7 +1,12 @@
1 1
 let phxInitCreateFromLibrary = require('../form_library_utility');
2
+let programUtility  = require('../utilities/program');
2 3
 
3 4
 
4
-$(document).ready(function () {
5
+$(document).ready(function ()
6
+{
7
+    // initialise le programme
8
+    programUtility.initProgram();
9
+
5 10
     // gère la modal d'édition d'une offre
6 11
     let modal = $('#modalEditThisLearningPath');
7 12
 

+ 130
- 135
assets/exclusive/js/back-office/learning_path/learning_path_editor.js View File

@@ -2,6 +2,12 @@ import { phxInitSearchCoworker } from '../../../../shared/js/init/init_coworker-
2 2
 import { phxInitOsmap } from '../../../../shared/js/init/init_osmap';
3 3
 var dropzoneInit = require('./../../utilities/dropzone');
4 4
 var phxInitCreateFromLibrary = require('../form_library_utility');
5
+const simplebar = require('simplebar/dist/simplebar.js');
6
+new simplebar($('.ali-EditorContentLeftPanelSimplebar')[0], { autoHide: false });
7
+new simplebar($('.ali-EditorContentRightPanelSimplebar')[0], { autoHide: false });
8
+import { updateSequenceSummaryList } from './learning_path_editor_sequence_summary.js';
9
+import { selectSequencInSummary } from './learning_path_editor_sequence_summary.js';
10
+
5 11
 
6 12
 $(document).ready(function () {
7 13
     updateWindowsSize();
@@ -26,11 +32,12 @@ $(document).ready(function () {
26 32
     }
27 33
 });
28 34
 
35
+
36
+
29 37
 /**
30 38
  * Initialise le parcours
31 39
  */
32
-function initLearningPath()
33
-{
40
+function initLearningPath() {
34 41
     initDragAndDrop();
35 42
     initConditions();
36 43
     initVirtualClassButtons();
@@ -63,6 +70,9 @@ function initOneSequence(sequence) {
63 70
     initCreateItem(sequence);
64 71
     initDeleteSequence(sequence.find("a[data-phx-delete-sequence]"));
65 72
     initOneDragAndDrop(sequence.find('[data-phx-draggable]')[0]);
73
+
74
+    updateSequenceSummaryList();
75
+    selectSequencInSummary(-1, true);
66 76
 }
67 77
 
68 78
 /**
@@ -125,8 +135,10 @@ function updateStatusScorm() {
125 135
     $.each(scormBeingProcessed, function () {
126 136
         var _this = $(this);
127 137
         var action = _this.attr('data-action-scorm-status');
138
+        //console.log(action);
128 139
 
129 140
         $.get(action, function (response) {
141
+            //console.log(response);
130 142
             if (typeof response.status != 'undefined' && response.status == 'IMPORTED') {
131 143
                 // Scorm importé
132 144
                 // Recharger le preview si c'est celui visualisé
@@ -143,6 +155,17 @@ function updateStatusScorm() {
143 155
                         }).insertAfter(_this);
144 156
                     });
145 157
                 }
158
+
159
+                if (typeof (response.duration) != 'undefined') {
160
+                    var sequenceItemParent = _this.parents('.ali-SequenceActivityPackage');
161
+
162
+                    if (sequenceItemParent.length) {
163
+                        sequenceItemParent.find('.ali-EditorSequenceItemLogo-duration').html(
164
+                            '<i class="material-icons">access_time</i> ' + response.duration
165
+                        );
166
+                    }
167
+                }
168
+
146 169
                 // Retirer la notice
147 170
                 _this.remove();
148 171
             }
@@ -185,8 +208,6 @@ function initOneDragAndDrop(container) {
185 208
     draggable.on('drag:start', function (e) {
186 209
         // Fixer la taille de la copie de l'élément
187 210
         $(e.source).width($(e.sourceContainer).width());
188
-        // Masquer le selecteur
189
-        $('.ali-SequenceItemSelector').fadeOut(200);
190 211
     });
191 212
     draggable.on('drag:stop', function (e) {
192 213
         setTimeout(setSelectorPosition, 50);
@@ -293,8 +314,7 @@ function saveSequenceItemsOrder(orders) {
293 314
 
294 315
             // Si de nouvelles limites concernant la date pour l'événement selectionné sont remontées suite au déplacement
295 316
             // Mettre à jour les limites sur le datepicker
296
-            if (typeof response['newMinDateSequenceItemSelect'] != 'undefined')
297
-            {
317
+            if (typeof response['newMinDateSequenceItemSelect'] != 'undefined') {
298 318
                 var fieldDate = $('.ali-EditorContentRightPanelContent-form [data-airpicker="date time"]');
299 319
                 if (fieldDate.length > 0) {
300 320
                     fieldDate.datepicker().data('datepicker').update({
@@ -464,7 +484,7 @@ function initConditions() {
464 484
 }
465 485
 
466 486
 /**
467
- * Recupération du formualire pour gérer les conditions
487
+ * Recupération du formualaire pour gérer les conditions
468 488
  * @param {*} zone 
469 489
  */
470 490
 function manageConditionForm(zone) {
@@ -483,13 +503,13 @@ function manageConditionForm(zone) {
483 503
 
484 504
         // Vérouillage des champs
485 505
         var contentCondition = newForm.find('.ali-EditorSequenceOneAssertionEdit-assertion');
486
-        contentCondition.each(function(){
506
+        contentCondition.each(function () {
487 507
             var _this = $(this);
488 508
             var checkbox = $(this).find('div:first-child input[type="checkbox"]');
489 509
             if (!checkbox.is(":checked")) {
490 510
                 _this.addClass('locked');
491 511
             }
492
-            checkbox.change(function(){
512
+            checkbox.change(function () {
493 513
                 if (checkbox.is(":checked")) {
494 514
                     _this.removeClass('locked');
495 515
                 }
@@ -508,7 +528,7 @@ function manageConditionForm(zone) {
508 528
             $.get(actionCancel).done(function (response) {
509 529
                 let responseContent = $(response.conditionHtml);
510 530
                 var parent = zone.parent().parent();
511
-                
531
+
512 532
                 parent.replaceWith(responseContent);
513 533
 
514 534
                 setSelectorPosition();
@@ -542,7 +562,7 @@ function manageConditionForm(zone) {
542 562
                             var parent = zone.parent().parent();
543 563
 
544 564
                             parent.replaceWith(responseContent);
545
-                            
565
+
546 566
                             setSelectorPosition();
547 567
 
548 568
                             initConditionsByParent(responseContent);
@@ -677,9 +697,9 @@ function initModalDelete() {
677 697
                 setSequenceItemOrderByList(parent, true);
678 698
             });
679 699
 
680
-            
700
+
681 701
             updateView(response);
682
-            
702
+
683 703
             // Effacer la preview si c'est le même item
684 704
             // @todo
685 705
 
@@ -723,6 +743,8 @@ function initModalDelete() {
723 743
                     setSelectorPosition();
724 744
                 }
725 745
                 $(this).remove();
746
+
747
+                updateSequenceSummaryList();
726 748
             });
727 749
         });
728 750
 
@@ -831,7 +853,9 @@ function initCreateItem(sequence) {
831 853
 
832 854
     // Activer les boutons de création
833 855
     sequence.find('.ali-EditorSequenceCreateItem').each(function () {
834
-        $(this).addClass('active');
856
+        if ($(this).hasClass('disabled') === false) {
857
+            $(this).addClass('active');
858
+        }
835 859
     });
836 860
 }
837 861
 
@@ -839,8 +863,8 @@ function initCreateItem(sequence) {
839 863
  * Initialise le comportement des popups de création
840 864
  */
841 865
 function initModalCreateItem() {
842
-    var modals = $('#modalCreateActivityPackage, #modalCreateActivityPage, #modalCreateEventClassroom, #modalCreateEventVirtualClassroom');
843
-
866
+    var modals = $('#modalCreateActivityPackage, #modalCreateActivityPage, #modalCreateEventClassroom, #modalCreateEventVirtualClassroom,[id^="modalBundle"]');
867
+    
844 868
     var cloneforms = {};
845 869
     modals.each(function () {
846 870
         var form = $(this).find('form');
@@ -879,6 +903,10 @@ function initModalCreateItem() {
879 903
 
880 904
                 // selectionner le sequence item
881 905
                 selectSequenceItem(sequenceItemHtml.find('.ali-EditorSequenceItem'));
906
+
907
+                
908
+                // Envoi event pour informer l'ajout d'un sequence item
909
+                $(".ali-EditorContentLeftPanelContent").trigger("logiprolearningpathaddsequenceitem", sequenceItemHtml);
882 910
             },
883 911
             beforeSubmit: function (formData) {
884 912
                 var listSequence = $('[data-phx-draggable-list="' + sequenceId + '"]');
@@ -901,7 +929,14 @@ function initCreateSequence() {
901 929
     var modal = $('#modalCreateSequence');
902 930
     var cloneform = null;
903 931
     var form = modal.find('form');
904
-    initForm(form, modal);
932
+
933
+    // Initialiser le formulaire qu'une fois
934
+    if (form.attr('data-formInit') != 'true')
935
+    {
936
+        initForm(form, modal);
937
+        form.attr('data-formInit', 'true');
938
+    }
939
+    
905 940
     // Clonage des formulaires
906 941
     cloneform = form.clone();
907 942
 
@@ -1049,7 +1084,6 @@ function setupPackageDropzone(content) {
1049 1084
     myDropzone.on('success', function (file) {
1050 1085
 
1051 1086
         let response = JSON.parse(file.xhr.response);
1052
-        console.log('finish');
1053 1087
         window.removeEventListener("beforeunload", lockClose, true);
1054 1088
 
1055 1089
         if (response.success) {
@@ -1146,40 +1180,41 @@ function showFormEditSequenceItem(action, sequenceItem) {
1146 1180
         initAirDatePicker(content);
1147 1181
         phxInitSearchCoworker();
1148 1182
         initSubmitFormUpdate(content.find('form'));
1149
-        
1183
+
1150 1184
         // Après ouverture du panneau de droite
1151
-        setTimeout(function(){initPlace();}, 200);
1185
+        setTimeout(function () { initPlace(); }, 200);
1152 1186
 
1153 1187
         content.initCustomInputFile();
1154 1188
 
1155
-        // Mettre à jour la taille de la zone du bouton submit
1156
-        updateFormSubmitPosition();
1157
-
1158 1189
         // Dévérouillage de la page
1159 1190
         $(document).phxUnlock();
1191
+        
1192
+        // Envoi event pour informer que le formulaire est affiché
1193
+        sequenceItem.trigger("logiprolearningpathsequenceformopen");
1160 1194
     });
1161 1195
 }
1162 1196
 
1163
-function updateView(response)
1164
-{
1197
+function updateView(response) {
1165 1198
     // Mise à jour de la liste
1166
-    if (typeof response.learningPathHtml != 'undefined') {
1199
+    if (typeof response.learningPathHtml != 'undefined')
1200
+    {
1167 1201
         var currentSelectId = $(".ali-EditorSequenceItem.active, .ali-EditorSequenceHeadTitle.active").attr('id');
1168
-        
1169
-        $('.ali-EditorContentLeftPanelContent').html(response.learningPathHtml);
1170 1202
 
1171
-        var newCurrentSelectId = $('.ali-EditorContentLeftPanelContent').find('#'+currentSelectId);
1203
+        var reponseHtml = $(response.learningPathHtml);
1204
+        // Déplacer le formulaire en mode responsive petit ecran dans le nouveau contenue
1205
+        reponseHtml.find('#'+currentSelectId+' + .ali-EditorSequenceContentEdit').replaceWith($('.ali-EditorSequenceItem.active + .ali-EditorSequenceContentEdit'));
1206
+
1207
+        $('.ali-EditorContentLeftPanelContent').html(reponseHtml);
1208
+
1209
+        var newCurrentSelectId = $('.ali-EditorContentLeftPanelContent').find('#' + currentSelectId);
1172 1210
         if (newCurrentSelectId.length) {
1173 1211
             newCurrentSelectId.addClass('active');
1174 1212
         }
1175
-
1176 1213
         initLearningPath();
1177 1214
 
1178
-
1179 1215
         // recharger la dropzone
1180 1216
         var sequenceItemActive = $('.ali-EditorSequenceItem.active');
1181
-        if (sequenceItemActive.length)
1182
-        {
1217
+        if (sequenceItemActive.length) {
1183 1218
             $(document).phxLock();
1184 1219
             var action = sequenceItemActive.attr('data-phx-update-item');
1185 1220
             var content = $('.ali-EditorContentRightPanelContent-form');
@@ -1200,7 +1235,9 @@ function updateView(response)
1200 1235
         var listItem = $('[data-phx-draggable-item="' + itemId + '"]')
1201 1236
 
1202 1237
         // Replacer le contenu
1203
-        listItem.replaceWith(response.sequenceItemHtml);
1238
+        listItem.find(".ali-EditorSequenceItem").replaceWith($(response.sequenceItemHtml).find(".ali-EditorSequenceItem"));
1239
+        listItem.find(".ali-EditorSequenceItemSeparator").replaceWith($(response.sequenceItemHtml).find(".ali-EditorSequenceItemSeparator"));
1240
+        
1204 1241
         // Nouvelle élement
1205 1242
         listItem = $('[data-phx-draggable-item="' + itemId + '"]');
1206 1243
         // Le rendre actif
@@ -1243,6 +1280,20 @@ function updateView(response)
1243 1280
             $(document).phxUnlock();
1244 1281
         });
1245 1282
     }
1283
+
1284
+     // Crée l'événement
1285
+     /*var event = document.createEvent('Event');
1286
+
1287
+     // Nomme l'événement 'build'.
1288
+     event.initEvent('logiprolearningpathsave', true, true);
1289
+
1290
+     // target peut être n'importe quel Element ou autre EventTarget.
1291
+     console.log($('.ali-EditorSequenceItem.active').parent());
1292
+     $('.ali-EditorSequenceItem.active').parent()[0].dispatchEvent(event);*/
1293
+
1294
+     console.log( $('.ali-EditorSequences'));
1295
+    
1296
+     $('.ali-EditorSequences').trigger('logiprolearningpathsequencesave');
1246 1297
 }
1247 1298
 
1248 1299
 /**
@@ -1282,6 +1333,7 @@ function initSubmitFormUpdate(form) {
1282 1333
             return formData;
1283 1334
         },
1284 1335
         postError: function (response) {
1336
+            console.log('error');
1285 1337
             var saveLoginAnim = form.find('.ali-SaveAnim');
1286 1338
             // Affichage d'erreur
1287 1339
             saveLoginAnim.text(Translator.trans('label_sequence_item_unsaved')).css({ 'background-image': 'none' });
@@ -1322,7 +1374,7 @@ function initAirDatePicker(container) {
1322 1374
         let dateEndSession = fieldDate.attr('data-phx-end-session');
1323 1375
         let dataAltField = fieldDate.attr('data-alt-field');
1324 1376
 
1325
-        let myDatepicker = fieldDate.datepicker({
1377
+        let options = {
1326 1378
             minDate: new Date(dateStartSession),
1327 1379
             maxDate: new Date(dateEndSession),
1328 1380
             offset: 0,
@@ -1332,17 +1384,11 @@ function initAirDatePicker(container) {
1332 1384
             position: 'top left',
1333 1385
             classes: 'ali-EditorSequence-datePicker',
1334 1386
             timepicker: true,
1335
-            language: {
1336
-                days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
1337
-                daysShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
1338
-                daysMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'],
1339
-                months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Decembre'],
1340
-                monthsShort: ['Jan', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Dec'],
1341
-                clear: 'Effacer'
1342
-            },
1343 1387
             startDate: start,
1344 1388
             minHours: 0
1345
-        }).data('datepicker');
1389
+        };
1390
+        let utility = require('../utilities/utility');
1391
+        let myDatepicker = utility.initDatepicker(container,options).first().datepicker().data('datepicker');
1346 1392
 
1347 1393
         let valueDate = $(dataAltField).val();
1348 1394
         if (valueDate != '') {
@@ -1353,7 +1399,7 @@ function initAirDatePicker(container) {
1353 1399
         // Si on scroll le calendrier disparait
1354 1400
         // C'est la seule solution rapide trouvé pour régler le problème de calendrier positionné toujours en bas
1355 1401
         var lastScrollTop = 0;
1356
-        $('.ali-EditorContentRightPanelContent').scroll(function (event) {
1402
+        $('.ali-EditorContentRightPanelContent').parent().scroll(function (event) {
1357 1403
             myDatepicker.hide();
1358 1404
         });
1359 1405
     }
@@ -1422,37 +1468,13 @@ function updateWindowsSize() {
1422 1468
         doit = setTimeout(function () {
1423 1469
             $(window).trigger('phx-windows-resize');
1424 1470
             // Fixer la taille du panneau d'édition qui est en sticky
1425
-            $('.ali-EditorContentRightPanelContent').css({ 'max-height': $(window).height() });
1471
+            //$('.ali-EditorContentRightPanelContent').css({ 'max-height': $(window).height() });
1426 1472
             // Mettre à jour la position du panneau d'édition en fonction de la taille de l'écran
1427 1473
             updateFormUpdatePosition();
1428 1474
             // Mettre à jour la position du selecteur
1429 1475
             setSelectorPosition();
1430
-            // Mettre à jour la taille de la zone du bouton submit
1431
-            updateFormSubmitPosition();
1432 1476
         }, 200);
1433 1477
     });
1434
-
1435
-    // Initialiser la taille du panneau d'édition qui est en sticky
1436
-    $('.ali-EditorContentRightPanelContent').css({ 'max-height': $(window).height() });
1437
-    updateFormSubmitPosition();
1438
-}
1439
-
1440
-/**
1441
- * Met à jour la postion du bouton submit du formulaire d'édition
1442
- */
1443
-function updateFormSubmitPosition() {
1444
-    var submitButtonContent = $('.ali-EditorSequenceItemSubmit');
1445
-    if (submitButtonContent.length) {
1446
-        if ($(window).width() <= 1200) {
1447
-            submitButtonContent.width('100%');
1448
-            submitButtonContent.css({ 'left': 0 });
1449
-        }
1450
-        else {
1451
-            submitButtonContent.width($('.ali-EditorContentRightPanel').width());
1452
-            submitButtonContent.css({ 'right': 0, 'left': 'initial' });
1453
-            //submitButtonContent.css({'left':$('.ali-EditorContentRightPanelContent-form').offset().left});
1454
-        }
1455
-    }
1456 1478
 }
1457 1479
 
1458 1480
 /**
@@ -1505,7 +1527,6 @@ function setSelectorPosition(itemSelect) {
1505 1527
     if (!rightPanel.hasClass('active')) {
1506 1528
         // Pour corriger le problème d'animation
1507 1529
         rightPanel.animate({ 'width': '30%' }, 200);
1508
-        setTimeout(updateFormSubmitPosition, 400);
1509 1530
     }
1510 1531
     rightPanel.addClass('active');
1511 1532
 
@@ -1518,16 +1539,6 @@ function setSelectorPosition(itemSelect) {
1518 1539
     // Récupération sequence item actif
1519 1540
     var currentActive = $('.ali-EditorSequenceItem.active, .ali-EditorSequenceHeadTitle.active');
1520 1541
 
1521
-    // Si l'élément selectioné est le même que l'actif
1522
-    if ($(currentActive[0]).is(itemSelect)) {
1523
-        // Mise à jour de la position
1524
-        $('.ali-SequenceItemSelector').css({
1525
-            height: height,
1526
-            top: topPosition
1527
-        }).fadeIn(200);
1528
-        return;
1529
-    }
1530
-
1531 1542
     // Rendre inactif l'ancien sequence item
1532 1543
     currentActive.removeClass('active');
1533 1544
     // Rendre actif le nouveau sequence item
@@ -1535,28 +1546,13 @@ function setSelectorPosition(itemSelect) {
1535 1546
 
1536 1547
 
1537 1548
     // Prendre les anciens selecteurs (élément affiché sur l'écran permétant de visualiser le sequence item en cours d'édition)
1538
-    var oldSelector = $('.ali-SequenceItemSelector');
1539 1549
     var oldSelectorLine = $('.ali-SequenceItemSelectorLine');
1540 1550
 
1541 1551
     // Faire disparaitre le ancien selecteur avec une animation
1542 1552
     oldSelectorLine.fadeOut(500, function () { $(this).remove() });
1543
-    oldSelector.animate({ left: -horizontalDiff }, 200, function () {
1544
-        $(this).remove();
1545
-    });
1546
-
1547
-    // Ajouter les nouveaux selecteur avec animation
1548
-    var newSelector = $('<div>', { class: "ali-SequenceItemSelector" }).css({
1549
-        width: '20px',
1550
-        height: height,
1551
-        background: itemSelect.css('border-left-color'),
1552
-        top: topPosition,
1553
-        left: -horizontalDiff
1554
-    })
1555
-        .appendTo(rightPanel);
1556 1553
 
1557 1554
     // Si le panneau d'édition n'est pas visible, pas d'animation
1558 1555
     if ($(window).width() <= 1200) {
1559
-        newSelector.fadeOut().css({ left: '-20px' });
1560 1556
 
1561 1557
         $('<div>', { class: "ali-SequenceItemSelectorLine" }).css({
1562 1558
             position: 'absolute',
@@ -1568,21 +1564,19 @@ function setSelectorPosition(itemSelect) {
1568 1564
         }).appendTo(rightPanel);
1569 1565
     }
1570 1566
     else {
1571
-        newSelector.animate({ left: '-20px' }, 200, function () {
1572
-            $('<div>', { class: "ali-SequenceItemSelectorLine" }).css({
1573
-                position: 'absolute',
1574
-                width: '4px',
1575
-                background: itemSelect.css('border-left-color'),
1576
-                top: topPosition,
1577
-                bottom: topPosition + height,
1578
-                left: 0
1579
-            })
1580
-                .appendTo(rightPanel)
1581
-                .animate({
1582
-                    top: 0,
1583
-                    bottom: 0
1584
-                }, 200);
1585
-        });
1567
+        $('<div>', { class: "ali-SequenceItemSelectorLine" }).css({
1568
+            position: 'absolute',
1569
+            width: '4px',
1570
+            background: itemSelect.css('border-left-color'),
1571
+            top: topPosition,
1572
+            bottom: topPosition + height,
1573
+            left: 0
1574
+        })
1575
+            .appendTo(rightPanel)
1576
+            .animate({
1577
+                top: 0,
1578
+                bottom: 0
1579
+            }, 200);
1586 1580
     }
1587 1581
 }
1588 1582
 
@@ -1613,10 +1607,14 @@ function selectSequence(sequence, force) {
1613 1607
     setSelectorPosition(sequence);
1614 1608
     updateFormUpdatePosition();
1615 1609
 
1616
-    var action = sequence.attr('data-phx-update-item');
1617
-    if (action) {
1618
-        showFormEditSequenceItem(action);
1619
-    }
1610
+    // On attend la fin de l'animation du panneau d'édition pour afficher 
1611
+    // correctement le contenue du formulaire. (voir BUGANDCO-25)
1612
+    setTimeout(function(){
1613
+        var action = sequence.attr('data-phx-update-item');
1614
+        if (action) {
1615
+            showFormEditSequenceItem(action);
1616
+        }
1617
+    }, 200);
1620 1618
 }
1621 1619
 
1622 1620
 /**
@@ -1653,21 +1651,23 @@ function selectSequenceItem(sequenceItem, force) {
1653 1651
     setSelectorPosition(sequenceItem);
1654 1652
     updateFormUpdatePosition();
1655 1653
 
1656
-    var action = sequenceItem.attr('data-phx-update-item');
1657
-    if (action) {
1658
-        showFormEditSequenceItem(action, sequenceItem);
1659
-    }
1654
+    // On attend la fin de l'animation du panneau d'édition pour afficher 
1655
+    // correctement le contenue du formulaire. (voir BUGANDCO-25)
1656
+    setTimeout(function(){
1657
+        var action = sequenceItem.attr('data-phx-update-item');
1658
+        if (action) {
1659
+            showFormEditSequenceItem(action, sequenceItem);
1660
+        }
1661
+    }, 200);
1660 1662
 }
1661 1663
 
1662 1664
 /**
1663 1665
  * Ferme la zone d'édition
1664 1666
  */
1665 1667
 function closeEditPanel() {
1666
-    var oldSelector = $('.ali-SequenceItemSelector');
1667 1668
     var oldSelectorLine = $('.ali-SequenceItemSelectorLine');
1668 1669
 
1669 1670
     oldSelectorLine.fadeOut(500, function () { $(this).remove() });
1670
-    oldSelector.fadeOut(500, function () { $(this).remove() });
1671 1671
 
1672 1672
     $('.ali-EditorSequenceItem.active').removeClass('active');
1673 1673
     $('.ali-EditorContentRightPanel').css('width', '').removeClass('active');
@@ -1923,11 +1923,10 @@ function initDropZone() {
1923 1923
                 });
1924 1924
 
1925 1925
                 // ajoute l'image de l'image
1926
-                if (file.type.indexOf('image') !== 0)
1927
-                {
1928
-                    imgField.attr('src',response.picture);
1926
+                if (file.type.indexOf('image') !== 0) {
1927
+                    imgField.attr('src', response.picture);
1929 1928
                 }
1930
-                imgField.parent().attr('href',response.url_download);
1929
+                imgField.parent().attr('href', response.url_download);
1931 1930
 
1932 1931
                 // lien d'edition
1933 1932
                 let editLink = bloc.find('.edit-name');
@@ -1954,7 +1953,6 @@ function initDropZone() {
1954 1953
     });
1955 1954
 
1956 1955
     Dropzone.prototype.filesize = function (bytes) {
1957
-        console.log(bytes);
1958 1956
 
1959 1957
         let prefix = '';
1960 1958
         let prefixes = [
@@ -1999,7 +1997,7 @@ function initDropZone() {
1999 1997
 
2000 1998
         $(file.previewElement).find('.dz-check,.dropdown').remove();
2001 1999
         $(file.previewElement).find('.text-danger').text(error);
2002
-        
2000
+
2003 2001
         $(document).phxUnlock();
2004 2002
         window.addEventListener("beforeunload", lockClose, true);
2005 2003
     });
@@ -2034,13 +2032,11 @@ function initDropZone() {
2034 2032
         }
2035 2033
     });
2036 2034
 
2037
-    window.addEventListener("beforeunload", function(event)
2038
-	{
2039
-		deleteAllTemporaryFilesRessources(dzWrapper);
2035
+    window.addEventListener("beforeunload", function (event) {
2036
+        deleteAllTemporaryFilesRessources(dzWrapper);
2040 2037
     }, true);
2041
-    
2042
-    dzWrapper.find(".list-group-item").parent().on("dragend dragenter dragleave dragover dragstart drop click",function(e)
2043
-    {
2038
+
2039
+    dzWrapper.find(".list-group-item").parent().on("dragend dragenter dragleave dragover dragstart drop click", function (e) {
2044 2040
         e.preventDefault();
2045 2041
     });
2046 2042
 
@@ -2059,5 +2055,4 @@ function deleteAllTemporaryFilesRessources(dzWrapper) {
2059 2055
 
2060 2056
         });
2061 2057
     }
2062
-}
2063
-
2058
+}

+ 373
- 0
assets/exclusive/js/back-office/learning_path/learning_path_editor_sequence_summary.js View File

@@ -0,0 +1,373 @@
1
+$(document).ready(function () {
2
+	// Initialiser le sommaire
3
+	initSequenceSummary();
4
+	
5
+	// Au redimentionnement de la fenêtre
6
+    $(window).on('phx-windows-resize', function () {
7
+		// Mettre à jour le sommaire des sequences
8
+		updateSequenceSummaryArrow($('.ali-EditorSequenceSummaryMask ul').css('top'));
9
+	});
10
+	
11
+	// Simuler un scroll pour lancer le calcule de la sequence affiché
12
+	$(".ali-EditorContentLeftPanel .simplebar-content").scroll();
13
+});
14
+
15
+// Indique si la flèche du haut et afficher ou non
16
+var arrowTop = 1;
17
+// Informe si l'action clique a été effecture sur l'un des élément du sommaire
18
+var sequenceSummaryClick = false;
19
+// Numéro du premier élément affiché dans le sommaire
20
+var firstSequenceShow = 0;
21
+// Numéro du dernier élément affiché dans le sommaire
22
+var lastSequenceShow = 0;
23
+
24
+
25
+/**
26
+ * Initialiser le sommaire des sequences
27
+ */
28
+function initSequenceSummary()
29
+{
30
+	// Mettre à jour la liste
31
+    updateSequenceSummaryList();
32
+
33
+	// Recalculer la taille que doit prendre la zone du sommaire des sequences
34
+    resizeSequenceSummary();
35
+
36
+    var sequenceContent = $('.ali-EditorSequenceSummary');
37
+    var maskSequenceList = sequenceContent.find('.ali-EditorSequenceSummaryMask');
38
+    var sequenceList = maskSequenceList.find('ul');
39
+    var sequences = sequenceList.find('li');
40
+
41
+    var sequenceFirst = sequences.first();
42
+    var sequenceHeight = parseInt(sequenceFirst.css('height')) + parseInt(sequenceFirst.css('margin-bottom'));
43
+
44
+    var animRunning = false;
45
+
46
+	// Click sur la flèche du bas
47
+    $(".ali-EditorSequenceSummary-down").click(function(){
48
+		// Effectuer l'action seulement s'il n'y a pas d'annimation en cours
49
+        if (!animRunning)
50
+        {
51
+			// Informer qu'on lance une animation
52
+			animRunning = true;
53
+			// Aubout de 500ms (durée de l'animation défini dans le css) informé que l'animation est terminée
54
+            setTimeout(function(){animRunning = false;}, 500);
55
+
56
+			// Calculer la nouvelle position que doit avoir la liste
57
+			// = sa position actuelle moins la hauteur de la zone d'affichage (ce qui a pour effet d'afficher les éléments suivants)
58
+			var newTop = parseInt(sequenceList.css('top')) - parseInt(maskSequenceList.height());
59
+			
60
+			// On actualiser l'affichage des flèches (si n'y a plus d'élément en dessous ne plus afficher la fleche du bas)
61
+            updateSequenceSummaryArrow(newTop);
62
+        }
63
+    });
64
+
65
+	// Click sur la flèche du haut
66
+    $(".ali-EditorSequenceSummary-up").click(function(){
67
+		// Effectuer l'action seulement s'il n'y a pas d'annimation en cours
68
+        if (!animRunning)
69
+        {
70
+			// Informer qu'on lance une animation
71
+            animRunning = true;
72
+			// Aubout de 500ms (durée de l'animation défini dans le css) informé que l'animation est terminée
73
+            setTimeout(function(){animRunning = false;}, 500);
74
+
75
+			// Calculer la nouvelle position que doit avoir la liste
76
+			// = sa position actuelle plus la hauteur de la zone d'affichage (ce qui a pour effet d'afficher les éléments précédents)
77
+            var newTop = parseInt(sequenceList.css('top')) + parseInt(maskSequenceList.height());
78
+            
79
+			// On actualiser l'affichage des flèches (si n'y a plus d'élément au dessus ne plus afficher la fleche du haut)
80
+            updateSequenceSummaryArrow(newTop);
81
+        }
82
+    });
83
+
84
+	// Mettre à jour l'affichage des flèches
85
+    updateSequenceSummaryArrow(0);
86
+
87
+	// Identifiant timer pour l'annuler si l'action est répété avant que ce dernier termine.
88
+	var idTimeout = null;
89
+	
90
+	// Au scroll du conteneur des sequences
91
+    $(".ali-EditorContentLeftPanel .simplebar-content").scroll(function() {
92
+		// Récupéré la position du scroll
93
+		var scrollTop = $(this).scrollTop();
94
+		// Si le scroll n'est pas causé par le clique sur un élément du sommaire de sequence
95
+		if (!sequenceSummaryClick)
96
+		{
97
+			// On ajouter une marge correspondant à la motier de l'écran
98
+			// Ce qui nous permet de dire que l'élément ciblé sur l'écran est celui qui se trouve le plus au centre de l'écran
99
+            scrollTop += $(this).height()/2;
100
+		};
101
+		
102
+		// Un repère pour savoir si on a trouvé l'élément le plus proche du centre de l'écrant pour ne pas tester les autres.
103
+		var find = false;
104
+		// On parcour la liste des sequences inversée et on cherche la séquence la plus proche au dessus (ou égale) du niveau "scrollTop"
105
+		// le égale est important si 'sequenceSummaryClick' est à 'true', car le scroll sera placer pile poile sur la sequence (donc =)
106
+        $($('.ali-EditorSequence').get().reverse()).each(function(id, elem){
107
+			// Tant qu'on n'a pas trouver la sequence la plus proche
108
+            if (!find)
109
+            {
110
+				// Si la séquence est au dessus (ou égale) du niveau "scrollTop", on la concidère la plus proche (comme on parours la liste à l'envers)
111
+                if ( (parseInt($(this).position().top)) <= scrollTop )
112
+                {
113
+					// On indique qu'on a trouvé
114
+					find = true;
115
+					// On récupère l'object dans le sommaire correspondant à la séquence trouvée
116
+					var object = $('#'+$(this).find('.ali-EditorSequenceHeadTitle').attr('id')+'Summary');
117
+					// S'il n'est pas déjà actif
118
+                    if (!object.hasClass('active'))
119
+                    {
120
+						// On désactive celui qui est actuellement actif
121
+						$('.ali-EditorSequenceSummaryMask ul li.active').removeClass('active');
122
+						// Et on active celui-là
123
+                        object.addClass('active');
124
+						
125
+						// Si l'on est pas dans le cas d'un clique sur le sommaire on peut supposer que 
126
+						// l'élément ciblé se trouve en dehors de la zone d'affichage du sommaire
127
+						// Donc afficher la bonne partie du sommaire pour que la séquence dans le sommaire soit visible.
128
+						if (!sequenceSummaryClick)
129
+						{
130
+							// Descendre ou monter pour afficher le niveau suivant ou précédent (pour avoir une animation sympa)
131
+							if (object.attr('data-num') < firstSequenceShow ) {
132
+								$(".ali-EditorSequenceSummary-up").click();
133
+							}
134
+							if (object.attr('data-num') > lastSequenceShow ) {
135
+								$(".ali-EditorSequenceSummary-down").click();
136
+							}
137
+
138
+							// Si l'élément n'est toujour pas affiché, aller directement sur lui
139
+							// Le time out est là pour que l'animation précédente
140
+							clearTimeout(idTimeout);
141
+							idTimeout = setTimeout(function() {
142
+								showSequencInSummary(object.attr('data-num'));
143
+							}, 500);
144
+						}
145
+                    }
146
+                    return;
147
+                }
148
+            }
149
+        });
150
+    });
151
+}
152
+
153
+/**
154
+ * Met à jour l'affichage des fleches sur le sommaire des sequences
155
+ * newTop INT La position de la liste sur laquelle se baser
156
+ */
157
+function updateSequenceSummaryArrow(newTop)
158
+{
159
+    if (!newTop) {
160
+        newTop = 0;
161
+    }
162
+    else {
163
+        newTop = parseInt(newTop);
164
+    }
165
+
166
+    var sequenceContent = $('.ali-EditorSequenceSummary');
167
+    var maskSequenceList = sequenceContent.find('.ali-EditorSequenceSummaryMask');
168
+    var sequenceList = maskSequenceList.find('ul');
169
+    var sequences = sequenceList.find('li');
170
+
171
+    var sequenceFirst = sequences.first();
172
+    var sequenceHeight = parseInt(sequenceFirst.css('height')) + parseInt(sequenceFirst.css('margin-bottom'));
173
+    
174
+    // Arrow down
175
+    if (-(newTop - parseInt(maskSequenceList.height())) >= parseInt(sequenceList.height()))
176
+    {
177
+        // Si Il n'y a que des éléménet au dessus de la zone basse d'affichage, ne pas afficher la fleche
178
+        newTop = -(parseInt(sequenceList.height()) - parseInt(maskSequenceList.height())  + 5);
179
+		// Seulement si elle est visible, la masquer
180
+		// La propriété visibility est utilisé car elle permet de masqué l'élément ici la flèche tout en reservant la taille qu'elle prend
181
+        if ($(".ali-EditorSequenceSummary-down").css("visibility") != 'hidden')
182
+        {
183
+            $(".ali-EditorSequenceSummary-down").css('visibility', 'hidden');
184
+        }
185
+    }
186
+    else if (parseInt(sequenceList.height()) + newTop > parseInt(maskSequenceList.height()))
187
+    {
188
+        // Si il a des élément en dessous de la zone basse d'affichage, afficher la fleche pour permettre de descendre
189
+        // Seulement si elle n'est pas visible
190
+		// La propriété visibility est utilisé car elle permet de masqué l'élément ici la flèche tout en reservant la taille qu'elle prend
191
+        if ($(".ali-EditorSequenceSummary-down").css("visibility") != 'visible')
192
+        {
193
+            $(".ali-EditorSequenceSummary-down").css('visibility', 'visible');
194
+        }
195
+    }
196
+        
197
+
198
+    // Arrow up
199
+    if ($(".ali-EditorSequenceSummary-down").css("visibility") != 'visible') {
200
+        // Si la fleche du bas n'est pas affiché, retirer la taille qu'elle devrais prendre et qui est du coup pris par un élément
201
+        newTop -= sequenceHeight;
202
+    }
203
+    if (newTop >= -sequenceHeight) {
204
+        // Si la position ne cache qu'un seul élément (à cause de la fleche) masquer la fleche
205
+        // Et positionner le top en haut, car rien de sert d'afficher de élément qui n'existe pas
206
+        newTop = -sequenceHeight;
207
+        // Seulement si elle est visible la masquer
208
+		// La propriété visibility est utilisé car elle permet de masqué l'élément ici la flèche tout en reservant la taille qu'elle prend
209
+        if ($(".ali-EditorSequenceSummary-up").css("visibility") != 'hidden')
210
+        {
211
+            $(".ali-EditorSequenceSummary-up").css('visibility', 'hidden');
212
+            arrowTop = 0;
213
+        }
214
+    }
215
+    else if (newTop != 0) {
216
+        // Sinon, s'il y a un décalage vers le haut, afficher la fleche pour permettre de remonter
217
+        // Seulement si elle n'est pas visible
218
+		// La propriété visibility est utilisé car elle permet de masqué l'élément ici la flèche tout en reservant la taille qu'elle prend
219
+        if ($(".ali-EditorSequenceSummary-up").css("visibility") != 'visible')
220
+        {
221
+            $(".ali-EditorSequenceSummary-up").css('visibility', 'visible');
222
+            arrowTop = 1;
223
+        }
224
+    }
225
+    sequenceList.css('top', newTop + 'px');
226
+    resizeSequenceSummary();
227
+
228
+    firstSequenceShow = -newTop/sequenceHeight + arrowTop;
229
+    lastSequenceShow = firstSequenceShow + maskSequenceList.height()/sequenceHeight - arrowTop;
230
+}
231
+
232
+/**
233
+ * Met à jour la liste des éléments composant le sommaire des sequences
234
+ */
235
+export function updateSequenceSummaryList()
236
+{
237
+	var sequenceList = $('.ali-EditorSequenceSummaryMask ul');
238
+	// Vider la liste
239
+    sequenceList.html('');
240
+
241
+    var sequences = $('.ali-EditorSequence');
242
+    
243
+    // Il y a moins de deux sequences, ne pas afficher le sommaire
244
+    if (sequences.length < 2) {
245
+        $('.ali-EditorSequenceSummary').addClass('d-none');
246
+    }
247
+    else
248
+    {
249
+        // Parcourir toutes les sequences
250
+        sequences.each(function(id, elem){
251
+            var _this = $(this);
252
+            var title = _this.find('.ali-EditorSequenceHeadTitle');
253
+
254
+            // Ajouter un élément dans la liste correspondant à la sequence courante
255
+            var li = $("<li>", {html:   'S'+(id+1), 
256
+                                title:  title.find('.ali-EditorSequenceHeadTitle-text').text(), 
257
+                                id:     title.attr('id')+'Summary',
258
+                                "data-target":	title.attr('id'),
259
+                                "data-num": (id+1)
260
+                            } ).appendTo(sequenceList).tooltip({
261
+                                placement: 'right', 
262
+                                template: '<div class="tooltip ali-EditorSequenceSummary-tooltip" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
263
+                            });
264
+
265
+            // Ajouter l'action au click permétant de scroller la page jusqu'à la sequence
266
+            li.click(function(){
267
+                // Préciser qu'on effecture une action click sur le sommaire (pour affecter le mode de ciblage des sequences qui est différent du scroll)
268
+                sequenceSummaryClick = true;
269
+                
270
+                // Animer le scroll
271
+                _this.parents('.simplebar-content').animate({
272
+                    scrollTop: title.position().top
273
+                }, 500, function(){
274
+                    // Par sécurité, après l'animation, déséléctionner l'élément représentant l'ancienne sequence séléctioné, et acrtiver la nouvelle)
275
+                    // Car la séléction à l'aide du scroll n'est pas fiable surtout pour le dernier élément car le scroll est bloqué à cause du fond de page.
276
+                    setTimeout(function(){
277
+                        sequenceList.find('li.active').removeClass('active');
278
+                        li.addClass('active');
279
+                        sequenceSummaryClick = false;
280
+                    }, 100);
281
+                });
282
+            });
283
+        });
284
+        
285
+        $('.ali-EditorSequenceSummary').removeClass('d-none');
286
+        
287
+        // Mettre à jour l'affichage des flèches.
288
+        updateSequenceSummaryArrow(sequenceList.css('top'));
289
+    }
290
+}
291
+
292
+/**
293
+ * Cible dans le sommaire la séquence que l'on désir afficher.
294
+ * num étant le numéro de la séquence correspondant à son ordre d'affichage (commençant à 1).
295
+ */
296
+function showSequencInSummary(num, force)
297
+{
298
+	if (typeof force == 'undefined') {
299
+		force = false;
300
+	}
301
+    if (num < firstSequenceShow || num > lastSequenceShow || force)
302
+    {
303
+        var sequenceContent = $('.ali-EditorSequenceSummary');
304
+        var maskSequenceList = sequenceContent.find('.ali-EditorSequenceSummaryMask');
305
+        var sequenceList = maskSequenceList.find('ul');
306
+        var sequences = sequenceList.find('li');
307
+        var sequenceFirst = sequences.first();
308
+        var sequenceHeight = parseInt(sequenceFirst.css('height')) + parseInt(sequenceFirst.css('margin-bottom'));
309
+
310
+        var top = (num-2) * sequenceHeight;
311
+        sequenceList.css('top', -top + "px");
312
+        updateSequenceSummaryArrow(-top)
313
+    }
314
+}
315
+
316
+/**
317
+ * Selectionne une sequence dans le sommaire et dans la vue
318
+ * -1 pour selectionner le dernier
319
+ */
320
+export function selectSequencInSummary(num)
321
+{
322
+	// Si c'est -1 c'est qu'on veut selectionner le dernier
323
+	if (num == -1) {
324
+		num = $('.ali-EditorSequence').length;
325
+	}
326
+	showSequencInSummary(num, true);
327
+
328
+	var elementInSummary = $('[data-num="'+num+'"]');
329
+	var sequence = $('#'+elementInSummary.attr('data-target'));
330
+
331
+	$('.ali-EditorSequenceHeadTitle-text').parents('.simplebar-content').animate({
332
+		scrollTop: sequence.position().top
333
+	}, 500, function(){
334
+		$('.ali-EditorSequenceSummaryMask ul li.active').removeClass('active');
335
+		elementInSummary.addClass('active');
336
+	});
337
+}
338
+
339
+/**
340
+ * Permet de définir la taille que doit prendre le sommaire et du coup le nombre d'élément affiché
341
+ */
342
+function resizeSequenceSummary()
343
+{
344
+	// On passe l'opacité des flèche à 1
345
+	// De base elle est à 0.01 (défini dans le css) car si on utilise display none, on ne peut pas connaitre sa taille tant que l'élément n'est pas affiché
346
+    $(".ali-EditorSequenceSummary-down, .ali-EditorSequenceSummary-up").css('opacity', 1);
347
+
348
+	// Le nombre maximum l'élément qu'on affiche dans le sommaire est de 9
349
+	var nbMaxSequence = 9;
350
+    var sequenceContent = $('.ali-EditorSequenceSummary');
351
+    var maskSequenceList = sequenceContent.find('.ali-EditorSequenceSummaryMask');
352
+    var sequenceList = maskSequenceList.find('ul');
353
+    var sequences = sequenceList.find('li');
354
+
355
+    var sequenceFirst = sequences.first();
356
+
357
+    var sequenceHeight = parseInt(sequenceFirst.css('height')) + parseInt(sequenceFirst.css('margin-bottom'));
358
+    var listHeight = sequenceContent.height();
359
+	
360
+	// On calcule en fonction de la taille de la page combien d'élément au maximum on peut afficher
361
+    var nbMaxListContent = Math.floor(listHeight / sequenceHeight);
362
+
363
+	// On garder le minimum entre le resultat trouvé et le maximum autorisé
364
+    var nbSequenceDisplayed = Math.min(nbMaxListContent, nbMaxSequence);
365
+
366
+	// On calcule et applique la taille du sommaire en retirant 2 espaces d'élément réservé pour les flèches
367
+    var maxHeight = (nbSequenceDisplayed - 2) * sequenceHeight;
368
+    maskSequenceList.height(maxHeight + "px");
369
+
370
+	// On affiche le sommaire
371
+	// De base elle est à 0.01 (défini dans le css) car si on utilise display none, on ne peut pas connaitre sa taille tant que l'élément n'est pas affiché
372
+    $(".ali-EditorSequenceSummaryMask").css('opacity', 1);
373
+}

+ 45
- 2
assets/exclusive/js/back-office/offer/menu_offer.js View File

@@ -1,5 +1,6 @@
1 1
 // gère la modal de création d'une session
2 2
 let phxInitCreateFromLibrary = require('../form_library_utility');
3
+let offerUtility = require('./offer_utility');
3 4
 //let sessionUtility = require('./session_utility');
4 5
 //let coworkerUtility = require('../utilities/coworker');
5 6
 
@@ -7,10 +8,52 @@ $('#modalCreateNewElementFromLibrary').on('load.phx.modal', function(event)
7 8
 {
8 9
 	let modal = $(this);
9 10
 
10
-// -- modal création session
11
+// -- modal création offre
11 12
 	if (modal.find('form[name="offer_create"]').length > 0)
12 13
 	{
13 14
 		// intialise le formulaire
14
-		phxInitCreateFromLibrary(modal);
15
+		phxInitCreateFromLibrary(modal, {
16
+			postError: function (response)
17
+			{
18
+				if (!response.success)
19
+				{
20
+					if (typeof response.formError.offer_create_isInter !== 'undefined')
21
+					{
22
+						let fields = modal.find('#offer_create_isInter, #offer_create_isIntra');
23
+						let fieldContainer = modal.find('#offer_create_type_content');
24
+
25
+						// Supprimer l'ancienne erreur sur ce champs s'il y est
26
+						let fieldError = modal.find('#offer_create_type_content .invalid-feedback');
27
+						if (fieldError.length > 0) {
28
+							fieldError.remove();
29
+						}
30
+						fields.addClass('ali-InputError').parent().find('.invalid-feedback').remove();
31
+
32
+						if (fieldContainer.length > 0)
33
+						{
34
+                            // Ajouter l'erreur
35
+							let span = $('<span>',{
36
+								class:'invalid-feedback mb-3 d-block'
37
+							}).text(response.formError.offer_create_isInter);
38
+
39
+							fieldContainer.append(span);
40
+						}
41
+					}
42
+				}
43
+
44
+			}
45
+		});
46
+
47
+		let fields = modal.find('#offer_create_isInter, #offer_create_isIntra');
48
+		fields.change(function(){
49
+			// Supprimer l'ancienne erreur sur ce champs s'il y est
50
+			let fieldError = modal.find('#offer_create_type_content .invalid-feedback');
51
+			if (fieldError.length > 0) {
52
+				fieldError.remove();
53
+			}
54
+		})
55
+
56
+		// initialise les types
57
+		offerUtility.initOfferTypes(modal);
15 58
 	}
16 59
 });

+ 108
- 34
assets/exclusive/js/back-office/offer/offer_edit.js View File

@@ -1,7 +1,25 @@
1 1
 let phxInitCreateFromLibrary = require('../form_library_utility');
2
+let offerUtility = require('./offer_utility');
3
+let programUtility  = require('../utilities/program');
2 4
 
3 5
 $(document).ready(function()
4 6
 {
7
+    let options = {
8
+        onchange: function (event)
9
+        {
10
+            // désactive le bouton
11
+            let button = $('form[name="program"] .ali-FormBox-submit a.btn,.ali-OfferFollow-colright a.btn');
12
+            button.attr('data-toggle','tooltip');
13
+            button.addClass('disabled-event');
14
+            button.tooltip();
15
+
16
+            button.on('click',function(event){
17
+                event.preventDefault();
18
+            });
19
+        }
20
+    };
21
+    programUtility.initProgram(options);
22
+
5 23
     // gère la modal d'édition d'une offre
6 24
     let modal = $('#modalEditThisOffer');
7 25
 
@@ -10,9 +28,53 @@ $(document).ready(function()
10 28
     if (form.length > 0)
11 29
     {
12 30
         // intialise le formulaire
13
-        phxInitCreateFromLibrary(form);
31
+        phxInitCreateFromLibrary(form, {
32
+			postError: function (response)
33
+			{
34
+				if (!response.success)
35
+				{
36
+                    // S'il ya une erreur concernant le type d'offre, prendre en main l'affichage de l'érreur
37
+					if (typeof response.formError.offer_update_isInter !== 'undefined')
38
+					{
39
+						let fields = modal.find('#offer_update_isInter, #offer_update_isIntra');
40
+						let fieldContainer = modal.find('#offer_update_type_content');
41
+
42
+						// Supprimer l'ancienne erreur sur ce champs s'il y est
43
+						let fieldError = modal.find('#offer_update_type_content .invalid-feedback');
44
+						if (fieldError.length > 0) {
45
+							fieldError.remove();
46
+						}
47
+                        fields.addClass('ali-InputError').parent().find('.invalid-feedback').remove();
48
+
49
+						if (fieldContainer.length > 0)
50
+						{
51
+                            // Ajouter l'erreur
52
+							let span = $('<span>',{
53
+								class:'invalid-feedback mb-3 d-block'
54
+							}).text(response.formError.offer_update_isInter);
55
+
56
+							fieldContainer.append(span);
57
+						}
58
+					}
59
+				}
60
+
61
+			}
62
+		});
63
+
64
+		let fields = modal.find('#offer_update_isInter, #offer_update_isIntra');
65
+		fields.change(function(){
66
+			// Supprimer l'ancienne erreur sur ce champs s'il y est
67
+			let fieldError = modal.find('#offer_update_type_content .invalid-feedback');
68
+			if (fieldError.length > 0) {
69
+				fieldError.remove();
70
+			}
71
+		})
14 72
     }
15 73
 
74
+    
75
+    // initialise les types
76
+    offerUtility.initOfferTypes(modal);
77
+
16 78
 // -- modal session
17 79
     var modalSession = $('#modalOfferAssociateSession');
18 80
     modalSession.on('load.phx.modal', function(event) {
@@ -69,43 +131,18 @@ $(document).ready(function()
69 131
             noResult.toggleClass('d-none', numResults > 0);
70 132
         });
71 133
 
72
-        // Gestion de la sélection
73
-        let submitButton = modalSession.find(".sessionSelection_submit");
74
-        let selectableRows = modalSession.find('[data-toggle="phxSelectSession"]');
75
-
76
-        selectableRows.each(function() {
77
-
78
-            let sessionRow = $(this);
79
-            let checkbox = sessionRow.find('input');
80
-
81
-            checkbox.on('change', function() {
82
-
83
-                let isChecked = $(this).prop('checked');
84
-
85
-                sessionRow.toggleClass('selected', isChecked);
86
-
87
-                let numSelected = selectableRows.filter('.selected').length;
88
-
89
-                if (numSelected > 0) 
90
-                {
91
-                    submitButton.prop('disabled', false);
92
-                    if (numSelected > 1) {
93
-                        submitButton.find('span').text('ces ' + numSelected + ' sessions');
94
-                    } else {
95
-                        submitButton.find('span').text('cette session');
96
-                    }
97
-                } 
98
-                else 
99
-                {
100
-                    submitButton.prop('disabled', true);
101
-                };                
102
-            });
134
+        // Selection des sessions
135
+        offerUtility.initLinkSession(modalSession, 'First');
136
+    });
103 137
 
104
-        });
138
+// -- modal programme de parcours
139
+    var modalLearningPathProgram = $('#modalOfferImportLearningPathProgram');
140
+    modalLearningPathProgram.on('load.phx.modal', function(event) {
141
+            offerUtility.initFormImportLearningPathProgram(modalLearningPathProgram);
105 142
     });
106 143
 
107 144
 	// Publication au catalogue
108
-	$('.ali-OfferInfosForum .custom-switch-indicator').click(function(event){
145
+	$('.ali-OfferInfosForum #switch-ali+.custom-switch-indicator').click(function(event){
109 146
         event.preventDefault();
110 147
         let target = $(this).parent().find('.custom-switch-input');
111 148
         
@@ -137,5 +174,42 @@ $(document).ready(function()
137 174
             });
138 175
         }
139 176
     });
177
+
178
+	// Activer achat
179
+	$('.ali-OfferInfosForum #switch-ali-sell+.custom-switch-indicator').click(function(event){
180
+        event.preventDefault();
181
+        let target = $(this).parent().find('.custom-switch-input');
182
+        
183
+        if (!target.prop('disabled'))
184
+        {
185
+            // get switch value
186
+            let newCheckValue = target[0].checked;
187
+            target.prop('checked', !newCheckValue);
188
+            target.prop('disabled', true);
189
+            // send via ajax
190
+            let url = target.data("url");
191
+
192
+            $.post({
193
+                url: url,
194
+                data: {sell: !newCheckValue},
195
+                dataType:"json",
196
+            }).done(function(response) {
197
+                if(response) {
198
+                    target.prop('checked', !newCheckValue);
199
+                }
200
+                else {
201
+                    target.prop('checked', newCheckValue);
202
+                }
203
+                
204
+                target.prop('disabled', false);
205
+            });
206
+        }
207
+    });
140 208
     
209
+
210
+    // Afficher nouveau formulaire du programme
211
+    $("#ali-OfferProgram-showForm").click(function(){
212
+        $("#ali-OfferProgram-form").removeClass('d-none');
213
+        $("#ali-OfferProgram-actions").hide();
214
+    });
141 215
 });

+ 9
- 0
assets/exclusive/js/back-office/offer/offer_import_learning_path.js View File

@@ -0,0 +1,9 @@
1
+let offerUtility = require('./offer_utility');
2
+
3
+$(document).ready(function()
4
+{
5
+	// -- modal parcours
6
+	let modalLearningPath = $('#modalCreateNewElementFromLibrary');
7
+
8
+	offerUtility.initFormImportLearningPathProgram(modalLearningPath);
9
+});

+ 59
- 0
assets/exclusive/js/back-office/offer/offer_import_session.js View File

@@ -0,0 +1,59 @@
1
+let offerUtility = require('./offer_utility');
2
+
3
+$(document).ready(function()
4
+{
5
+	// -- modal parcours
6
+	let modalSession = $('#modalCreateNewElementFromLibrary');
7
+
8
+	// Champ de recherche
9
+	let searchBar = modalSession.find('.sessionSelection_search');
10
+	let noResult = modalSession.find('.sessionSelection_noResult');
11
+
12
+	/**
13
+	 * Désactive la touche Entrée dans ce champ,
14
+	 * sinon ça valide le formulaire.
15
+	 */
16
+	searchBar.on('keypress', function(event) {
17
+		if (event.which == 13) {
18
+			return false;
19
+		}
20
+	});
21
+
22
+	searchBar.on('keyup', function() {
23
+
24
+		let term = $(this).val();
25
+		term = term.trim();
26
+		term = term.replace(/\s+/g, ' ');
27
+
28
+		let words = term.split(' ');
29
+
30
+		let numResults = 0;
31
+
32
+		modalSession.find('[data-phx-filterable]').each(function() {
33
+
34
+			let filterTest = $(this).attr('data-phx-filterable');
35
+
36
+			for (let i in words) {
37
+				let regexp = new RegExp(words[i], 'i');
38
+
39
+				if (!regexp.test(filterTest)) {
40
+					// Un mot non trouvé = on cache
41
+					$(this).addClass('filter-not-match');
42
+					return;
43
+				}
44
+			}
45
+
46
+			// Si on arrive ici c'est qu'on a trouvé tous les mots
47
+			$(this).removeClass('filter-not-match');
48
+
49
+			++numResults;
50
+		});
51
+
52
+		// Affichage du message "aucun résultat"
53
+		noResult.toggleClass('d-none', numResults > 0);
54
+	}); 
55
+
56
+	// Selection des sessions
57
+	offerUtility.initLinkSession(modalSession, 'modalOfferSessionImport');
58
+
59
+});

+ 165
- 0
assets/exclusive/js/back-office/offer/offer_utility.js View File

@@ -0,0 +1,165 @@
1
+"use strict";
2
+let phxInitCreateFromLibrary = require('../form_library_utility');
3
+
4
+module.exports = {
5
+    initOfferTypes : (function(target)
6
+    {
7
+		target.find('.content_offer_isInter, .content_offer_isIntra').css('min-width', '100%');
8
+		function checkOfferTypeInter()
9
+		{
10
+			// Test sur type inter
11
+			if (target.find('.offer_isInter').is(':checked')) {
12
+				target.find('.content_offer_isInter').hide().removeClass('d-none').show(200);
13
+			}
14
+			else {
15
+				target.find('.content_offer_isInter').hide(200, function(){$(this).addClass('d-none')});
16
+			}
17
+		}
18
+
19
+		function checkOfferTypeIntra()
20
+		{
21
+			// Test sur type intra
22
+			if (target.find('.offer_isIntra').is(':checked')) {
23
+				target.find('.content_offer_isIntra').hide().removeClass('d-none').show(200);
24
+			}
25
+			else {
26
+				target.find('.content_offer_isIntra').hide(200, function(){$(this).addClass('d-none')});
27
+			}
28
+		}
29
+		
30
+		checkOfferTypeInter();
31
+		checkOfferTypeIntra();
32
+
33
+		// Au changement
34
+		target.find('.offer_isInter').change(function(){
35
+			checkOfferTypeInter();
36
+		});
37
+		target.find('.offer_isIntra').change(function(){
38
+			checkOfferTypeIntra();
39
+		});
40
+	}),
41
+	initLinkSession : (function(container, stepName)
42
+	{
43
+		// Gestion de la sélection
44
+		let submitButton = container.find(".sessionSelection_submit");
45
+		let selectableRows = container.find('[data-toggle="phxSelectSession"]');
46
+
47
+		selectableRows.each(function() {
48
+
49
+			let sessionRow = $(this);
50
+			let checkbox = sessionRow.find('input');
51
+
52
+			checkbox.on('change', function() {
53
+
54
+				let isChecked = $(this).prop('checked');
55
+
56
+				sessionRow.toggleClass('selected', isChecked);
57
+
58
+				let numSelected = selectableRows.filter('.selected').length;
59
+
60
+				if (numSelected > 0) 
61
+				{
62
+					submitButton.prop('disabled', false);
63
+					if (numSelected > 1) {
64
+						submitButton.find('span').text('ces ' + numSelected + ' sessions');
65
+					} else {
66
+						submitButton.find('span').text('cette session');
67
+					}
68
+				} 
69
+				else 
70
+				{
71
+					submitButton.prop('disabled', true);
72
+				};                
73
+			});
74
+
75
+		});
76
+
77
+		// cible les formulaire de la première étape
78
+		container.find('[data-modal-step="'+ stepName +'"] form').each(function()
79
+		{
80
+			// validation du formulaire en ajax
81
+			let form = $(this);
82
+			phxInitCreateFromLibrary(form,
83
+			{
84
+				postSucces: function (response)
85
+				{
86
+					// redirige la page en cas de demande de redirection
87
+					if (response.urlRedirect)
88
+					{
89
+						if (window.location.href == response.urlRedirect)
90
+						{
91
+							window.location.reload();
92
+						}
93
+						else
94
+						{
95
+							// On est sur la liste on reactualise la page
96
+							window.location.href = response.urlRedirect;
97
+						}
98
+					}
99
+					// ajoute une étape à la modal
100
+					else
101
+					{
102
+						// insert le pannel
103
+						container.find('.modal-content').append(response.html);
104
+
105
+						// affiche le pannel
106
+						$.phoenix.showPannel(form.parents('[data-modal-step]'),'from-right','resumeOffer');
107
+
108
+						// initialise le pannel
109
+						let pannel =container.find('[data-modal-step="resumeOffer"]');
110
+						pannel.find('[data-modal-trigger="'+ stepName +'"]').on('click',function()
111
+						{
112
+							pannel.remove();
113
+						});
114
+
115
+						phxInitCreateFromLibrary(pannel.find('form'));
116
+
117
+
118
+						// @FIXME
119
+
120
+					}
121
+				}
122
+			});
123
+		})
124
+	}),
125
+	initFormImportLearningPathProgram : (function(container)
126
+	{
127
+		// Champ de recherche
128
+		let searchBar = container.find('.pathSelection_search');
129
+		let noResult = container.find('.pathSelection_noResult');
130
+	
131
+		searchBar.on('keyup', function() {
132
+	
133
+		let term = $(this).val();
134
+		term = term.trim();
135
+		term = term.replace(/\s+/g, ' ');
136
+	
137
+		let words = term.split(' ');
138
+	
139
+		let numResults = 0;
140
+	
141
+		container.find('[data-phx-filterable]').each(function() {
142
+	
143
+			let filterTest = $(this).attr('data-phx-filterable');
144
+	
145
+			for (let i in words) {
146
+				let regexp = new RegExp(words[i], 'i');
147
+	
148
+				if (!regexp.test(filterTest)) {
149
+					// Un mot non trouvé = on cache
150
+					$(this).addClass('filter-not-match');
151
+					return;
152
+				}
153
+			}
154
+	
155
+			// Si on arrive ici c'est qu'on a trouvé tous les mots
156
+			$(this).removeClass('filter-not-match');
157
+	
158
+			++numResults;
159
+		});
160
+	
161
+		// Affichage du message "aucun résultat"
162
+		noResult.toggleClass('d-none', numResults > 0);
163
+		}); 
164
+	})
165
+};

+ 0
- 1
assets/exclusive/js/back-office/person/tab/notices.js View File

@@ -45,7 +45,6 @@ module.exports = function ()
45 45
 		let attribut = 'data-phx-remote-select';
46 46
 		let remote = _this.find('[' + attribut + ']')
47 47
 		let selectInput = remote.attr(attribut);
48
-		console.log(selectInput);
49 48
 		new PHXRemoteSelect(this, {
50 49
 			selectInput: selectInput,
51 50
 		});

+ 31
- 12
assets/exclusive/js/back-office/session/create/menu_session.js View File

@@ -3,30 +3,49 @@ let phxInitCreateFromLibrary = require('../../form_library_utility');
3 3
 let sessionUtility = require('./session_utility');
4 4
 let coworkerUtility = require('../../utilities/coworker');
5 5
 let utility = require('../../utilities/utility');
6
-let personUtility  = require('../../person/person_utility');
6
+let personUtility = require('../../person/person_utility');
7 7
 let societyUtility = require('../../utilities/society');
8 8
 
9
-$('#modalCreateNewElementFromLibrary').on('load.phx.modal', function(event)
10
-{
9
+$('#modalCreateNewElementFromLibrary').on('load.phx.modal', function (event) {
11 10
 	let modal = $(this);
12 11
 
13
-// -- Création session
14
-	let sessionCreationForm = modal.find('form[name="session_create"]');
15
-	if (sessionCreationForm.length > 0)
16
-	{
12
+	// -- Création session classique
13
+	let sessionFixedForm = modal.find('form[name="session_create"]');
14
+	if (sessionFixedForm.length > 0) {
17 15
 		// intialise le formulaire
18
-		phxInitCreateFromLibrary(sessionCreationForm);
16
+		phxInitCreateFromLibrary(sessionFixedForm);
19 17
 
20 18
 		// initialise date début < date fin
21
-		sessionUtility.initSessionDates(sessionCreationForm);
19
+		sessionUtility.initSessionDates(sessionFixedForm);
22 20
 
23 21
 		// initialise la recherche de référence pédagogique
24
-		coworkerUtility.initCoworkerSearch(sessionCreationForm);
22
+		coworkerUtility.initCoworkerSearch(sessionFixedForm);
25 23
 
26 24
 		// Initialise le changement de type
27
-		sessionUtility.initTypeSession(sessionCreationForm);	
25
+		sessionUtility.initTypeSession(sessionFixedForm);
26
+
27
+		// initialise la zone pour activer les notification email du forum
28
+		sessionUtility.initAreaNotifyMailForum(sessionFixedForm);
29
+	}
30
+
31
+	// -- Création session ouverte
32
+	let sessionOpenForm = modal.find('form[name="session_open_create"]');
33
+	if (sessionOpenForm.length > 0) {
34
+		// intialise le formulaire
35
+		phxInitCreateFromLibrary(sessionOpenForm);
36
+
37
+		// initialise date début < date fin
38
+		sessionUtility.initSessionOpenDates(sessionOpenForm);
39
+
40
+		// initialise la recherche de référence pédagogique
41
+		coworkerUtility.initCoworkerSearch(sessionOpenForm);
42
+
43
+		// initialise la zone pour activer les notification email du forum
44
+		sessionUtility.initAreaNotifyMailForum(sessionOpenForm);
28 45
 	}
29 46
 
30 47
 	// -- Création collaborateur
31
-	sessionUtility.initCoworkerCreate(modal); 	
48
+	sessionUtility.initCoworkerCreate(modal);
49
+
50
+
32 51
 });

+ 267
- 254
assets/exclusive/js/back-office/session/create/session_edit.js View File

@@ -2,46 +2,41 @@ let phxInitCreateFromLibrary = require('../../form_library_utility');
2 2
 let sessionUtility = require('./session_utility');
3 3
 let coworker = require('../../utilities/coworker');
4 4
 let utility = require('../../utilities/utility');
5
-let personUtility  = require('../../person/person_utility');
6
-let societyUtility  = require('../../utilities/society');
5
+let offerUtility = require('../../offer/offer_utility');
6
+let personUtility = require('../../person/person_utility');
7
+let societyUtility = require('../../utilities/society');
7 8
 import phxRemoveAccents from '../../../../../modules/phxRemoveAccents';
8
-let PHXRemoteSelect = require ('../../../../../shared/js/classes/PHXRemoteSelect');
9
+let PHXRemoteSelect = require('../../../../../shared/js/classes/PHXRemoteSelect');
10
+let programUtility = require('../../utilities/program');
9 11
 
10
-
11
-$(document).ready(function()
12
-{
12
+$(document).ready(function () {
13 13
 	initVirtualClassButtons();
14
-	
15
-    // gère la modal d'édition d'une session
14
+
15
+	programUtility.initProgram();
16
+
17
+	// gère la modal d'édition d'une session
16 18
 	let modal = $('#modalEditThisSession');
17
-	if (modal.find('.ali-focus').length > 0)
18
-	{
19
+	if (modal.find('.ali-focus').length > 0) {
19 20
 		modal.modal('show');
20 21
 	}
21 22
 
22 23
 	// événement lors de l'affichage de l'onglet
23
-	$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e)
24
-	{
24
+	$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
25 25
 		let id = $(e.currentTarget).attr('aria-controls');
26
-		switch (id)
27
-		{
26