From f5a144b8f728e5ceddb5b1799d56b056270918cb Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Wed, 10 Mar 2021 16:07:03 +0100 Subject: [PATCH] wip #4333 @2 --- .idea/.gitignore | 8 + .idea/deployment.xml | 343 ++++++++++ .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/scorm-scroll.iml | 9 + .idea/vcs.xml | 6 + images/ VM-law.svg | 73 +++ images/ VM-poor-safety.svg | 34 + images/ VM-risk-assesment.svg | 21 + images/ VM-risk-emplyoer.svg | 81 +++ images/ VM-risk-managers.svg | 61 ++ images/ VM-risk-work-alone.svg | 20 + images/ VM-risk-working.svg | 22 + images/ VM-tools-check.svg | 27 + images/ VM-tools-inspect.svg | 20 + images/ VM-tools-powertools.svg | 34 + images/ VM-tools-using.svg | 17 + images/ VM-tools-usingtools.svg | 33 + images/ VM-working-safely.svg | 29 + images/ VM-zero-harm.svg | 17 + images/VM-checklist-tick.svg | 1 + images/VM-confined-space.svg | 25 + images/VM-cpe.svg | 67 ++ images/VM-enclosed-space.svg | 20 + images/VM-fall.svg | 1 + images/VM-fire-extinguish.svg | 53 ++ images/VM-first-aid-appointed-person.svg | 21 + images/VM-first-aid-facilities.svg | 27 + images/VM-first-aid-help.svg | 34 + images/VM-first-aid-manager.svg | 22 + images/VM-first-aid-role.svg | 29 + images/VM-first-aid.svg | 20 + images/VM-gas-white.svg | 1 + images/VM-gas.svg | 1 + images/VM-hazardous-atmosphere.svg | 49 ++ images/VM-healthandsafety.svg | 75 +++ images/VM-heart-line-purple.svg | 98 +++ images/VM-heart-line.svg | 98 +++ images/VM-hurt.svg | 1 + images/VM-injury.svg | 1 + images/VM-logo-white.png | Bin 0 -> 20802 bytes images/VM-machine-injury.svg | 1 + images/VM-notify-computer-purple.svg | 1 + images/VM-notify-computer.svg | 1 + images/VM-risks.svg | 19 + images/VM-safety-everyone.svg | 32 + images/VM-shouting.svg | 1 + images/VM-small-squiggle-purple.svg | 42 ++ images/VM-small-squiggle.svg | 42 ++ images/VM-squiggle-line.svg | 61 ++ images/VM-traffic accident.svg | 1 + images/VM-wrist.svg | 1 + images/checklist-tick-purple.svg | 1 + images/example-button-white.svg | 41 ++ images/example-button.svg | 41 ++ images/html-header-firstaid.svg | 697 ++++++++++++++++++++ images/html-header-hand-tools.svg | 764 ++++++++++++++++++++++ images/html-header-lone-working.svg | 704 +++++++++++++++++++++ images/html-header-safely.svg | 769 +++++++++++++++++++++++ images/number-1-roundal-white.svg | 62 ++ images/number-1-roundal.svg | 62 ++ images/number-2-roundal-white.svg | 62 ++ images/number-2-roundal.svg | 62 ++ images/number-3-roundal-white.svg | 62 ++ images/number-3-roundal.svg | 62 ++ images/number-4-roundal-white.svg | 62 ++ images/number-4-roundal.svg | 62 ++ images/number-5-roundal-white.svg | 62 ++ images/number-5-roundal.svg | 62 ++ images/number-6-roundal-white.svg | 62 ++ images/number-6-roundal.svg | 62 ++ images/number-7-roundal-white.svg | 62 ++ images/number-7-roundal.svg | 62 ++ images/number-8-roundal-white.svg | 62 ++ images/number-8-roundal.svg | 62 ++ images/teardrop-purple.svg | 19 + images/teardrop-red.svg | 19 + images/teardrop-white.svg | 19 + imsmanifest.xml | 27 + index.html | 339 ++++++++++ scorm-scroll.min.js | 1 + scripts/compile.bat | 1 + scripts/project.js | 13 + scripts/scorm-wrapper.js | 735 ++++++++++++++++++++++ scripts/scorm.js | 463 ++++++++++++++ 85 files changed, 7360 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/deployment.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scorm-scroll.iml create mode 100644 .idea/vcs.xml create mode 100644 images/ VM-law.svg create mode 100644 images/ VM-poor-safety.svg create mode 100644 images/ VM-risk-assesment.svg create mode 100644 images/ VM-risk-emplyoer.svg create mode 100644 images/ VM-risk-managers.svg create mode 100644 images/ VM-risk-work-alone.svg create mode 100644 images/ VM-risk-working.svg create mode 100644 images/ VM-tools-check.svg create mode 100644 images/ VM-tools-inspect.svg create mode 100644 images/ VM-tools-powertools.svg create mode 100644 images/ VM-tools-using.svg create mode 100644 images/ VM-tools-usingtools.svg create mode 100644 images/ VM-working-safely.svg create mode 100644 images/ VM-zero-harm.svg create mode 100644 images/VM-checklist-tick.svg create mode 100644 images/VM-confined-space.svg create mode 100644 images/VM-cpe.svg create mode 100644 images/VM-enclosed-space.svg create mode 100644 images/VM-fall.svg create mode 100644 images/VM-fire-extinguish.svg create mode 100644 images/VM-first-aid-appointed-person.svg create mode 100644 images/VM-first-aid-facilities.svg create mode 100644 images/VM-first-aid-help.svg create mode 100644 images/VM-first-aid-manager.svg create mode 100644 images/VM-first-aid-role.svg create mode 100644 images/VM-first-aid.svg create mode 100644 images/VM-gas-white.svg create mode 100644 images/VM-gas.svg create mode 100644 images/VM-hazardous-atmosphere.svg create mode 100644 images/VM-healthandsafety.svg create mode 100644 images/VM-heart-line-purple.svg create mode 100644 images/VM-heart-line.svg create mode 100644 images/VM-hurt.svg create mode 100644 images/VM-injury.svg create mode 100644 images/VM-logo-white.png create mode 100644 images/VM-machine-injury.svg create mode 100644 images/VM-notify-computer-purple.svg create mode 100644 images/VM-notify-computer.svg create mode 100644 images/VM-risks.svg create mode 100644 images/VM-safety-everyone.svg create mode 100644 images/VM-shouting.svg create mode 100644 images/VM-small-squiggle-purple.svg create mode 100644 images/VM-small-squiggle.svg create mode 100644 images/VM-squiggle-line.svg create mode 100644 images/VM-traffic accident.svg create mode 100644 images/VM-wrist.svg create mode 100644 images/checklist-tick-purple.svg create mode 100644 images/example-button-white.svg create mode 100644 images/example-button.svg create mode 100644 images/html-header-firstaid.svg create mode 100644 images/html-header-hand-tools.svg create mode 100644 images/html-header-lone-working.svg create mode 100644 images/html-header-safely.svg create mode 100644 images/number-1-roundal-white.svg create mode 100644 images/number-1-roundal.svg create mode 100644 images/number-2-roundal-white.svg create mode 100644 images/number-2-roundal.svg create mode 100644 images/number-3-roundal-white.svg create mode 100644 images/number-3-roundal.svg create mode 100644 images/number-4-roundal-white.svg create mode 100644 images/number-4-roundal.svg create mode 100644 images/number-5-roundal-white.svg create mode 100644 images/number-5-roundal.svg create mode 100644 images/number-6-roundal-white.svg create mode 100644 images/number-6-roundal.svg create mode 100644 images/number-7-roundal-white.svg create mode 100644 images/number-7-roundal.svg create mode 100644 images/number-8-roundal-white.svg create mode 100644 images/number-8-roundal.svg create mode 100644 images/teardrop-purple.svg create mode 100644 images/teardrop-red.svg create mode 100644 images/teardrop-white.svg create mode 100644 imsmanifest.xml create mode 100644 index.html create mode 100644 scorm-scroll.min.js create mode 100644 scripts/compile.bat create mode 100644 scripts/project.js create mode 100644 scripts/scorm-wrapper.js create mode 100644 scripts/scorm.js diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..edf4bc2 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/../../../../../../:\Users\vince\Works\scorm-scroll\.idea/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..4d7d1a3 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..bf84b09 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..12c8494 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/scorm-scroll.iml b/.idea/scorm-scroll.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/scorm-scroll.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/images/ VM-law.svg b/images/ VM-law.svg new file mode 100644 index 0000000..7f35445 --- /dev/null +++ b/images/ VM-law.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-poor-safety.svg b/images/ VM-poor-safety.svg new file mode 100644 index 0000000..ec61780 --- /dev/null +++ b/images/ VM-poor-safety.svg @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/images/ VM-risk-assesment.svg b/images/ VM-risk-assesment.svg new file mode 100644 index 0000000..315e88c --- /dev/null +++ b/images/ VM-risk-assesment.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/images/ VM-risk-emplyoer.svg b/images/ VM-risk-emplyoer.svg new file mode 100644 index 0000000..f147568 --- /dev/null +++ b/images/ VM-risk-emplyoer.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-risk-managers.svg b/images/ VM-risk-managers.svg new file mode 100644 index 0000000..abb53f7 --- /dev/null +++ b/images/ VM-risk-managers.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-risk-work-alone.svg b/images/ VM-risk-work-alone.svg new file mode 100644 index 0000000..4771ee0 --- /dev/null +++ b/images/ VM-risk-work-alone.svg @@ -0,0 +1,20 @@ + + + + + + diff --git a/images/ VM-risk-working.svg b/images/ VM-risk-working.svg new file mode 100644 index 0000000..2ed04da --- /dev/null +++ b/images/ VM-risk-working.svg @@ -0,0 +1,22 @@ + + + + + + diff --git a/images/ VM-tools-check.svg b/images/ VM-tools-check.svg new file mode 100644 index 0000000..cb523bc --- /dev/null +++ b/images/ VM-tools-check.svg @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/images/ VM-tools-inspect.svg b/images/ VM-tools-inspect.svg new file mode 100644 index 0000000..9c000e6 --- /dev/null +++ b/images/ VM-tools-inspect.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/images/ VM-tools-powertools.svg b/images/ VM-tools-powertools.svg new file mode 100644 index 0000000..ee1545c --- /dev/null +++ b/images/ VM-tools-powertools.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-tools-using.svg b/images/ VM-tools-using.svg new file mode 100644 index 0000000..eaf753b --- /dev/null +++ b/images/ VM-tools-using.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/images/ VM-tools-usingtools.svg b/images/ VM-tools-usingtools.svg new file mode 100644 index 0000000..b7b0734 --- /dev/null +++ b/images/ VM-tools-usingtools.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-working-safely.svg b/images/ VM-working-safely.svg new file mode 100644 index 0000000..b8d66b4 --- /dev/null +++ b/images/ VM-working-safely.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/images/ VM-zero-harm.svg b/images/ VM-zero-harm.svg new file mode 100644 index 0000000..09b1545 --- /dev/null +++ b/images/ VM-zero-harm.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/images/VM-checklist-tick.svg b/images/VM-checklist-tick.svg new file mode 100644 index 0000000..9f7acfa --- /dev/null +++ b/images/VM-checklist-tick.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-confined-space.svg b/images/VM-confined-space.svg new file mode 100644 index 0000000..a7df3e6 --- /dev/null +++ b/images/VM-confined-space.svg @@ -0,0 +1,25 @@ + + + + + + + diff --git a/images/VM-cpe.svg b/images/VM-cpe.svg new file mode 100644 index 0000000..2143bd3 --- /dev/null +++ b/images/VM-cpe.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + diff --git a/images/VM-enclosed-space.svg b/images/VM-enclosed-space.svg new file mode 100644 index 0000000..ddd89b6 --- /dev/null +++ b/images/VM-enclosed-space.svg @@ -0,0 +1,20 @@ + + + + + + + diff --git a/images/VM-fall.svg b/images/VM-fall.svg new file mode 100644 index 0000000..2c405ff --- /dev/null +++ b/images/VM-fall.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-fire-extinguish.svg b/images/VM-fire-extinguish.svg new file mode 100644 index 0000000..f5fea67 --- /dev/null +++ b/images/VM-fire-extinguish.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + diff --git a/images/VM-first-aid-appointed-person.svg b/images/VM-first-aid-appointed-person.svg new file mode 100644 index 0000000..fa8f84e --- /dev/null +++ b/images/VM-first-aid-appointed-person.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/images/VM-first-aid-facilities.svg b/images/VM-first-aid-facilities.svg new file mode 100644 index 0000000..2322b07 --- /dev/null +++ b/images/VM-first-aid-facilities.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/images/VM-first-aid-help.svg b/images/VM-first-aid-help.svg new file mode 100644 index 0000000..af05686 --- /dev/null +++ b/images/VM-first-aid-help.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/VM-first-aid-manager.svg b/images/VM-first-aid-manager.svg new file mode 100644 index 0000000..ef3d381 --- /dev/null +++ b/images/VM-first-aid-manager.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/images/VM-first-aid-role.svg b/images/VM-first-aid-role.svg new file mode 100644 index 0000000..f20d57e --- /dev/null +++ b/images/VM-first-aid-role.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/VM-first-aid.svg b/images/VM-first-aid.svg new file mode 100644 index 0000000..b968a0e --- /dev/null +++ b/images/VM-first-aid.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/images/VM-gas-white.svg b/images/VM-gas-white.svg new file mode 100644 index 0000000..1775798 --- /dev/null +++ b/images/VM-gas-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-gas.svg b/images/VM-gas.svg new file mode 100644 index 0000000..81fc090 --- /dev/null +++ b/images/VM-gas.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-hazardous-atmosphere.svg b/images/VM-hazardous-atmosphere.svg new file mode 100644 index 0000000..c5b226e --- /dev/null +++ b/images/VM-hazardous-atmosphere.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + diff --git a/images/VM-healthandsafety.svg b/images/VM-healthandsafety.svg new file mode 100644 index 0000000..fc357bd --- /dev/null +++ b/images/VM-healthandsafety.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + diff --git a/images/VM-heart-line-purple.svg b/images/VM-heart-line-purple.svg new file mode 100644 index 0000000..2c7b4a9 --- /dev/null +++ b/images/VM-heart-line-purple.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/VM-heart-line.svg b/images/VM-heart-line.svg new file mode 100644 index 0000000..325f085 --- /dev/null +++ b/images/VM-heart-line.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/VM-hurt.svg b/images/VM-hurt.svg new file mode 100644 index 0000000..9a58a3d --- /dev/null +++ b/images/VM-hurt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-injury.svg b/images/VM-injury.svg new file mode 100644 index 0000000..8ab36ee --- /dev/null +++ b/images/VM-injury.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-logo-white.png b/images/VM-logo-white.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb5ab6c9a33393d2997717efdc70269997b4edf GIT binary patch literal 20802 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 \ No newline at end of file diff --git a/images/VM-notify-computer-purple.svg b/images/VM-notify-computer-purple.svg new file mode 100644 index 0000000..d311def --- /dev/null +++ b/images/VM-notify-computer-purple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-notify-computer.svg b/images/VM-notify-computer.svg new file mode 100644 index 0000000..3abbdae --- /dev/null +++ b/images/VM-notify-computer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-risks.svg b/images/VM-risks.svg new file mode 100644 index 0000000..be022f0 --- /dev/null +++ b/images/VM-risks.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/images/VM-safety-everyone.svg b/images/VM-safety-everyone.svg new file mode 100644 index 0000000..ab45945 --- /dev/null +++ b/images/VM-safety-everyone.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/images/VM-shouting.svg b/images/VM-shouting.svg new file mode 100644 index 0000000..3f01a50 --- /dev/null +++ b/images/VM-shouting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-small-squiggle-purple.svg b/images/VM-small-squiggle-purple.svg new file mode 100644 index 0000000..dc578b5 --- /dev/null +++ b/images/VM-small-squiggle-purple.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/images/VM-small-squiggle.svg b/images/VM-small-squiggle.svg new file mode 100644 index 0000000..7b15129 --- /dev/null +++ b/images/VM-small-squiggle.svg @@ -0,0 +1,42 @@ + + + + + + diff --git a/images/VM-squiggle-line.svg b/images/VM-squiggle-line.svg new file mode 100644 index 0000000..ebc9909 --- /dev/null +++ b/images/VM-squiggle-line.svg @@ -0,0 +1,61 @@ + + + + + + diff --git a/images/VM-traffic accident.svg b/images/VM-traffic accident.svg new file mode 100644 index 0000000..78c149a --- /dev/null +++ b/images/VM-traffic accident.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/VM-wrist.svg b/images/VM-wrist.svg new file mode 100644 index 0000000..403ab76 --- /dev/null +++ b/images/VM-wrist.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/checklist-tick-purple.svg b/images/checklist-tick-purple.svg new file mode 100644 index 0000000..1b40961 --- /dev/null +++ b/images/checklist-tick-purple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/example-button-white.svg b/images/example-button-white.svg new file mode 100644 index 0000000..4179fa0 --- /dev/null +++ b/images/example-button-white.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/images/example-button.svg b/images/example-button.svg new file mode 100644 index 0000000..6874956 --- /dev/null +++ b/images/example-button.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/images/html-header-firstaid.svg b/images/html-header-firstaid.svg new file mode 100644 index 0000000..411c2f7 --- /dev/null +++ b/images/html-header-firstaid.svg @@ -0,0 +1,697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Quick Reference Guide + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/html-header-hand-tools.svg b/images/html-header-hand-tools.svg new file mode 100644 index 0000000..9909bdd --- /dev/null +++ b/images/html-header-hand-tools.svg @@ -0,0 +1,764 @@ + + + + + + + + + + + + + + + + + + + +Lo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Quick Reference Guide + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/html-header-lone-working.svg b/images/html-header-lone-working.svg new file mode 100644 index 0000000..cc73c9c --- /dev/null +++ b/images/html-header-lone-working.svg @@ -0,0 +1,704 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Quick Reference Guide + + + + + + + + + + + + + + + + + diff --git a/images/html-header-safely.svg b/images/html-header-safely.svg new file mode 100644 index 0000000..b703795 --- /dev/null +++ b/images/html-header-safely.svg @@ -0,0 +1,769 @@ + + + + + + + + + + + + + + + + + + + +Lo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +What You Need to Know and Do + diff --git a/images/number-1-roundal-white.svg b/images/number-1-roundal-white.svg new file mode 100644 index 0000000..2a1c7a0 --- /dev/null +++ b/images/number-1-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-1-roundal.svg b/images/number-1-roundal.svg new file mode 100644 index 0000000..384a91d --- /dev/null +++ b/images/number-1-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-2-roundal-white.svg b/images/number-2-roundal-white.svg new file mode 100644 index 0000000..f2ccd89 --- /dev/null +++ b/images/number-2-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-2-roundal.svg b/images/number-2-roundal.svg new file mode 100644 index 0000000..f1bd4ea --- /dev/null +++ b/images/number-2-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-3-roundal-white.svg b/images/number-3-roundal-white.svg new file mode 100644 index 0000000..5326a6c --- /dev/null +++ b/images/number-3-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-3-roundal.svg b/images/number-3-roundal.svg new file mode 100644 index 0000000..1f6e2ee --- /dev/null +++ b/images/number-3-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-4-roundal-white.svg b/images/number-4-roundal-white.svg new file mode 100644 index 0000000..24f44ff --- /dev/null +++ b/images/number-4-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-4-roundal.svg b/images/number-4-roundal.svg new file mode 100644 index 0000000..82f2eb5 --- /dev/null +++ b/images/number-4-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-5-roundal-white.svg b/images/number-5-roundal-white.svg new file mode 100644 index 0000000..eff0ee5 --- /dev/null +++ b/images/number-5-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-5-roundal.svg b/images/number-5-roundal.svg new file mode 100644 index 0000000..9008c00 --- /dev/null +++ b/images/number-5-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-6-roundal-white.svg b/images/number-6-roundal-white.svg new file mode 100644 index 0000000..af7b23e --- /dev/null +++ b/images/number-6-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-6-roundal.svg b/images/number-6-roundal.svg new file mode 100644 index 0000000..8aa3eaf --- /dev/null +++ b/images/number-6-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-7-roundal-white.svg b/images/number-7-roundal-white.svg new file mode 100644 index 0000000..0a6fd03 --- /dev/null +++ b/images/number-7-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-7-roundal.svg b/images/number-7-roundal.svg new file mode 100644 index 0000000..5fc4e24 --- /dev/null +++ b/images/number-7-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-8-roundal-white.svg b/images/number-8-roundal-white.svg new file mode 100644 index 0000000..9e96c7d --- /dev/null +++ b/images/number-8-roundal-white.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/number-8-roundal.svg b/images/number-8-roundal.svg new file mode 100644 index 0000000..8898849 --- /dev/null +++ b/images/number-8-roundal.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/teardrop-purple.svg b/images/teardrop-purple.svg new file mode 100644 index 0000000..dc779a5 --- /dev/null +++ b/images/teardrop-purple.svg @@ -0,0 +1,19 @@ + + + + + + diff --git a/images/teardrop-red.svg b/images/teardrop-red.svg new file mode 100644 index 0000000..9f62f88 --- /dev/null +++ b/images/teardrop-red.svg @@ -0,0 +1,19 @@ + + + + + + diff --git a/images/teardrop-white.svg b/images/teardrop-white.svg new file mode 100644 index 0000000..128604b --- /dev/null +++ b/images/teardrop-white.svg @@ -0,0 +1,19 @@ + + + + + + diff --git a/imsmanifest.xml b/imsmanifest.xml new file mode 100644 index 0000000..8b478d8 --- /dev/null +++ b/imsmanifest.xml @@ -0,0 +1,27 @@ + + + + ADL SCORM + 1.2 + + + + $scorm_title + + $scorm_title + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..9ff079a --- /dev/null +++ b/index.html @@ -0,0 +1,339 @@ + + + + + + + + +
+
+
+
+
+
+ +
+


