scorm-again 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,50 +1,58 @@
1
1
  {
2
2
  "name": "scorm-again",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "A modern SCORM JavaScript run-time library for AICC, SCORM 1.2, and SCORM 2004",
5
5
  "main": "dist/scorm-again.min.js",
6
+ "browserslist": [
7
+ "> 1%",
8
+ "edge >= 16",
9
+ "safari >= 9",
10
+ "firefox >= 57",
11
+ "ie >= 11",
12
+ "ios >= 9",
13
+ "chrome >= 49"
14
+ ],
6
15
  "directories": {
7
16
  "test": "test"
8
17
  },
9
18
  "devDependencies": {
10
- "@babel/cli": "^7.14.3",
11
- "@babel/core": "^7.14.3",
12
- "@babel/node": "^7.14.2",
13
- "@babel/plugin-proposal-class-properties": "^7.13.0",
14
- "@babel/plugin-proposal-optional-chaining": "^7.14.2",
15
- "@babel/plugin-proposal-private-methods": "^7.13.0",
16
- "@babel/preset-env": "^7.14.2",
17
- "@babel/preset-flow": "^7.13.13",
18
- "@babel/register": "^7.13.16",
19
- "@types/chai": "^4.2.18",
20
- "@types/mocha": "^8.2.2",
19
+ "@babel/cli": "^7.17.10",
20
+ "@babel/core": "^7.18.5",
21
+ "@babel/node": "^7.18.5",
22
+ "@babel/plugin-proposal-class-properties": "^7.17.12",
23
+ "@babel/plugin-proposal-optional-chaining": "^7.17.12",
24
+ "@babel/plugin-proposal-private-methods": "^7.17.12",
25
+ "@babel/preset-env": "^7.18.2",
26
+ "@babel/preset-flow": "^7.17.12",
27
+ "@babel/register": "^7.17.7",
28
+ "@types/chai": "^4.3.1",
29
+ "@types/mocha": "^9.1.1",
21
30
  "babel-eslint": "^11.0.0-beta.2",
31
+ "babel-loader": "^8.2.5",
22
32
  "babelify": "^10.0.0",
23
33
  "browserify": "^17.0.0",
24
- "chai": "^4.3.4",
25
- "eslint": "^7.27.0",
34
+ "chai": "^4.3.6",
35
+ "eslint": "^8.18.0",
26
36
  "eslint-config-google": "^0.14.0",
27
- "eslint-plugin-import": "^2.23.3",
37
+ "eslint-plugin-import": "^2.26.0",
38
+ "eslint-webpack-plugin": "^3.1.1",
28
39
  "fetch-pretender": "^1.5.0",
29
- "grunt": "^1.4.1",
30
- "grunt-browserify": "^6.0.0",
31
- "grunt-cli": "^1.4.3",
32
- "grunt-contrib-watch": "^1.1.0",
33
- "grunt-mocha-test": "^0.13.3",
34
- "jsdoc": "^3.6.7",
40
+ "jsdoc": "^3.6.10",
35
41
  "jsdoc-babel": "^0.5.0",
36
42
  "lodash.debounce": "^4.0.8",
37
43
  "minimist": "^1.2.5",
38
- "mocha": "^8.4.0",
39
- "mocha-junit-reporter": "^2.0.0",
40
- "mochawesome": "^6.2.1",
44
+ "mocha": "^10.0.0",
45
+ "mocha-junit-reporter": "^2.0.2",
46
+ "mochawesome": "^7.1.3",
41
47
  "nyc": "^15.1.0",
42
- "sinon": "^11.1.1",
43
- "uglifyify": "^5.0.2"
48
+ "sinon": "^14.0.0",
49
+ "uglifyjs-webpack-plugin": "^2.2.0",
50
+ "webpack": "^5.73.0",
51
+ "webpack-cli": "^4.10.0"
44
52
  },
45
53
  "scripts": {
46
54
  "test": "./node_modules/.bin/mocha --require @babel/register --bdd --recursive --reporter list",
47
- "compile": "./node_modules/.bin/grunt default",
55
+ "compile": "./node_modules/.bin/webpack --bail --config webpack.js",
48
56
  "fix": "./node_modules/.bin/eslint ./src --fix"
49
57
  },
50
58
  "repository": {
package/src/BaseAPI.js CHANGED
@@ -29,6 +29,8 @@ export default class BaseAPI {
29
29
  selfReportSessionTime: false,
30
30
  alwaysSendTotalTime: false,
31
31
  strict_errors: true,
32
+ xhrHeaders: {},
33
+ xhrWithCredentials: false,
32
34
  responseHandler: function(xhr) {
33
35
  let result;
34
36
  if (typeof xhr !== 'undefined') {
@@ -46,6 +48,29 @@ export default class BaseAPI {
46
48
  }
47
49
  return result;
48
50
  },
51
+ requestHandler: function(commitObject) {
52
+ return commitObject;
53
+ },
54
+ onLogMessage: function(messageLevel, logMessage) {
55
+ switch (messageLevel) {
56
+ case global_constants.LOG_LEVEL_ERROR:
57
+ console.error(logMessage);
58
+ break;
59
+ case global_constants.LOG_LEVEL_WARNING:
60
+ console.warn(logMessage);
61
+ break;
62
+ case global_constants.LOG_LEVEL_INFO:
63
+ console.info(logMessage);
64
+ break;
65
+ case global_constants.LOG_LEVEL_DEBUG:
66
+ if (console.debug) {
67
+ console.debug(logMessage);
68
+ } else {
69
+ console.log(logMessage);
70
+ }
71
+ break;
72
+ }
73
+ },
49
74
  };
50
75
  cmi;
51
76
  startingData: {};
@@ -149,11 +174,11 @@ export default class BaseAPI {
149
174
 
150
175
  const result = this.storeData(true);
151
176
  if (!this.settings.sendBeaconCommit && !this.settings.asyncCommit &&
152
- typeof result.errorCode !== 'undefined' && result.errorCode > 0) {
177
+ typeof result.errorCode !== 'undefined' && result.errorCode > 0) {
153
178
  this.throwSCORMError(result.errorCode);
154
179
  }
155
180
  returnValue = (typeof result !== 'undefined' && result.result) ?
156
- result.result : global_constants.SCORM_FALSE;
181
+ result.result : global_constants.SCORM_FALSE;
157
182
 
158
183
  if (checkTerminated) this.lastErrorCode = 0;
159
184
 
@@ -290,11 +315,11 @@ export default class BaseAPI {
290
315
  this.#error_codes.COMMIT_AFTER_TERM)) {
291
316
  const result = this.storeData(false);
292
317
  if (!this.settings.sendBeaconCommit && !this.settings.asyncCommit &&
293
- result.errorCode && result.errorCode > 0) {
318
+ result.errorCode && result.errorCode > 0) {
294
319
  this.throwSCORMError(result.errorCode);
295
320
  }
296
321
  returnValue = (typeof result !== 'undefined' && result.result) ?
297
- result.result : global_constants.SCORM_FALSE;
322
+ result.result : global_constants.SCORM_FALSE;
298
323
 
299
324
  this.apiLog(callbackName, 'HttpRequest', ' Result: ' + returnValue,
300
325
  global_constants.LOG_LEVEL_DEBUG);
@@ -408,24 +433,7 @@ export default class BaseAPI {
408
433
  logMessage = this.formatMessage(functionName, CMIElement, logMessage);
409
434
 
410
435
  if (messageLevel >= this.apiLogLevel) {
411
- switch (messageLevel) {
412
- case global_constants.LOG_LEVEL_ERROR:
413
- console.error(logMessage);
414
- break;
415
- case global_constants.LOG_LEVEL_WARNING:
416
- console.warn(logMessage);
417
- break;
418
- case global_constants.LOG_LEVEL_INFO:
419
- console.info(logMessage);
420
- break;
421
- case global_constants.LOG_LEVEL_DEBUG:
422
- if (console.debug) {
423
- console.debug(logMessage);
424
- } else {
425
- console.log(logMessage);
426
- }
427
- break;
428
- }
436
+ this.settings.onLogMessage(messageLevel, logMessage);
429
437
  }
430
438
  }
431
439
 
@@ -490,9 +498,9 @@ export default class BaseAPI {
490
498
  */
491
499
  _checkObjectHasProperty(refObject, attribute: String) {
492
500
  return Object.hasOwnProperty.call(refObject, attribute) ||
493
- Object.getOwnPropertyDescriptor(
494
- Object.getPrototypeOf(refObject), attribute) ||
495
- (attribute in refObject);
501
+ Object.getOwnPropertyDescriptor(
502
+ Object.getPrototypeOf(refObject), attribute) ||
503
+ (attribute in refObject);
496
504
  }
497
505
 
498
506
  /**
@@ -556,21 +564,21 @@ export default class BaseAPI {
556
564
 
557
565
  const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`;
558
566
  const invalidErrorCode = scorm2004 ?
559
- this.#error_codes.UNDEFINED_DATA_MODEL :
560
- this.#error_codes.GENERAL;
567
+ this.#error_codes.UNDEFINED_DATA_MODEL :
568
+ this.#error_codes.GENERAL;
561
569
 
562
570
  for (let i = 0; i < structure.length; i++) {
563
571
  const attribute = structure[i];
564
572
 
565
573
  if (i === structure.length - 1) {
566
574
  if (scorm2004 && (attribute.substr(0, 8) === '{target=') &&
567
- (typeof refObject._isTargetValid == 'function')) {
575
+ (typeof refObject._isTargetValid == 'function')) {
568
576
  this.throwSCORMError(this.#error_codes.READ_ONLY_ELEMENT);
569
577
  } else if (!this._checkObjectHasProperty(refObject, attribute)) {
570
578
  this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
571
579
  } else {
572
580
  if (this.isInitialized() &&
573
- this.stringMatches(CMIElement, '\\.correct_responses\\.\\d+')) {
581
+ this.stringMatches(CMIElement, '\\.correct_responses\\.\\d+')) {
574
582
  this.validateCorrectResponse(CMIElement, value);
575
583
  }
576
584
 
@@ -671,8 +679,8 @@ export default class BaseAPI {
671
679
  const uninitializedErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) has not been initialized.`;
672
680
  const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`;
673
681
  const invalidErrorCode = scorm2004 ?
674
- this.#error_codes.UNDEFINED_DATA_MODEL :
675
- this.#error_codes.GENERAL;
682
+ this.#error_codes.UNDEFINED_DATA_MODEL :
683
+ this.#error_codes.GENERAL;
676
684
 
677
685
  for (let i = 0; i < structure.length; i++) {
678
686
  attribute = structure[i];
@@ -686,9 +694,8 @@ export default class BaseAPI {
686
694
  }
687
695
  } else {
688
696
  if ((String(attribute).substr(0, 8) === '{target=') &&
689
- (typeof refObject._isTargetValid == 'function')) {
690
- const target = String(attribute).
691
- substr(8, String(attribute).length - 9);
697
+ (typeof refObject._isTargetValid == 'function')) {
698
+ const target = String(attribute).substr(8, String(attribute).length - 9);
692
699
  return refObject._isTargetValid(target);
693
700
  } else if (!this._checkObjectHasProperty(refObject, attribute)) {
694
701
  this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
@@ -818,7 +825,7 @@ export default class BaseAPI {
818
825
  const removeIndex = this.listenerArray.findIndex((obj) =>
819
826
  obj.functionName === functionName &&
820
827
  obj.CMIElement === CMIElement &&
821
- obj.callback === callback
828
+ obj.callback === callback,
822
829
  );
823
830
  if (removeIndex !== -1) {
824
831
  this.listenerArray.splice(removeIndex, 1);
@@ -867,8 +874,8 @@ export default class BaseAPI {
867
874
  const listenerHasCMIElement = !!listener.CMIElement;
868
875
  let CMIElementsMatch = false;
869
876
  if (CMIElement && listener.CMIElement &&
870
- listener.CMIElement.substring(listener.CMIElement.length - 1) ===
871
- '*') {
877
+ listener.CMIElement.substring(listener.CMIElement.length - 1) ===
878
+ '*') {
872
879
  CMIElementsMatch = CMIElement.indexOf(listener.CMIElement.substring(0,
873
880
  listener.CMIElement.length - 1)) === 0;
874
881
  } else {
@@ -1093,6 +1100,15 @@ export default class BaseAPI {
1093
1100
  if (!settings.sendBeaconCommit) {
1094
1101
  const httpReq = new XMLHttpRequest();
1095
1102
  httpReq.open('POST', url, settings.asyncCommit);
1103
+
1104
+ if (Object.keys(settings.xhrHeaders).length) {
1105
+ Object.keys(settings.xhrHeaders).forEach((header) => {
1106
+ httpReq.setRequestHeader(header, settings.xhrHeaders[header]);
1107
+ });
1108
+ }
1109
+
1110
+ httpReq.withCredentials = settings.xhrWithCredentials;
1111
+
1096
1112
  if (settings.asyncCommit) {
1097
1113
  httpReq.onload = function(e) {
1098
1114
  if (typeof settings.responseHandler === 'function') {
@@ -1103,6 +1119,7 @@ export default class BaseAPI {
1103
1119
  };
1104
1120
  }
1105
1121
  try {
1122
+ params = settings.requestHandler(params);
1106
1123
  if (params instanceof Array) {
1107
1124
  httpReq.setRequestHeader('Content-Type',
1108
1125
  'application/x-www-form-urlencoded');
@@ -1164,7 +1181,7 @@ export default class BaseAPI {
1164
1181
  }
1165
1182
 
1166
1183
  if (result.result === true ||
1167
- result.result === global_constants.SCORM_TRUE) {
1184
+ result.result === global_constants.SCORM_TRUE) {
1168
1185
  api.processListeners('CommitSuccess');
1169
1186
  } else {
1170
1187
  api.processListeners('CommitError');
@@ -11,7 +11,7 @@ const learner = {
11
11
  unique: false,
12
12
  },
13
13
  'choice': {
14
- format: scorm2004_regex.CMIShortIdentifier,
14
+ format: scorm2004_regex.CMILongIdentifier,
15
15
  max: 36,
16
16
  delimiter: '[,]',
17
17
  unique: true,
@@ -85,7 +85,7 @@ const correct = {
85
85
  delimiter: '[,]',
86
86
  unique: true,
87
87
  duplicate: false,
88
- format: scorm2004_regex.CMIShortIdentifier,
88
+ format: scorm2004_regex.CMILongIdentifier,
89
89
  },
90
90
  'fill-in': {
91
91
  max: 10,
@@ -356,6 +356,19 @@ describe('SCORM 2004 API Tests', () => {
356
356
  String(scorm2004API.lmsGetLastError()),
357
357
  ).to.equal(String(0));
358
358
  });
359
+ it('should allow cmi.interactions.0.correct_responses.0.pattern to be set - choice for SCORM 2004 4th Edition',
360
+ () => {
361
+ const scorm2004API = apiInitialized();
362
+ scorm2004API.setCMIValue('cmi.interactions.0.id',
363
+ 'urn:scormdriver:Test_Your_Knowledge.Select_the_ONE_TRUE_answer._0');
364
+ scorm2004API.setCMIValue('cmi.interactions.0.type', 'choice');
365
+ scorm2004API.setCMIValue(
366
+ 'cmi.interactions.0.correct_responses.0.pattern',
367
+ 'urn:scormdriver:This%20is%20a%20choice.');
368
+ expect(
369
+ String(scorm2004API.lmsGetLastError()),
370
+ ).to.equal(String(0));
371
+ });
359
372
  it('should allow cmi.interactions.0.objectives.0.id to be set',
360
373
  () => {
361
374
  const scorm2004API = apiInitialized();
@@ -386,6 +399,27 @@ describe('SCORM 2004 API Tests', () => {
386
399
  scorm2004API.getCMIValue('cmi.interactions.0.learner_response'),
387
400
  ).to.equal('VP_on-call_or_President');
388
401
  });
402
+ it('should allow cmi.interactions.0.learner_response to be set for SCORM 2004 4th Edition',
403
+ () => {
404
+ const scorm2004API = apiInitialized();
405
+ scorm2004API.setCMIValue('cmi.interactions.0.id',
406
+ 'urn:scormdriver:Test_Your_Knowledge.Select_the_ONE_TRUE_answer._0');
407
+ scorm2004API.setCMIValue('cmi.interactions.0.type', 'choice');
408
+ scorm2004API.setCMIValue('cmi.interactions.0.learner_response',
409
+ 'urn:scormdriver:This%20is%20an%20incorrect%20response.');
410
+ expect(
411
+ String(scorm2004API.lmsGetLastError()),
412
+ ).to.equal(String(0));
413
+ expect(
414
+ scorm2004API.getCMIValue('cmi.interactions.0.id'),
415
+ ).to.equal('urn:scormdriver:Test_Your_Knowledge.Select_the_ONE_TRUE_answer._0');
416
+ expect(
417
+ scorm2004API.getCMIValue('cmi.interactions.0.type'),
418
+ ).to.equal('choice');
419
+ expect(
420
+ scorm2004API.getCMIValue('cmi.interactions.0.learner_response'),
421
+ ).to.equal('urn:scormdriver:This%20is%20an%20incorrect%20response.');
422
+ });
389
423
  it('should allow `long-fill-in` cmi.interactions.0.learner_response to be set to 4000 characters',
390
424
  () => {
391
425
  const scorm2004API = apiInitialized();
@@ -405,10 +439,8 @@ describe('SCORM 2004 API Tests', () => {
405
439
  ).to.equal('long-fill-in');
406
440
  expect(
407
441
  scorm2004API.getCMIValue('cmi.interactions.0.learner_response'),
408
- ).
409
- to.
410
- equal(
411
- 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer et sodales purus, in aliquam ex. Nunc suscipit interdum tortor ut hendrerit. Donec auctor erat suscipit justo hendrerit, at lacinia ipsum ullamcorper. Cras sollicitudin vestibulum malesuada. Sed non nibh pharetra, suscipit ipsum sed, maximus tortor. Morbi pharetra accumsan turpis id fringilla. In volutpat metus a dui semper, nec tincidunt nibh aliquam. Praesent viverra neque in elementum commodo. Integer hendrerit placerat ante, ac finibus urna tincidunt at. Phasellus consectetur mauris vitae orci viverra luctus. Proin vestibulum blandit mauris quis pellentesque. Proin volutpat hendrerit nisi. Etiam pellentesque urna nec massa congue ultricies. Mauris at eros viverra, posuere tortor id, elementum nisi. In hac habitasse platea dictumst. Pellentesque semper tristique arcu, in tristique metus. Vestibulum ut lacus dui. Aenean mattis malesuada arcu non ullamcorper. Suspendisse tincidunt euismod tincidunt. In tincidunt at nunc rhoncus vehicula. Quisque nulla massa, vestibulum nec laoreet sit amet, posuere eu massa. Donec accumsan efficitur turpis, quis eleifend odio aliquam a. Phasellus placerat ante id dui consectetur dictum. Morbi aliquam, nibh id elementum suscipit, neque ante scelerisque velit, at feugiat turpis odio ac ligula. Phasellus vel urna nulla. Donec vulputate nulla vel purus pellentesque gravida. Vestibulum rutrum, est vel cursus ultrices, orci arcu scelerisque magna, id facilisis mauris arcu ut turpis. Vestibulum consectetur faucibus ante, eu posuere quam ornare et. Aenean vitae dictum neque. Donec nisl justo, porta a sapien quis, luctus congue diam. Integer id metus dolor. Maecenas euismod vulputate leo in lobortis. Vestibulum dignissim finibus est, sed sollicitudin ipsum hendrerit ac. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Pellentesque diam lorem, mattis vel orci interdum, tempor luctus elit. Ut id porta nisi. In dignissim quam urna, et iaculis lectus eleifend ut. Nam vitae felis ac risus tincidunt elementum. Nunc hendrerit augue a nulla hendrerit rutrum. Integer euismod est at orci eleifend, sed laoreet justo auctor. Sed sem orci, imperdiet at erat non, vehicula convallis libero. Aenean hendrerit cursus leo ut malesuada. Donec eu placerat lorem. Sed mattis tristique lorem, eget placerat erat scelerisque faucibus. Vivamus eleifend in augue id mollis. Nulla vehicula, metus eu auctor accumsan, lectus sapien pretium dui, non scelerisque magna augue a sem. Suspendisse sem enim, mattis ac augue non, placerat accumsan sem. Vivamus hendrerit, sapien sit amet consectetur pulvinar, ante nisl pulvinar purus, a ullamcorper dolor leo id arcu. Aliquam sed metus arcu. Quisque erat libero, tincidunt non dictum vel, bibendum ut ante. Nunc vel imperdiet risus. Sed sit amet porta enim. Mauris metus tortor, mattis vitae convallis vitae, dictum nec dui. Aliquam volutpat nisi consequat, gravida tellus eget, cursus purus. Nunc at venenatis enim. Proin dictum, magna ultrices tempor aliquam, metus lacus consectetur odio, quis pharetra massa est at est. Nullam non nibh massa. Duis scelerisque massa a luctus vehicula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec tortor lacus, consequat eget neque sit amet, imperdiet porttitor felis. Duis ante erat, cursus sed venenatis nec, semper sollicitudin felis. Sed tincidunt et tortor quis vehicula. Morbi porta dapibus quam quis iaculis. Nunc mauris dolor, rutrum non pellentesque consectetur, ornare quis lacus. Maecenas eget feugiat odio. Proin vitae magna ut justo bibendum lacinia consequat at orci. Phasellus tincidunt lorem eu justo mollis sagittis. Maecenas fermentum nunc augue, et bibendum augue varius venenatis. Donec eu purus at tellus ullamcorper imperdiet. Duis id orci laoreet, semper eros et, tincidunt nisl. Suspendisse vehicula sed enim ut dignissim. Nam ornare leo eu nibh malesuada, eget ullamcorper sapien egestas. In at commod');
442
+ ).to.equal(
443
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer et sodales purus, in aliquam ex. Nunc suscipit interdum tortor ut hendrerit. Donec auctor erat suscipit justo hendrerit, at lacinia ipsum ullamcorper. Cras sollicitudin vestibulum malesuada. Sed non nibh pharetra, suscipit ipsum sed, maximus tortor. Morbi pharetra accumsan turpis id fringilla. In volutpat metus a dui semper, nec tincidunt nibh aliquam. Praesent viverra neque in elementum commodo. Integer hendrerit placerat ante, ac finibus urna tincidunt at. Phasellus consectetur mauris vitae orci viverra luctus. Proin vestibulum blandit mauris quis pellentesque. Proin volutpat hendrerit nisi. Etiam pellentesque urna nec massa congue ultricies. Mauris at eros viverra, posuere tortor id, elementum nisi. In hac habitasse platea dictumst. Pellentesque semper tristique arcu, in tristique metus. Vestibulum ut lacus dui. Aenean mattis malesuada arcu non ullamcorper. Suspendisse tincidunt euismod tincidunt. In tincidunt at nunc rhoncus vehicula. Quisque nulla massa, vestibulum nec laoreet sit amet, posuere eu massa. Donec accumsan efficitur turpis, quis eleifend odio aliquam a. Phasellus placerat ante id dui consectetur dictum. Morbi aliquam, nibh id elementum suscipit, neque ante scelerisque velit, at feugiat turpis odio ac ligula. Phasellus vel urna nulla. Donec vulputate nulla vel purus pellentesque gravida. Vestibulum rutrum, est vel cursus ultrices, orci arcu scelerisque magna, id facilisis mauris arcu ut turpis. Vestibulum consectetur faucibus ante, eu posuere quam ornare et. Aenean vitae dictum neque. Donec nisl justo, porta a sapien quis, luctus congue diam. Integer id metus dolor. Maecenas euismod vulputate leo in lobortis. Vestibulum dignissim finibus est, sed sollicitudin ipsum hendrerit ac. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Pellentesque diam lorem, mattis vel orci interdum, tempor luctus elit. Ut id porta nisi. In dignissim quam urna, et iaculis lectus eleifend ut. Nam vitae felis ac risus tincidunt elementum. Nunc hendrerit augue a nulla hendrerit rutrum. Integer euismod est at orci eleifend, sed laoreet justo auctor. Sed sem orci, imperdiet at erat non, vehicula convallis libero. Aenean hendrerit cursus leo ut malesuada. Donec eu placerat lorem. Sed mattis tristique lorem, eget placerat erat scelerisque faucibus. Vivamus eleifend in augue id mollis. Nulla vehicula, metus eu auctor accumsan, lectus sapien pretium dui, non scelerisque magna augue a sem. Suspendisse sem enim, mattis ac augue non, placerat accumsan sem. Vivamus hendrerit, sapien sit amet consectetur pulvinar, ante nisl pulvinar purus, a ullamcorper dolor leo id arcu. Aliquam sed metus arcu. Quisque erat libero, tincidunt non dictum vel, bibendum ut ante. Nunc vel imperdiet risus. Sed sit amet porta enim. Mauris metus tortor, mattis vitae convallis vitae, dictum nec dui. Aliquam volutpat nisi consequat, gravida tellus eget, cursus purus. Nunc at venenatis enim. Proin dictum, magna ultrices tempor aliquam, metus lacus consectetur odio, quis pharetra massa est at est. Nullam non nibh massa. Duis scelerisque massa a luctus vehicula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec tortor lacus, consequat eget neque sit amet, imperdiet porttitor felis. Duis ante erat, cursus sed venenatis nec, semper sollicitudin felis. Sed tincidunt et tortor quis vehicula. Morbi porta dapibus quam quis iaculis. Nunc mauris dolor, rutrum non pellentesque consectetur, ornare quis lacus. Maecenas eget feugiat odio. Proin vitae magna ut justo bibendum lacinia consequat at orci. Phasellus tincidunt lorem eu justo mollis sagittis. Maecenas fermentum nunc augue, et bibendum augue varius venenatis. Donec eu purus at tellus ullamcorper imperdiet. Duis id orci laoreet, semper eros et, tincidunt nisl. Suspendisse vehicula sed enim ut dignissim. Nam ornare leo eu nibh malesuada, eget ullamcorper sapien egestas. In at commod');
412
444
  });
413
445
  });
414
446
 
@@ -558,9 +590,7 @@ describe('SCORM 2004 API Tests', () => {
558
590
  'cmi.interactions.0.objectives.0.correct_responses.0.pattern': 'CPR',
559
591
  }, '');
560
592
  scorm2004API.lmsInitialize();
561
- expect(scorm2004API.lmsGetValue('cmi.interactions.0.id')).
562
- to.
563
- eq('Question14_1');
593
+ expect(scorm2004API.lmsGetValue('cmi.interactions.0.id')).to.eq('Question14_1');
564
594
  });
565
595
  });
566
596
 
package/webpack.js ADDED
@@ -0,0 +1,78 @@
1
+ const path = require('path');
2
+ const webpack = require('webpack');
3
+ const ESLintPlugin = require('eslint-webpack-plugin');
4
+ const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
5
+
6
+ const JSLoader = {
7
+ test: /\.js$/i,
8
+ use: {
9
+ loader: 'babel-loader',
10
+ options: {
11
+ presets: [
12
+ [
13
+ '@babel/preset-env',
14
+ {
15
+ 'corejs': '3',
16
+ 'useBuiltIns': 'entry',
17
+ 'targets': {
18
+ 'browsers': [
19
+ 'edge >= 16',
20
+ 'safari >= 9',
21
+ 'firefox >= 57',
22
+ 'ie >= 11',
23
+ 'ios >= 9',
24
+ 'chrome >= 49',
25
+ ],
26
+ },
27
+ },
28
+ ],
29
+ ['@babel/preset-flow'],
30
+ ],
31
+ plugins: [
32
+ '@babel/plugin-proposal-class-properties',
33
+ '@babel/plugin-proposal-private-methods',
34
+ '@babel/plugin-proposal-optional-chaining',
35
+ ],
36
+ },
37
+ },
38
+ };
39
+
40
+ module.exports = {
41
+ mode: 'development',
42
+ devtool: 'source-map',
43
+ entry: {
44
+ 'aicc': './src/exports/aicc.js',
45
+ 'scorm12': './src/exports/scorm12.js',
46
+ 'scorm2004': './src/exports/scorm2004.js',
47
+ 'scorm-again': './src/exports/scorm-again.js',
48
+ 'aicc.min': './src/exports/aicc.js',
49
+ 'scorm12.min': './src/exports/scorm12.js',
50
+ 'scorm2004.min': './src/exports/scorm2004.js',
51
+ 'scorm-again.min': './src/exports/scorm-again.js',
52
+ },
53
+ target: ['web', 'es5'],
54
+ module: {
55
+ rules: [
56
+ JSLoader,
57
+ ],
58
+ },
59
+ output: {
60
+ path: path.resolve(__dirname, 'dist'),
61
+ environment: {
62
+ arrowFunction: false,
63
+ },
64
+ },
65
+ optimization: {
66
+ minimize: true,
67
+ minimizer: [new UglifyJsPlugin({
68
+ include: /\.min\.js$/,
69
+ })],
70
+ },
71
+ plugins: [
72
+ new ESLintPlugin({
73
+ overrideConfigFile: path.resolve(__dirname, '.eslintrc.js'),
74
+ context: path.resolve(__dirname, '../src'),
75
+ files: '**/*.js',
76
+ }),
77
+ ],
78
+ };
package/gruntfile.js DELETED
@@ -1,90 +0,0 @@
1
- module.exports = function(grunt) {
2
- grunt.initConfig({
3
- mochaTest: {
4
- test: {
5
- options: {
6
- reporter: 'list',
7
- require: '@babel/register',
8
- noFail: false,
9
- recursive: true,
10
- captureFile: false,
11
- },
12
- src: ['test/**/*.spec.js'],
13
- },
14
- },
15
- watch: {
16
- scripts: {
17
- files: ['src/**/*.js'],
18
- tasks: ['default'],
19
- options: {
20
- spawn: false,
21
- },
22
- },
23
- },
24
- browserify: {
25
- development: {
26
- files: [{
27
- expand: true,
28
- cwd: 'src/exports/',
29
- src: ['*.js'],
30
- dest: 'dist/',
31
- ext: '.js',
32
- extDot: 'first',
33
- }],
34
- options: {
35
- browserifyOptions: {debug: true},
36
- transform: [
37
- [
38
- 'babelify', {
39
- 'presets': ['@babel/preset-env', '@babel/preset-flow'],
40
- 'plugins': [
41
- '@babel/plugin-proposal-class-properties',
42
- '@babel/plugin-proposal-private-methods',
43
- '@babel/plugin-proposal-optional-chaining',
44
- ],
45
- },
46
- ],
47
- ],
48
- },
49
- },
50
- production: {
51
- files: [{
52
- expand: true,
53
- cwd: 'src/exports/',
54
- src: ['*.js'],
55
- dest: 'dist/',
56
- ext: '.min.js',
57
- extDot: 'first',
58
- }],
59
- options: {
60
- browserifyOptions: {debug: false},
61
- transform: [
62
- [
63
- 'babelify', {
64
- 'presets': ['@babel/preset-env', '@babel/preset-flow'],
65
- 'plugins': [
66
- '@babel/plugin-proposal-class-properties',
67
- '@babel/plugin-proposal-private-methods',
68
- '@babel/plugin-proposal-optional-chaining',
69
- ],
70
- },
71
- 'uglifyify', {
72
- sourceMap: true,
73
- },
74
- ],
75
- ],
76
- },
77
- },
78
- },
79
-
80
- });
81
-
82
- grunt.loadNpmTasks('grunt-browserify');
83
- grunt.loadNpmTasks('grunt-mocha-test');
84
- grunt.loadNpmTasks('grunt-contrib-watch');
85
-
86
- grunt.registerTask('test', 'mochaTest');
87
-
88
- grunt.registerTask('default',
89
- ['browserify:development', 'browserify:production']);
90
- };