154 lines
4.0 KiB
Markdown
154 lines
4.0 KiB
Markdown
|
|
# Documentación de CourseNav.js
|
||
|
|
|
||
|
|
**Versión:** 1.1.5
|
||
|
|
**Autor:** Salvador Martínez Gaytán
|
||
|
|
**Licencia:** Comercial Propietaria
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Descripción
|
||
|
|
|
||
|
|
**CourseNav.js** es una librería en Vanilla JS para gestionar:
|
||
|
|
|
||
|
|
- Carga dinámica de contenido (HTML + scripts)
|
||
|
|
- Navegación “prev/next” con bloqueo hasta completar cada slide
|
||
|
|
- Integración con SCORM (pipwerks wrapper)
|
||
|
|
- Control de audio avanzado (Howler.js)
|
||
|
|
- Diálogos de inicio/retomar con SweetAlert2
|
||
|
|
- Barra de progreso y eventos custom
|
||
|
|
|
||
|
|
No depende de jQuery, Swiper ni Bootstrap, y funciona incluso con CSP/CORS restrictivos.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Prerrequisitos
|
||
|
|
|
||
|
|
Antes de `coursenav.js` debes incluir en tu HTML:
|
||
|
|
|
||
|
|
```html
|
||
|
|
<script src="path/to/pipwerks-scorm.js"></script>
|
||
|
|
<script src="path/to/howler.core.min.js"></script>
|
||
|
|
<script src="path/to/sweetalert2.all.min.js"></script>
|
||
|
|
<script src="path/to/coursenav.js"></script>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Estructura del DOM requerida
|
||
|
|
|
||
|
|
```html
|
||
|
|
<div id="main-content"></div>
|
||
|
|
<div id="loader-course" style="display:none"></div>
|
||
|
|
<button id="prev-btn">Prev</button>
|
||
|
|
<button id="next-btn">Next</button>
|
||
|
|
<div id="progress-bar"></div>
|
||
|
|
|
||
|
|
<button id="audio-control"></button>
|
||
|
|
<i id="audio-icon"></i>
|
||
|
|
<svg><circle id="progress-circle" r="50"></circle></svg>
|
||
|
|
```
|
||
|
|
|
||
|
|
> Si cambias los IDs, ajusta las llamadas a `document.getElementById(...)` en el código.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Inicialización automática
|
||
|
|
|
||
|
|
Al cargarse el DOM, CourseNav:
|
||
|
|
|
||
|
|
1. Inicializa SCORM o sessionStorage
|
||
|
|
2. Carga `config.json` mediante XHR con cookies y cabecera `X-Requested-With`
|
||
|
|
3. Construye el array `courseData.contentArray`
|
||
|
|
4. Muestra diálogo “Retomar / Comenzar de nuevo” o arranca el curso
|
||
|
|
5. Carga el primer slide e instala la navegación
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## API pública
|
||
|
|
|
||
|
|
```js
|
||
|
|
const CN = window.CourseNav;
|
||
|
|
```
|
||
|
|
|
||
|
|
### Control de Audio
|
||
|
|
|
||
|
|
- `CN.audioController`
|
||
|
|
- `loadAudio(url)`
|
||
|
|
- `playAudio()`, `pauseAudio()`, `stopAudio()`
|
||
|
|
- `toggleAudio()`, `toggleMute()`
|
||
|
|
- `CN.createSound(audioUrl)` → retorna `ExtendedHowl`
|
||
|
|
- `CN.soundClick()` → reproduce sonido de clic
|
||
|
|
- `CN.isDebug()` → `true` si debug activo
|
||
|
|
|
||
|
|
### Navegación de Slides
|
||
|
|
|
||
|
|
- `CN.nextSlide()`, `CN.prevSlide()`
|
||
|
|
- `CN.gotoSlide(index)` → salta a slide validado
|
||
|
|
- `CN.isVisited()` → `true` si slide actual ya visitado
|
||
|
|
- `CN.isCompletedSlideIndex(idx)` → `visited` de slide `idx`
|
||
|
|
- `CN.getCurrentSlide()` → `{ title, content, audio, visited }`
|
||
|
|
- `CN.setSlideVisited([state])` → marca visitado + dispara evento
|
||
|
|
- `CN.markSlidesAsVisited(indicesArray)`
|
||
|
|
- `CN.updateProgressBar()` → refresca `#progress-bar`
|
||
|
|
|
||
|
|
### SCORM / Progreso
|
||
|
|
|
||
|
|
- `CN.getStudentName()`
|
||
|
|
- `CN.getLessonLocation()`, `CN.setLessonLocation(loc)`
|
||
|
|
- `CN.getLessonStatus()`, `CN.setLessonStatus(status)`
|
||
|
|
- `CN.getScore()`, `CN.setScore(score)`
|
||
|
|
- `CN.getSuspendData()`, `CN.setSuspendData(data)`
|
||
|
|
- `CN.getScormData(key)`, `CN.setScormData(key,value)`
|
||
|
|
- `CN.save()` → guarda en SCORM o sessionStorage
|
||
|
|
- `CN.completeLesson()` → marca estado SCORM “completed”
|
||
|
|
|
||
|
|
### Utilitarios
|
||
|
|
|
||
|
|
- `CN.resetCourse()` → reinicia todo el progreso
|
||
|
|
- `CN.reload()` → recarga slide actual
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Eventos personalizados
|
||
|
|
|
||
|
|
```js
|
||
|
|
document.body.addEventListener("slideChange", e => {
|
||
|
|
console.log("Slide cambiado:", e.detail.slideIndex);
|
||
|
|
});
|
||
|
|
|
||
|
|
document.body.addEventListener("slideCompleted", e => {
|
||
|
|
console.log("Slide completado:", e.detail.slideIndex);
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
> `e.detail` contiene `{ message, slideIndex, totalSlides, slide }`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Ejemplos de uso
|
||
|
|
|
||
|
|
### Saltar a un slide
|
||
|
|
|
||
|
|
```js
|
||
|
|
CourseNav.gotoSlide(4); // va al slide índice 4
|
||
|
|
```
|
||
|
|
|
||
|
|
### Control de audio desde UI
|
||
|
|
|
||
|
|
```html
|
||
|
|
<button id="audio-control">🔊</button>
|
||
|
|
<script>
|
||
|
|
document.getElementById("audio-control")
|
||
|
|
.addEventListener("click", () => CourseNav.audioController.toggleMute());
|
||
|
|
</script>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Notas técnicas
|
||
|
|
|
||
|
|
- **XHR** en `loadConfig()` para sortear CSP/CORS de SuccessFactors.
|
||
|
|
- **executeInjectedScripts()** re-ejecuta `<script>` externos e inline tras `innerHTML`.
|
||
|
|
- **ExtendedHowl** incluye evento `onTimeUpdate` cada 250 ms.
|
||
|
|
- No hay dependencias externas (jQuery/Swiper/Bootstrap).
|