+

Introduction

+

+ +

At Virgin Media, the safety of our people, partners and customers is paramount and everyone deserves a place to work that is safe and comfortable and to get home safe, every day. +In our business, there are plenty of potential risks. Hence our commitment to creating a Zero Harm culture. You are responsible for living the five Zero Harm behaviours every day.


+ +
+ +
+ +

Why is it important we Be Safe?

+ +

+ +

To avoid injuring ourselves, our work colleagues, our customers, or anyone who might be affected by our work

+

+ +

The impact of an injury at work doesn't stop with the pain and discomfort of the physical injury. It can be emotionally and mentally damaging to the injured party, witnesses to the injury and those close to the injured party at home, and at work.

+

This may result in stress for the injured party, their family and those close to them. Serious injuries could result in long term sickness, financial difficulties, and long-term health complications.


+ +

+ +

+ +

Poor safety can harm our business, as well as our people

+ +

Poor safety practices also cost time and money and that is bad for any business. Possible costs to the business in the event of a serious accident:


+

+ +

downtime at the time of the accident (injured party and witnesses)

+

+ +

downtime for those undertaking and participating in the accident investigation

+

+ +

additional labour costs, if injured party is off sick and work needs to be completed on paid overtime, or by employing contractors

+

+ +

cost of possible enforcement activity (downtime and potentially fines)

+

+ +

cost of defending a personal injury claim

+

+ +

cost of paying out on a successful claim plus court costs

+

+ +

increased insurance premiums

+

+ +

brand damage and consequent loss of business


+ + +

Even a minor incident can impact the business.

+

We have a brand we are immensely proud of and want to protect, as well as maintain your and our customers’ confidence in us.


+ +

+ +

It's the law!

+

+ + +

The Health and Safety at Work etc Act 1974 is the primary legislation covering occupational health and safety in Great Britain. It sets out the general principles for managing health and safety at work.

+

This includes the Duty of Care Responsibilities...

+

employers have towards employees and members of the public

+

+ +

employees have to themselves and to each other

+

+ +

Our Partners and self-employed workers have towards themselves and others


+ +

Looking after your, and others’, health and safety isn’t just down to Virgin Media – legally, it’s down to you too!


+ +
+ +
+ +

The five Zero Harm behaviours to help you

+

+ +

+

Safety First - in everything you do

+

Always think safety first in everything you do both in and out of work.


+ +

+

Take care - of yourself and everyone else

+

Always take care of yourself and others


+ +

+

Do the right thing

+

Be vigilant about safety. Follow safe systems of work and always carry out simple risk assessments or Be Safe checks before every job, and if it doesn't feel safe then don’t do it!

+

If ever you are in any doubt speak to your manager or the safety team.


+ +

+

Report that stuff

+

Report all unsafe practices or procedures you identify. Knowing about issues helps us put things right, and continually improve health and safety performance.


+ +

+

Speak up and own it

+

If you see something or someone you know that is unsafe, you are expected to be confident and challenge the person and do something to make the situation safe.


+ + +
+ + + + + + \ No newline at end of file diff --git a/scorm-scroll.min.js b/scorm-scroll.min.js new file mode 100644 index 0000000..8ac1102 --- /dev/null +++ b/scorm-scroll.min.js @@ -0,0 +1 @@ +var pipwerks={UTILS:{},debug:{isActive:!0},SCORM:{version:null,handleCompletionStatus:!0,handleExitMode:!0,API:{handle:null,isFound:!1},connection:{isActive:!1},data:{completionStatus:null,exitStatus:null},debug:{}}};pipwerks.SCORM.isAvailable=function(){return!0},pipwerks.SCORM.API.find=function(e){for(var t=null,i=0,n="SCORM.API.find",s=pipwerks.UTILS.trace,o=pipwerks.SCORM;!e.API&&!e.API_1484_11&&e.parent&&e.parent!=e&&i<=12;)i++,e=e.parent;if(o.version)switch(o.version){case"2004":e.API_1484_11?t=e.API_1484_11:s(n+": SCORM version 2004 was specified by user, but API_1484_11 cannot be found.");break;case"1.2":e.API?t=e.API:s(n+": SCORM version 1.2 was specified by user, but API cannot be found.")}else e.API_1484_11?(o.version="2004",t=e.API_1484_11):e.API&&(o.version="1.2",t=e.API);return t?(s(n+": API found. Version: "+o.version),s("API: "+t)):s(n+": Error finding API. \nFind attempts: "+i+". \nFind attempt limit: 12"),t},pipwerks.SCORM.API.get=function(){var e=null,t=window,i=pipwerks.SCORM,n=i.API.find,s=pipwerks.UTILS.trace;return(e=!(e=!(e=!(e=n(t))&&t.parent&&t.parent!=t?n(t.parent):e)&&t.top&&t.top.opener?n(t.top.opener):e)&&t.top&&t.top.opener&&t.top.opener.document?n(t.top.opener.document):e)?i.API.isFound=!0:s("API.get failed: Can't find the API!"),e},pipwerks.SCORM.API.getHandle=function(){var e=pipwerks.SCORM.API;return e.handle||e.isFound||(e.handle=e.get()),e.handle},pipwerks.SCORM.connection.initialize=function(){var e=!1,t=pipwerks.SCORM,i=t.data.completionStatus,n=pipwerks.UTILS.trace,s=pipwerks.UTILS.StringToBoolean,o=t.debug,r="SCORM.connection.initialize ";if(n("connection.initialize called."),t.connection.isActive)n(r+"aborted: Connection already active.");else{var a=t.API.getHandle(),c=0;if(a){switch(t.version){case"1.2":e=s(a.LMSInitialize(""));break;case"2004":e=s(a.Initialize(""))}if(e)if(null!==(c=o.getCode())&&0===c){if(t.connection.isActive=!0,t.handleCompletionStatus&&(i=t.status("get"))){switch(i){case"not attempted":case"unknown":t.status("set","incomplete"),t.set("cmi.success_status","unknown");break;default:t.status("set",i),t.set("cmi.success_status",t.get("cmi.success_status"))}t.save()}}else e=!1,n(r+"failed. \nError code: "+c+" \nError info: "+o.getInfo(c));else n(null!==(c=o.getCode())&&0!==c?r+"failed. \nError code: "+c+" \nError info: "+o.getInfo(c):r+"failed: No response from server.")}else n(r+"failed: API is null.")}return e},pipwerks.SCORM.connection.terminate=function(){var e=!1,t=pipwerks.SCORM,i=t.data.exitStatus,n=t.data.completionStatus,s=pipwerks.UTILS.trace,o=pipwerks.UTILS.StringToBoolean,r=t.debug,a="SCORM.connection.terminate ";if(t.connection.isActive){var c,l=t.API.getHandle();if(l){if(t.handleExitMode&&!i)if("completed"!==n&&"passed"!==n)switch(t.version){case"1.2":e=t.set("cmi.core.exit","suspend");break;case"2004":e=t.set("cmi.exit","suspend")}else switch(t.version){case"1.2":e=t.set("cmi.core.exit","suspend");break;case"2004":e=t.set("cmi.exit","suspend")}if(e=t.save()){switch(t.version){case"1.2":e=o(l.LMSFinish(""));break;case"2004":e=o(l.Terminate(""))}e?t.connection.isActive=!1:s(a+"failed. \nError code: "+(c=r.getCode())+" \nError info: "+r.getInfo(c))}}else s(a+"failed: API is null.")}else s(a+"aborted: Connection already terminated.");return e},pipwerks.SCORM.data.get=function(e){var t=null,i=pipwerks.SCORM,n=pipwerks.UTILS.trace,s=i.debug,o="SCORM.data.get('"+e+"') ";if(i.connection.isActive){var r,a=i.API.getHandle();if(a){switch(i.version){case"1.2":t=a.LMSGetValue(e);break;case"2004":t=a.GetValue(e)}if(r=s.getCode(),""!==t||0===r)switch(e){case"cmi.core.lesson_status":case"cmi.completion_status":i.data.completionStatus=t;break;case"cmi.core.exit":case"cmi.exit":i.data.exitStatus=t}else n(o+"failed. \nError code: "+r+"\nError info: "+s.getInfo(r))}else n(o+"failed: API is null.")}else n(o+"failed: API connection is inactive.");return n(o+" value: "+t),String(t)},pipwerks.SCORM.data.set=function(e,t){var i=!1,n=pipwerks.SCORM,s=pipwerks.UTILS.trace,o=pipwerks.UTILS.StringToBoolean,r=n.debug,a="SCORM.data.set('"+e+"') ";if(n.connection.isActive){var c,l=n.API.getHandle();if(l){switch(n.version){case"1.2":i=o(l.LMSSetValue(e,t));break;case"2004":i=o(l.SetValue(e,t))}i?"cmi.core.lesson_status"===e||"cmi.completion_status"===e?n.data.completionStatus=t:"cmi.core.exit"!=e&&"cmi.exit"!=e||(n.data.exitStatus=t):s(a+"failed. \nError code: "+(c=r.getCode())+". \nError info: "+r.getInfo(c))}else s(a+"failed: API is null.")}else s(a+"failed: API connection is inactive.");return s(a+" value: "+t),i},pipwerks.SCORM.data.save=function(){var e=!1,t=pipwerks.SCORM,i=pipwerks.UTILS.trace,n=pipwerks.UTILS.StringToBoolean,s="SCORM.data.save failed";if(t.connection.isActive){var o=t.API.getHandle();if(o)switch(t.version){case"1.2":e=n(o.LMSCommit(""));break;case"2004":e=n(o.Commit(""))}else i(s+": API is null.")}else i(s+": API connection is inactive.");return e},pipwerks.SCORM.status=function(e,t){var i=!1,n=pipwerks.SCORM,s=pipwerks.UTILS.trace,o="SCORM.getStatus failed",r="";if(null!==e){switch(n.version){case"1.2":r="cmi.core.lesson_status";break;case"2004":r="cmi.completion_status"}switch(e){case"get":i=n.data.get(r);break;case"set":null!==t?i=n.data.set(r,t):(i=!1,s(o+": status was not specified."));break;default:i=!1,s(o+": no valid action was specified.")}}else s(o+": action was not specified.");return i},pipwerks.SCORM.debug.getCode=function(){var e=pipwerks.SCORM,t=e.API.getHandle(),i=pipwerks.UTILS.trace,n=0;if(t)switch(e.version){case"1.2":n=parseInt(t.LMSGetLastError(),10);break;case"2004":n=parseInt(t.GetLastError(),10)}else i("SCORM.debug.getCode failed: API is null.");return n},pipwerks.SCORM.debug.getInfo=function(e){var t=pipwerks.SCORM,i=t.API.getHandle(),n=pipwerks.UTILS.trace,s="";if(i)switch(t.version){case"1.2":s=i.LMSGetErrorString(e.toString());break;case"2004":s=i.GetErrorString(e.toString())}else n("SCORM.debug.getInfo failed: API is null.");return String(s)},pipwerks.SCORM.debug.getDiagnosticInfo=function(e){var t=pipwerks.SCORM,i=t.API.getHandle(),n=pipwerks.UTILS.trace,s="";if(i)switch(t.version){case"1.2":s=i.LMSGetDiagnostic(e);break;case"2004":s=i.GetDiagnostic(e)}else n("SCORM.debug.getDiagnosticInfo failed: API is null.");return String(s)},pipwerks.SCORM.init=pipwerks.SCORM.connection.initialize,pipwerks.SCORM.get=pipwerks.SCORM.data.get,pipwerks.SCORM.set=pipwerks.SCORM.data.set,pipwerks.SCORM.save=pipwerks.SCORM.data.save,pipwerks.SCORM.quit=pipwerks.SCORM.connection.terminate,pipwerks.UTILS.StringToBoolean=function(e){switch(typeof e){case"object":case"string":return/(true|1)/i.test(e);case"number":return!!e;case"boolean":return e;case"undefined":return null;default:return!1}},pipwerks.UTILS.trace=function(e){pipwerks.debug.isActive&&window.console&&window.console.log&&window.console.log(e)},SCORM=!0,SCORM_INITED=!1,SCORM_START_TIME=null,SCORM_INTERACTION_TIMESTAMPS=[],SCORM_CORRECT_ANSWERS=[],SCORM_ID_TO_N={},SCORM_QUESTIONS=[],SCORM_SUCCESS_STATUS="unknown",SCORM_SUCCESS_SCORE=SCORM_WEIGHTING=0,SCORM_INTERACTIONS_INITED=SCORM_EVENTS_INITED=!1,SCORM_LOCATION_INITED=!1,SCORM_OK=!1;var _CMI12={location:"cmi.core.lesson_location",status:"cmi.core.lesson_status",session_time:"cmi.core.session_time",success_status:"",exit:"cmi.core.exit"},_CMI2004={location:"cmi.location",status:"cmi.completion_status",session_time:"cmi.session_time",success_status:"cmi.success_status",exit:"cmi.exit"};function initScorm(){if(!SCORM_INITED){console.log("init scorm"),SCORM_INITED=!0;try{pipwerks.SCORM.init()&&(SCORM_OK=!0)}catch(e){}try{FORCE_SCORM&&(SCORM_OK=!0)}catch(e){}return SCORM_OK?$(document).on("fluidbook.ready",function(){scormExit(),startScormTimer(),initScormEvents(),initScormInteractions()}):console.log("SCORM nok"),SCORM_OK}}function _cmi(e){var t=null;switch(pipwerks.SCORM.version){case"1.2":t=_CMI12[e];break;case"2004":t=_CMI2004[e]}return t=null==t||null==t?e:t}function initScormEvents(){SCORM_OK&&!SCORM_EVENTS_INITED&&(SCORM_EVENTS_INITED=!0,$(window).on("unload",function(){scormMarkAsComplete(),finishScorm()}),SCORM_LOCATION_INITED||(SCORM_LOCATION_INITED=!0,setInterval(function(){pipwerks.SCORM.save()},5e3)))}function finishScorm(){SCORM_OK&&(setSessionTime(),pipwerks.SCORM.save(),pipwerks.SCORM.quit())}function scormMarkAsComplete(){SCORM_OK&&(scormExit(),setScormValue("status","completed"),setScormValue("success_status","passed"))}function scormExit(){var e;SCORM_OK&&(e="suspend",setScormValue("exit",e=fluidbook.settings.scorm_force_attempts?"1.2"===pipwerks.SCORM.version?"logout":"normal":e))}function startScormTimer(){SCORM_START_TIME=new Date}function scormComplete(){SCORM_OK&&(scormMarkAsComplete(),finishScorm())}function scormCompleteAndClose(){scormComplete(),scormClose()}function scormClose(){parent.close(),top.close(),window.close()}function getScormValue(e){if(!SCORM_OK)return null;e=_cmi(e);return""==e?null:pipwerks.SCORM.get(e)}function setScormValue(e,t){if(SCORM_OK){e=_cmi(e);return""==e?!1:pipwerks.SCORM.set(e,t)}}function setSessionTime(){var e,t,i;SCORM_OK&&(e=(new Date).getTime()-SCORM_START_TIME,"1.2"==pipwerks.SCORM.version?(e-=1e3*(t=Math.floor(e/1e3/60/60))*60*60,t<1e3&&99= COMPLETE_SCROLL_RATIO) { + scormComplete(); + } + return true; +}); \ No newline at end of file diff --git a/scripts/scorm-wrapper.js b/scripts/scorm-wrapper.js new file mode 100644 index 0000000..b294fd2 --- /dev/null +++ b/scripts/scorm-wrapper.js @@ -0,0 +1,735 @@ +/*global console*/ + +/* =========================================================== + +pipwerks SCORM Wrapper for JavaScript +v1.1.20160322 + +Created by Philip Hutchison, January 2008-2016 +https://github.com/pipwerks/scorm-api-wrapper + +Copyright (c) Philip Hutchison +MIT-style license: http://pipwerks.mit-license.org/ + +This wrapper works with both SCORM 1.2 and SCORM 2004. + +Inspired by APIWrapper.js, created by the ADL and +Concurrent Technologies Corporation, distributed by +the ADL (http://www.adlnet.gov/scorm). + +SCORM.API.find() and SCORM.API.get() functions based +on ADL code, modified by Mike Rustici +(http://www.scorm.com/resources/apifinder/SCORMAPIFinder.htm), +further modified by Philip Hutchison + +=============================================================== */ + +var pipwerks = {}; //pipwerks 'namespace' helps ensure no conflicts with possible other "SCORM" variables +pipwerks.UTILS = {}; //For holding UTILS functions +pipwerks.debug = {isActive: true}; //Enable (true) or disable (false) for debug mode + +pipwerks.SCORM = { //Define the SCORM object + version: null, //Store SCORM version. + handleCompletionStatus: true, //Whether or not the wrapper should automatically handle the initial completion status + handleExitMode: true, //Whether or not the wrapper should automatically handle the exit mode + API: { + handle: null, + isFound: false + }, //Create API child object + connection: {isActive: false}, //Create connection child object + data: { + completionStatus: null, + exitStatus: null + }, //Create data child object + debug: {} //Create debug child object +}; + + +/* -------------------------------------------------------------------------------- + pipwerks.SCORM.isAvailable + A simple function to allow Flash ExternalInterface to confirm + presence of JS wrapper before attempting any LMS communication. + + Parameters: none + Returns: Boolean (true) +----------------------------------------------------------------------------------- */ + +pipwerks.SCORM.isAvailable = function () { + return true; +}; + + +// ------------------------------------------------------------------------- // +// --- SCORM.API functions ------------------------------------------------- // +// ------------------------------------------------------------------------- // + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.API.find(window) + Looks for an object named API in parent and opener windows + + Parameters: window (the browser window object). + Returns: Object if API is found, null if no API found +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.API.find = function (win) { + var API = null, + findAttempts = 0, + findAttemptLimit = 12, + traceMsgPrefix = "SCORM.API.find", + trace = pipwerks.UTILS.trace, + scorm = pipwerks.SCORM; + + while ( + (!win.API && !win.API_1484_11) && + (win.parent) && + (win.parent != win) && + (findAttempts <= findAttemptLimit) + ) { + findAttempts++; + win = win.parent; + } + + //If SCORM version is specified by user, look for specific API + if (scorm.version) { + switch (scorm.version) { + case "2004" : + if (win.API_1484_11) { + API = win.API_1484_11; + } else { + trace(traceMsgPrefix + ": SCORM version 2004 was specified by user, but API_1484_11 cannot be found."); + } + break; + case "1.2" : + if (win.API) { + API = win.API; + } else { + trace(traceMsgPrefix + ": SCORM version 1.2 was specified by user, but API cannot be found."); + } + break; + } + } else { //If SCORM version not specified by user, look for APIs + if (win.API_1484_11) { //SCORM 2004-specific API. + scorm.version = "2004"; //Set version + API = win.API_1484_11; + } else if (win.API) { //SCORM 1.2-specific API + scorm.version = "1.2"; //Set version + API = win.API; + } + } + + if (API) { + trace(traceMsgPrefix + ": API found. Version: " + scorm.version); + trace("API: " + API); + } else { + trace(traceMsgPrefix + ": Error finding API. \nFind attempts: " + findAttempts + ". \nFind attempt limit: " + findAttemptLimit); + } + + return API; +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.API.get() + Looks for an object named API, first in the current window's frame + hierarchy and then, if necessary, in the current window's opener window + hierarchy (if there is an opener window). + + Parameters: None. + Returns: Object if API found, null if no API found +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.API.get = function () { + var API = null, + win = window, + scorm = pipwerks.SCORM, + find = scorm.API.find, + trace = pipwerks.UTILS.trace; + + API = find(win); + + if (!API && win.parent && win.parent != win) { + API = find(win.parent); + } + + if (!API && win.top && win.top.opener) { + API = find(win.top.opener); + } + + //Special handling for Plateau + //Thanks to Joseph Venditti for the patch + if (!API && win.top && win.top.opener && win.top.opener.document) { + API = find(win.top.opener.document); + } + + if (API) { + scorm.API.isFound = true; + } else { + trace("API.get failed: Can't find the API!"); + } + + return API; +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.API.getHandle() + Returns the handle to API object if it was previously set + + Parameters: None. + Returns: Object (the pipwerks.SCORM.API.handle variable). +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.API.getHandle = function () { + var API = pipwerks.SCORM.API; + + if (!API.handle && !API.isFound) { + API.handle = API.get(); + } + return API.handle; +}; + + +// ------------------------------------------------------------------------- // +// --- pipwerks.SCORM.connection functions --------------------------------- // +// ------------------------------------------------------------------------- // + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.connection.initialize() + Tells the LMS to initiate the communication session. + + Parameters: None + Returns: Boolean +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.connection.initialize = function () { + var success = false, + scorm = pipwerks.SCORM, + completionStatus = scorm.data.completionStatus, + trace = pipwerks.UTILS.trace, + makeBoolean = pipwerks.UTILS.StringToBoolean, + debug = scorm.debug, + traceMsgPrefix = "SCORM.connection.initialize "; + + trace("connection.initialize called."); + + if (!scorm.connection.isActive) { + var API = scorm.API.getHandle(), + errorCode = 0; + + if (API) { + switch (scorm.version) { + case "1.2" : + success = makeBoolean(API.LMSInitialize("")); + break; + case "2004": + success = makeBoolean(API.Initialize("")); + break; + } + + if (success) { + //Double-check that connection is active and working before returning 'true' boolean + errorCode = debug.getCode(); + if (errorCode !== null && errorCode === 0) { + scorm.connection.isActive = true; + if (scorm.handleCompletionStatus) { + //Automatically set new launches to incomplete + completionStatus = scorm.status("get"); + if (completionStatus) { + switch (completionStatus) { + //Both SCORM 1.2 and 2004 + case "not attempted": + scorm.status("set", "incomplete"); + scorm.set('cmi.success_status', 'unknown'); + break; + //SCORM 2004 only + case "unknown" : + scorm.status("set", "incomplete"); + scorm.set('cmi.success_status', 'unknown'); + break; + //Additional options, presented here in case you'd like to use them + //case "completed" : break; + //case "incomplete" : break; + //case "passed" : break; //SCORM 1.2 only + //case "failed" : break; //SCORM 1.2 only + //case "browsed" : break; //SCORM 1.2 only + default : + scorm.status('set', completionStatus); + scorm.set('cmi.success_status', scorm.get('cmi.success_status')); + break; + } + //Commit changes + scorm.save(); + } + } + } else { + success = false; + trace(traceMsgPrefix + "failed. \nError code: " + errorCode + " \nError info: " + debug.getInfo(errorCode)); + } + } else { + errorCode = debug.getCode(); + + if (errorCode !== null && errorCode !== 0) { + trace(traceMsgPrefix + "failed. \nError code: " + errorCode + " \nError info: " + debug.getInfo(errorCode)); + } else { + trace(traceMsgPrefix + "failed: No response from server."); + } + } + } else { + trace(traceMsgPrefix + "failed: API is null."); + } + } else { + trace(traceMsgPrefix + "aborted: Connection already active."); + + } + return success; + +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.connection.terminate() + Tells the LMS to terminate the communication session + + Parameters: None + Returns: Boolean +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.connection.terminate = function () { + + var success = false, + scorm = pipwerks.SCORM, + exitStatus = scorm.data.exitStatus, + completionStatus = scorm.data.completionStatus, + trace = pipwerks.UTILS.trace, + makeBoolean = pipwerks.UTILS.StringToBoolean, + debug = scorm.debug, + traceMsgPrefix = "SCORM.connection.terminate "; + + + if (scorm.connection.isActive) { + var API = scorm.API.getHandle(), + errorCode = 0; + + if (API) { + if (scorm.handleExitMode && !exitStatus) { + if (completionStatus !== "completed" && completionStatus !== "passed") { + switch (scorm.version) { + case "1.2" : + success = scorm.set("cmi.core.exit", "suspend"); + break; + case "2004": + success = scorm.set("cmi.exit", "suspend"); + break; + } + } else { + switch (scorm.version) { + case "1.2" : + success = scorm.set("cmi.core.exit", "suspend"); + break; + case "2004": + success = scorm.set("cmi.exit", "suspend"); + break; + } + } + } + + //Ensure we persist the data + success = scorm.save(); + + if (success) { + switch (scorm.version) { + case "1.2" : + success = makeBoolean(API.LMSFinish("")); + break; + case "2004": + success = makeBoolean(API.Terminate("")); + break; + } + + if (success) { + scorm.connection.isActive = false; + } else { + errorCode = debug.getCode(); + trace(traceMsgPrefix + "failed. \nError code: " + errorCode + " \nError info: " + debug.getInfo(errorCode)); + } + } + } else { + trace(traceMsgPrefix + "failed: API is null."); + } + } else { + trace(traceMsgPrefix + "aborted: Connection already terminated."); + } + return success; +}; + + +// ------------------------------------------------------------------------- // +// --- pipwerks.SCORM.data functions --------------------------------------- // +// ------------------------------------------------------------------------- // + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.data.get(parameter) + Requests information from the LMS. + + Parameter: parameter (string, name of the SCORM data model element) + Returns: string (the value of the specified data model element) +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.data.get = function (parameter) { + var value = null, + scorm = pipwerks.SCORM, + trace = pipwerks.UTILS.trace, + debug = scorm.debug, + traceMsgPrefix = "SCORM.data.get('" + parameter + "') "; + + if (scorm.connection.isActive) { + var API = scorm.API.getHandle(), + errorCode = 0; + + if (API) { + switch (scorm.version) { + case "1.2" : + value = API.LMSGetValue(parameter); + break; + case "2004": + value = API.GetValue(parameter); + break; + } + errorCode = debug.getCode(); + + //GetValue returns an empty string on errors + //If value is an empty string, check errorCode to make sure there are no errors + if (value !== "" || errorCode === 0) { + //GetValue is successful. + //If parameter is lesson_status/completion_status or exit status, let's + //grab the value and cache it so we can check it during connection.terminate() + switch (parameter) { + case "cmi.core.lesson_status": + case "cmi.completion_status" : + scorm.data.completionStatus = value; + break; + case "cmi.core.exit": + case "cmi.exit" : + scorm.data.exitStatus = value; + break; + } + } else { + trace(traceMsgPrefix + "failed. \nError code: " + errorCode + "\nError info: " + debug.getInfo(errorCode)); + } + } else { + trace(traceMsgPrefix + "failed: API is null."); + } + } else { + trace(traceMsgPrefix + "failed: API connection is inactive."); + } + trace(traceMsgPrefix + " value: " + value); + return String(value); +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.data.set() + Tells the LMS to assign the value to the named data model element. + Also stores the SCO's completion status in a variable named + pipwerks.SCORM.data.completionStatus. This variable is checked whenever + pipwerks.SCORM.connection.terminate() is invoked. + + Parameters: parameter (string). The data model element + value (string). The value for the data model element + Returns: Boolean +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.data.set = function (parameter, value) { + var success = false, + scorm = pipwerks.SCORM, + trace = pipwerks.UTILS.trace, + makeBoolean = pipwerks.UTILS.StringToBoolean, + debug = scorm.debug, + traceMsgPrefix = "SCORM.data.set('" + parameter + "') "; + + + if (scorm.connection.isActive) { + var API = scorm.API.getHandle(), + errorCode = 0; + + if (API) { + switch (scorm.version) { + case "1.2" : + success = makeBoolean(API.LMSSetValue(parameter, value)); + break; + case "2004": + success = makeBoolean(API.SetValue(parameter, value)); + break; + } + + if (success) { + if (parameter === "cmi.core.lesson_status" || parameter === "cmi.completion_status") { + scorm.data.completionStatus = value; + } else if (parameter == 'cmi.core.exit' || parameter == 'cmi.exit') { + scorm.data.exitStatus = value; + } + } else { + errorCode = debug.getCode(); + trace(traceMsgPrefix + "failed. \nError code: " + errorCode + ". \nError info: " + debug.getInfo(errorCode)); + } + } else { + trace(traceMsgPrefix + "failed: API is null."); + } + } else { + trace(traceMsgPrefix + "failed: API connection is inactive."); + } + trace(traceMsgPrefix + " value: " + value); + return success; +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.data.save() + Instructs the LMS to persist all data to this point in the session + + Parameters: None + Returns: Boolean +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.data.save = function () { + + var success = false, + scorm = pipwerks.SCORM, + trace = pipwerks.UTILS.trace, + makeBoolean = pipwerks.UTILS.StringToBoolean, + traceMsgPrefix = "SCORM.data.save failed"; + + + if (scorm.connection.isActive) { + var API = scorm.API.getHandle(); + if (API) { + switch (scorm.version) { + case "1.2" : + success = makeBoolean(API.LMSCommit("")); + break; + case "2004": + success = makeBoolean(API.Commit("")); + break; + } + } else { + trace(traceMsgPrefix + ": API is null."); + } + } else { + trace(traceMsgPrefix + ": API connection is inactive."); + } + + return success; + +}; + + +pipwerks.SCORM.status = function (action, status) { + var success = false, + scorm = pipwerks.SCORM, + trace = pipwerks.UTILS.trace, + traceMsgPrefix = "SCORM.getStatus failed", + cmi = ""; + + if (action !== null) { + switch (scorm.version) { + case "1.2" : + cmi = "cmi.core.lesson_status"; + break; + case "2004": + cmi = "cmi.completion_status"; + break; + } + + switch (action) { + case "get": + success = scorm.data.get(cmi); + break; + case "set": + if (status !== null) { + success = scorm.data.set(cmi, status); + } else { + success = false; + trace(traceMsgPrefix + ": status was not specified."); + } + break; + default : + success = false; + trace(traceMsgPrefix + ": no valid action was specified."); + } + } else { + trace(traceMsgPrefix + ": action was not specified."); + } + + return success; + +}; + + +// ------------------------------------------------------------------------- // +// --- pipwerks.SCORM.debug functions -------------------------------------- // +// ------------------------------------------------------------------------- // + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.debug.getCode + Requests the error code for the current error state from the LMS + + Parameters: None + Returns: Integer (the last error code). +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.debug.getCode = function () { + + var scorm = pipwerks.SCORM, + API = scorm.API.getHandle(), + trace = pipwerks.UTILS.trace, + code = 0; + + if (API) { + switch (scorm.version) { + case "1.2" : + code = parseInt(API.LMSGetLastError(), 10); + break; + case "2004": + code = parseInt(API.GetLastError(), 10); + break; + } + } else { + trace("SCORM.debug.getCode failed: API is null."); + } + + return code; +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.debug.getInfo() + "Used by a SCO to request the textual description for the error code + specified by the value of [errorCode]." + + Parameters: errorCode (integer). + Returns: String. +----------------------------------------------------------------------------- */ + +pipwerks.SCORM.debug.getInfo = function (errorCode) { + var scorm = pipwerks.SCORM, + API = scorm.API.getHandle(), + trace = pipwerks.UTILS.trace, + result = ""; + + if (API) { + switch (scorm.version) { + case "1.2" : + result = API.LMSGetErrorString(errorCode.toString()); + break; + case "2004": + result = API.GetErrorString(errorCode.toString()); + break; + } + } else { + trace("SCORM.debug.getInfo failed: API is null."); + } + return String(result); +}; + + +/* ------------------------------------------------------------------------- + pipwerks.SCORM.debug.getDiagnosticInfo + "Exists for LMS specific use. It allows the LMS to define additional + diagnostic information through the API Instance." + + Parameters: errorCode (integer). + Returns: String (Additional diagnostic information about the given error code). +---------------------------------------------------------------------------- */ + +pipwerks.SCORM.debug.getDiagnosticInfo = function (errorCode) { + var scorm = pipwerks.SCORM, + API = scorm.API.getHandle(), + trace = pipwerks.UTILS.trace, + result = ""; + + if (API) { + switch (scorm.version) { + case "1.2" : + result = API.LMSGetDiagnostic(errorCode); + break; + case "2004": + result = API.GetDiagnostic(errorCode); + break; + } + } else { + trace("SCORM.debug.getDiagnosticInfo failed: API is null."); + } + + return String(result); +}; + + +// ------------------------------------------------------------------------- // +// --- Shortcuts! ---------------------------------------------------------- // +// ------------------------------------------------------------------------- // + +// Because nobody likes typing verbose code. + +pipwerks.SCORM.init = pipwerks.SCORM.connection.initialize; +pipwerks.SCORM.get = pipwerks.SCORM.data.get; +pipwerks.SCORM.set = pipwerks.SCORM.data.set; +pipwerks.SCORM.save = pipwerks.SCORM.data.save; +pipwerks.SCORM.quit = pipwerks.SCORM.connection.terminate; + + +// ------------------------------------------------------------------------- // +// --- pipwerks.UTILS functions -------------------------------------------- // +// ------------------------------------------------------------------------- // + + +/* ------------------------------------------------------------------------- + pipwerks.UTILS.StringToBoolean() + Converts 'boolean strings' into actual valid booleans. + + (Most values returned from the API are the strings "true" and "false".) + + Parameters: String + Returns: Boolean +---------------------------------------------------------------------------- */ + +pipwerks.UTILS.StringToBoolean = function (value) { + var t = typeof value; + switch (t) { + //typeof new String("true") === "object", so handle objects as string via fall-through. + //See https://github.com/pipwerks/scorm-api-wrapper/issues/3 + case "object": + case "string": + return (/(true|1)/i).test(value); + case "number": + return !!value; + case "boolean": + return value; + case "undefined": + return null; + default: + return false; + } +}; + + +/* ------------------------------------------------------------------------- + pipwerks.UTILS.trace() + Displays error messages when in debug mode. + + Parameters: msg (string) + Return: None +---------------------------------------------------------------------------- */ + +pipwerks.UTILS.trace = function (msg) { + if (pipwerks.debug.isActive) { + if (window.console && window.console.log) { + window.console.log(msg); + } else { + //alert(msg); + } + } +}; diff --git a/scripts/scorm.js b/scripts/scorm.js new file mode 100644 index 0000000..bb53ae2 --- /dev/null +++ b/scripts/scorm.js @@ -0,0 +1,463 @@ +SCORM = true; +SCORM_INITED = false; +SCORM_START_TIME = null; +SCORM_INTERACTION_TIMESTAMPS = []; +SCORM_CORRECT_ANSWERS = []; +SCORM_ID_TO_N = {}; +SCORM_WEIGHTING = 0; +SCORM_QUESTIONS = []; +SCORM_SUCCESS_STATUS = 'unknown'; +SCORM_SUCCESS_SCORE = 0; +SCORM_EVENTS_INITED = false; +SCORM_INTERACTIONS_INITED = false; +SCORM_LOCATION_INITED = false; +SCORM_OK = false; + +var _CMI12 = { + 'location': 'cmi.core.lesson_location', + 'status': "cmi.core.lesson_status", + 'session_time': 'cmi.core.session_time', + 'success_status': '', + 'exit': 'cmi.core.exit', +}; + +var _CMI2004 = { + 'location': 'cmi.location', + 'status': 'cmi.completion_status', + 'session_time': 'cmi.session_time', + 'success_status': 'cmi.success_status', + 'exit': 'cmi.exit', +} + +function initScorm() { + if (SCORM_INITED) { + return; + } + console.log('init scorm'); + SCORM_INITED = true; + try { + if (pipwerks.SCORM.init()) { + SCORM_OK = true; + } + } catch (e) { + + } + + try { + if (FORCE_SCORM) { + SCORM_OK = true; + } + } catch (e) { + + } + + if (SCORM_OK) { + $(document).on('fluidbook.ready', function () { + scormExit(); + startScormTimer(); + initScormEvents(); + initScormInteractions(); + }); + } else { + console.log('SCORM nok'); + } + return SCORM_OK; +} + +function _cmi(key) { + var res = null; + switch (pipwerks.SCORM.version) { + case "1.2" : + res = _CMI12[key]; + break; + case '2004': + res = _CMI2004[key]; + break; + } + if (res == undefined || res == null) { + res = key; + } + return res; +} + +function initScormEvents() { + if (!SCORM_OK || SCORM_EVENTS_INITED) { + return; + } + SCORM_EVENTS_INITED = true; + + $(window).on('unload', function () { + if (COMPLETE_ON_CLOSE) { + scormMarkAsComplete(); + } + finishScorm(); + }); + + if (SCORM_LOCATION_INITED) { + return; + } + SCORM_LOCATION_INITED = true; + // var currentLocation = getScormValue('location'); + // console.log(currentLocation, 'null'); + // if (currentLocation !== 'null') { + // try { + // var changePage = false; + // if (currentLocation.indexOf('page_') === 0) { + // var e = currentPage.split('_'); + // if (e.length === 2 && e[0] === 'page') { + // fluidbook.setCurrentPage(e[1]); + // changePage = true; + // } + // } else if (currentLocation.indexOf('{') === 0) { + // var location = JSON.parse(currentLocation); + // if (location.maxPage && fluidbook.settings.hasContentLock) { + // fluidbook.contentlock.setMaxPage(location.maxPage, true); + // } + // if (location.page) { + // fluidbook.setCurrentPage(location.page); + // changePage = true; + // } + // } + // + // } catch (err) { + // console.log(err); + // } + // } + + + // $(fluidbook).on('fluidbook.page.navigation', function (e, page) { + // fluidbook.networkControl.executeWhenNetwork(function (cb) { + // scormSaveCurrentPosition(page); + // if (cb !== undefined) { + // setTimeout(cb, 100); + // } + // }, true); + // }); + // + // $(fluidbook).on('fluidbook.maxpage.set', function (e, page) { + // scormSaveCurrentPosition(undefined, page); + // }); + + + // Commit data every 5 seconds + setInterval(function () { + pipwerks.SCORM.save(); + }, 5000); +} + +// function scormSaveCurrentPosition(page, maxPage) { +// if (!SCORM_OK) { +// return; +// } +// if (page === undefined) { +// page = fluidbook.currentPage; +// } +// if (maxPage === undefined) { +// maxPage = fluidbook.contentlock.getMaxPage(); +// } +// setScormValue('location', JSON.stringify({page: page, maxPage: maxPage})); +// } + +function finishScorm() { + if (!SCORM_OK) { + return; + } + setSessionTime(); + pipwerks.SCORM.save(); + pipwerks.SCORM.quit(); +} + +function scormMarkAsComplete() { + if (!SCORM_OK) { + return; + } + scormExit(); + setScormValue('status', "completed"); + //if (!fluidbook.scorm.manageScore && fluidbook.settings.scorm_pass_on_complete) { + setScormValue('success_status', 'passed'); + //} +} + +function scormExit() { + if (!SCORM_OK) { + return; + } + var v = 'suspend'; + if (fluidbook.settings.scorm_force_attempts) { + if (pipwerks.SCORM.version === '1.2') { + v = 'logout'; + } else { + v = 'normal'; + } + } + + setScormValue('exit', v); +} + +function startScormTimer() { + SCORM_START_TIME = new Date(); +} + +function scormComplete() { + if (SCORM_OK) { + scormMarkAsComplete(); + finishScorm(); + return; + } +} + +function scormCompleteAndClose() { + scormComplete(); + scormClose(); +} + +function scormClose() { + parent.close(); + top.close(); + window.close(); +} + +function getScormValue(elementName) { + if (!SCORM_OK) { + return null; + } + var cmi = _cmi(elementName); + if (cmi == '') { + return null; + } + var result = pipwerks.SCORM.get(cmi); + return result; +} + +function setScormValue(elementName, value) { + if (!SCORM_OK) { + return; + } + var cmi = _cmi(elementName); + if (cmi == '') { + return false; + } + var result = pipwerks.SCORM.set(cmi, value); + return result; +} + +// function initScormInteractions() { +// if (!SCORM_OK) { +// return; +// } +// if (SCORM_INTERACTIONS_INITED) { +// return; +// } +// SCORM_INTERACTIONS_INITED = true; +// if (fluidbook.settings.scorm_quizdata === '') { +// return; +// } +// var n = 0; +// for (var sheet in fluidbook.settings.scorm_quizdata) { +// var s = fluidbook.settings.scorm_quizdata[sheet]; +// for (var l in s) { +// if (l == 0) { +// continue; +// } +// var line = s[l]; +// if (line[1] === null || line[1] === '') { +// continue; +// } +// defineScormInteraction(n, line[0], line[2], line[1], line[3], parseFloat(line[4])); +// n++; +// } +// } +// if (fluidbook.scorm.manageScore && SCORM_WEIGHTING > 0) { +// pipwerks.SCORM.set('cmi.score.min', '0'); +// pipwerks.SCORM.set('cmi.score.max', SCORM_WEIGHTING); +// SCORM_SUCCESS_SCORE = parseFloat(fluidbook.settings.scorm_score_min) / 100; +// +// updateInteractionsScore(); +// } +// } +// +// function defineScormInteraction(number, id, type, question, correct_response, weighting) { +// if (!SCORM_OK) { +// return; +// } +// if (weighting === undefined) { +// weighting = 1; +// } +// if (question === undefined) { +// question = ''; +// } +// if (type === undefined) { +// type = 'other'; +// } +// if (id === undefined) { +// id = 'Q' + number; +// } +// +// SCORM_QUESTIONS[number] = { +// id: id, +// question: question, +// type: type, +// correct_response: correct_response, +// weighting: weighting, +// timestamp: null, +// result: false +// }; +// SCORM_ID_TO_N[id] = number; +// +// setScormValue('cmi.interactions.' + number + '.id', id); +// setScormValue('cmi.interactions.' + number + '.description', question); +// setScormValue('cmi.interactions.' + number + '.type', type); +// if (fluidbook.scorm.manageScore) { +// setScormValue('cmi.interactions.' + number + '.correct_responses.0.pattern', correct_response); +// setScormValue('cmi.interactions.' + number + '.weighting', weighting); +// } +// +// SCORM_WEIGHTING += weighting; +// } +// +// function getLearnerResponseById(id) { +// if (!SCORM_OK) { +// return; +// } +// return getScormValue('cmi.interactions.' + scormIdToN(id) + '.learner_response'); +// } +// +// function scormIdToN(id) { +// return SCORM_ID_TO_N[id]; +// } +// +// function displayScormInteraction(id) { +// if (!SCORM_OK) { +// return; +// } +// var n = scormIdToN(id); +// var now = new Date(); +// if (SCORM_QUESTIONS[n].timestamp !== null) { +// return; +// } +// SCORM_QUESTIONS[n].timestamp = now; +// setScormValue('cmi.interactions.' + n + '.timestamp', dateToScormTime(now)); +// } +// +// function answerScormInteraction(id, learner_response, result, set_latency) { +// if (!SCORM_OK) { +// return; +// } +// var n = scormIdToN(id); +// var currentTime = Math.round(new Date().getTime() / 1000); +// displayScormInteraction(id); +// var latency = getScormTimeInterval(SCORM_QUESTIONS[n].timestamp, new Date()); +// +// if (fluidbook.scorm.manageScore) { +// if (result === undefined) { +// result = fluidbook.settings.scorm_quiz_as_questionnaire || (learner_response === SCORM_QUESTIONS[n].correct_response); +// } +// setScormValue('cmi.interactions.' + n + '.result', result ? 'correct' : 'incorrect'); +// } +// +// setScormValue('cmi.interactions.' + n + '.learner_response', learner_response); +// setScormValue('cmi.interactions.' + n + '.latency', latency); +// +// updateInteractionsScore(); +// } +// +// function updateInteractionsScore() { +// +// if (!SCORM_OK || !fluidbook.scorm.manageScore) { +// return; +// } +// var score = 0; +// var answered = 0; +// $.each(SCORM_QUESTIONS, function (n, q) { +// var r = getScormValue('cmi.interactions.' + n + '.result'); +// if (r == '') { +// return; +// } +// answered++; +// if (r == 'correct') { +// score += q.weighting; +// } +// }); +// +// var scaled = score / SCORM_WEIGHTING; +// +// setScormValue('cmi.score.raw', score); +// setScormValue('cmi.score.scaled', scaled); +// var status = 'unknown' +// if (answered > 0) { +// if (scaled >= SCORM_SUCCESS_SCORE) { +// status = 'passed'; +// } else { +// status = 'failed'; +// } +// } +// setScormValue('success_status', status); +// } + +function setSessionTime() { + if (!SCORM_OK) { + return; + } + var currentTime = new Date(); + var sessionTime; + + var endTime = currentTime.getTime() + var calculatedTime = endTime - SCORM_START_TIME; + + if (pipwerks.SCORM.version == '1.2') { + var totalHours = Math.floor(calculatedTime / 1000 / 60 / 60); + calculatedTime = calculatedTime - totalHours * 1000 * 60 * 60 + if (totalHours < 1000 && totalHours > 99) { + totalHours = "0" + totalHours; + } else if (totalHours < 100 && totalHours > 9) { + totalHours = "00" + totalHours; + } else if (totalHours < 10) { + totalHours = "000" + totalHours; + } + + var totalMinutes = Math.floor(calculatedTime / 1000 / 60); + calculatedTime = calculatedTime - totalMinutes * 1000 * 60; + if (totalMinutes < 10) { + totalMinutes = "0" + totalMinutes; + } + + var totalSeconds = Math.floor(calculatedTime / 1000); + if (totalSeconds < 10) { + totalSeconds = "0" + totalSeconds; + } + sessionTime = totalHours + ":" + totalMinutes + ":" + totalSeconds; + setScormValue('session_time', sessionTime); + } else { + setScormValue('session_time', scormSecondsToTimeInterval(calculatedTime / 1000)); + } + +} + +function dateToScormTime(date) { + var res = date.toISOString(); + var e = res.split('.'); + e.pop(); + return e.join('.'); +} + +function getScormTimeInterval(start, end) { + var diff = Math.round((end.getTime() - start.getTime()) / 1000); + return scormSecondsToTimeInterval(diff); +} + +function scormSecondsToTimeInterval(diff) { + var diff = Math.round(diff); + var h = Math.floor(diff / 3600); + diff = diff % 3600; + var m = Math.floor(diff / 60); + var s = diff % 60; + return 'PT' + h + 'H' + m + 'M' + s + 'S'; +} + +function getWindowScroll() { + var h = document.documentElement, + b = document.body, + st = 'scrollTop', + sh = 'scrollHeight'; + return (h[st] || b[st]) / ((h[sh] || b[sh]) - h.clientHeight); +} \ No newline at end of file -- 2.39.5