@instructure/quiz-core 17.53.1-rc.1 → 17.53.1-rc.11

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.
Files changed (28) hide show
  1. package/es/common/components/layout/Page/index.js +1 -3
  2. package/es/index.js +1 -0
  3. package/es/messages/LocalStorageAdapter.js +41 -0
  4. package/es/messages/LocalStorageLimits.js +87 -0
  5. package/es/messages/StorageExhaustionError.js +24 -0
  6. package/es/messages/postMessageService.js +37 -10
  7. package/es/messages/subjectHandlers/forwardMessage.js +1 -1
  8. package/es/messages/subjectHandlers/lti.capabilities.js +1 -1
  9. package/es/messages/subjectHandlers/lti.fetchWindowSize.js +16 -0
  10. package/es/messages/subjectHandlers/lti.frameResize.js +1 -1
  11. package/es/messages/subjectHandlers/lti.get_data.js +25 -0
  12. package/es/messages/subjectHandlers/lti.put_data.js +43 -0
  13. package/es/messages/subjectHandlers/requestFullWindowLaunch.js +14 -0
  14. package/lib/common/components/layout/Page/index.js +1 -3
  15. package/lib/messages/LocalStorageAdapter.js +51 -0
  16. package/lib/messages/LocalStorageLimits.js +97 -0
  17. package/lib/messages/StorageExhaustionError.js +35 -0
  18. package/lib/messages/postMessageService.js +39 -10
  19. package/lib/messages/subjectHandlers/forwardMessage.js +1 -1
  20. package/lib/messages/subjectHandlers/lti.capabilities.js +1 -1
  21. package/lib/messages/subjectHandlers/lti.fetchWindowSize.js +24 -0
  22. package/lib/messages/subjectHandlers/lti.frameResize.js +1 -1
  23. package/lib/messages/subjectHandlers/lti.get_data.js +34 -0
  24. package/lib/messages/subjectHandlers/lti.put_data.js +57 -0
  25. package/lib/messages/subjectHandlers/requestFullWindowLaunch.js +26 -0
  26. package/package.json +9 -9
  27. package/es/messages/subjectHandlers/lti.scrollToTop.js +0 -15
  28. package/lib/messages/subjectHandlers/lti.scrollToTop.js +0 -23
@@ -49,7 +49,6 @@ export var Page = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
49
49
  key: "render",
50
50
  value: function render() {
51
51
  var childrenWrapperStyles = classnames(styles.content, _defineProperty({}, styles.scrollable, this.shouldRenderSidebar()));
52
- var scrollableToolContainerId = 'scrollable-tool-container';
53
52
  return /*#__PURE__*/React.createElement("div", {
54
53
  className: styles.wrapper
55
54
  }, this.shouldRenderSidebar() ? this.renderSidebar() : null, /*#__PURE__*/React.createElement("div", {
@@ -57,8 +56,7 @@ export var Page = (_dec = themeable(theme, styles), _dec(_class = (_temp = _clas
57
56
  tabIndex: "-1",
58
57
  ref: this.props.childrenWrapperRef,
59
58
  role: this.props.contentRole,
60
- className: childrenWrapperStyles,
61
- id: scrollableToolContainerId
59
+ className: childrenWrapperStyles
62
60
  }, this.props.children));
63
61
  }
64
62
  }]);
package/es/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint "import/newline-after-import": "warn" */
1
2
  // Components
2
3
  export { DragDroppableSDKApp as SDKApp } from "./common/components/SDKApp/index.js";
3
4
  export { ModerateTable } from "./moderating/components/resources/ModerateTable/index.js";
@@ -0,0 +1,41 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
+ import { localStorageLimits } from "./LocalStorageLimits.js";
3
+
4
+ var LocalStorageAdapter = function LocalStorageAdapter() {
5
+ var _this = this;
6
+
7
+ var lsLimits = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : localStorageLimits;
8
+ var ls = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : window.localStorage;
9
+
10
+ _classCallCheck(this, LocalStorageAdapter);
11
+
12
+ this.putData = function (tool_id, key, value) {
13
+ _this.localStorageLimits.addToLimit(tool_id, key, value);
14
+
15
+ _this.localStorage.setItem(_this.getKey(tool_id, key), value);
16
+ };
17
+
18
+ this.getKey = function (tool_id, key) {
19
+ return "lti|platform_storage|".concat(tool_id, "|").concat(key);
20
+ };
21
+
22
+ this.getData = function (tool_id, key) {
23
+ return _this.localStorage.getItem(_this.getKey(tool_id, key));
24
+ };
25
+
26
+ this.clearData = function (tool_id, key) {
27
+ var value = _this.getData(tool_id, key);
28
+
29
+ if (value) {
30
+ _this.localStorageLimits.removeFromLimit(tool_id, key, value);
31
+
32
+ _this.localStorage.removeItem(_this.getKey(tool_id, key));
33
+ }
34
+ };
35
+
36
+ this.localStorageLimits = lsLimits;
37
+ this.localStorage = ls;
38
+ };
39
+
40
+ export { LocalStorageAdapter as default };
41
+ export var localStorageAdapter = new LocalStorageAdapter();
@@ -0,0 +1,87 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
+ import StorageExhaustionError from "./StorageExhaustionError.js";
3
+
4
+ var LocalStorageLimits = // IMS minimum storage limit is 4096 bytes so 4096 chars is more than enough
5
+ function LocalStorageLimits() {
6
+ var _this = this;
7
+
8
+ _classCallCheck(this, LocalStorageLimits);
9
+
10
+ this.STORAGE_CHAR_LIMIT = 4096;
11
+ this.STORAGE_KEY_LIMIT = 500;
12
+
13
+ this.changeKeyCount = function (tool_id, value) {
14
+ _this.limits.set(tool_id, {
15
+ charCount: _this.limits.get(tool_id).charCount,
16
+ keyCount: _this.limits.get(tool_id).keyCount + value
17
+ });
18
+ };
19
+
20
+ this.changeCharCount = function (tool_id, value) {
21
+ _this.limits.set(tool_id, {
22
+ charCount: _this.limits.get(tool_id).charCount + value,
23
+ keyCount: _this.limits.get(tool_id).keyCount
24
+ });
25
+ };
26
+
27
+ this.createLimit = function (tool_id) {
28
+ if (!_this.limits.get(tool_id)) {
29
+ _this.limits.set(tool_id, {
30
+ keyCount: 0,
31
+ charCount: 0
32
+ });
33
+ }
34
+ };
35
+
36
+ this.getLimit = function (tool_id) {
37
+ _this.createLimit(tool_id);
38
+
39
+ return _this.limits.get(tool_id);
40
+ };
41
+
42
+ this.clearLimit = function (tool_id) {
43
+ _this.limits.delete(tool_id);
44
+ };
45
+
46
+ this.addToLimit = function (tool_id, key, value) {
47
+ _this.createLimit(tool_id);
48
+
49
+ var length = key.length + value.length;
50
+
51
+ if (_this.limits.get(tool_id).keyCount >= _this.STORAGE_KEY_LIMIT) {
52
+ throw new StorageExhaustionError('Reached key limit for tool');
53
+ }
54
+
55
+ if (_this.limits.get(tool_id).charCount + length > _this.STORAGE_CHAR_LIMIT) {
56
+ throw new StorageExhaustionError('Reached byte limit for tool');
57
+ }
58
+
59
+ _this.changeKeyCount(tool_id, 1);
60
+
61
+ _this.changeCharCount(tool_id, length);
62
+ };
63
+
64
+ this.removeFromLimit = function (tool_id, key, value) {
65
+ _this.changeKeyCount(tool_id, -1);
66
+
67
+ _this.changeCharCount(tool_id, -key.length - value.length);
68
+
69
+ if (_this.limits.get(tool_id).keyCount < 0) {
70
+ _this.limits.set(tool_id, {
71
+ keyCount: 0,
72
+ charCount: _this.limits.get(tool_id).charCount
73
+ });
74
+ }
75
+
76
+ if (_this.limits.get(tool_id).charCount < 0) {
77
+ _this.limits.set(tool_id, {
78
+ keyCount: _this.limits.get(tool_id).keyCount,
79
+ charCount: 0
80
+ });
81
+ }
82
+ };
83
+
84
+ this.limits = new Map();
85
+ };
86
+
87
+ export var localStorageLimits = new LocalStorageLimits();
@@ -0,0 +1,24 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2
+ import _inherits from "@babel/runtime/helpers/esm/inherits";
3
+ import _createSuper from "@babel/runtime/helpers/esm/createSuper";
4
+ import _wrapNativeSuper from "@babel/runtime/helpers/esm/wrapNativeSuper";
5
+
6
+ var StorageExhaustionError = /*#__PURE__*/function (_Error) {
7
+ _inherits(StorageExhaustionError, _Error);
8
+
9
+ var _super = _createSuper(StorageExhaustionError);
10
+
11
+ function StorageExhaustionError(message) {
12
+ var _this;
13
+
14
+ _classCallCheck(this, StorageExhaustionError);
15
+
16
+ _this = _super.call(this, message);
17
+ _this.code = 'storage_exhaustion';
18
+ return _this;
19
+ }
20
+
21
+ return StorageExhaustionError;
22
+ }( /*#__PURE__*/_wrapNativeSuper(Error));
23
+
24
+ export { StorageExhaustionError as default };
@@ -3,13 +3,19 @@ import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
3
3
  import handleFrameResize from './subjectHandlers/lti.frameResize';
4
4
  import handleCapabilities from './subjectHandlers/lti.capabilities';
5
5
  import forwardMessage from "./subjectHandlers/forwardMessage.js";
6
- import handleScrollToTop from './subjectHandlers/lti.scrollToTop';
6
+ import handlePutData from './subjectHandlers/lti.put_data';
7
+ import handleGetData from './subjectHandlers/lti.get_data';
8
+ import handleFetchWindowSize from './subjectHandlers/lti.fetchWindowSize';
9
+ import handleRequestFullWindowLaunch from "./subjectHandlers/requestFullWindowLaunch.js";
7
10
 
8
11
  var PostMessageService = function PostMessageService() {
9
12
  var _this = this;
10
13
 
11
14
  _classCallCheck(this, PostMessageService);
12
15
 
16
+ this.BAD_REQUEST_ERROR_CODE = 'bad_request';
17
+ this.GENERIC_ERROR_CODE = 'error';
18
+
13
19
  this.subjectNotAllowed = function (subject) {
14
20
  return !_this.handlerMap.has(subject);
15
21
  };
@@ -42,32 +48,53 @@ var PostMessageService = function PostMessageService() {
42
48
  window.removeEventListener('message', _this.messageHandlerDispatcher);
43
49
  };
44
50
 
45
- this.sendResponse = function (subject, data, sourceWindow) {
51
+ this.sendResponse = function (subject, data, sourceWindow, origin) {
46
52
  sourceWindow.postMessage(_objectSpread({
47
53
  subject: subject + '.response'
48
- }, data));
54
+ }, data), origin);
49
55
  };
50
56
 
51
- this.sendSuccessPostMessageResponse = function (subject, message, sourceWindow) {
57
+ this.sendSuccessPostMessageResponse = function (subject, message, sourceWindow, origin) {
52
58
  _this.sendResponse(subject, {
53
59
  message: message
54
- }, sourceWindow);
60
+ }, sourceWindow, origin);
55
61
  };
56
62
 
57
- this.sendErrorPostMessageResponse = function (subject, error, sourceWindow) {
58
- _this.sendResponse(subject, {
59
- error: error
60
- }, sourceWindow);
63
+ this.sendErrorPostMessageResponse = function (subject, message, code, sourceWindow, origin) {
64
+ _this.sendResponse(subject, _this.buildError(code, message), sourceWindow, origin);
65
+ };
66
+
67
+ this.sendBadRequestErrorPostMessageResponse = function (subject, errorMessage, sourceWindow, origin) {
68
+ _this.sendErrorPostMessageResponse(subject, errorMessage, _this.BAD_REQUEST_ERROR_CODE, sourceWindow, origin);
69
+ };
70
+
71
+ this.sendGenericErrorPostMessageResponse = function (subject, errorMessage, sourceWindow, origin) {
72
+ _this.sendErrorPostMessageResponse(subject, errorMessage, _this.GENERIC_ERROR_CODE, sourceWindow, origin);
73
+ };
74
+
75
+ this.buildError = function (code, message) {
76
+ var error = {
77
+ code: code
78
+ };
79
+
80
+ if (message) {
81
+ error.message = message;
82
+ }
83
+
84
+ return error;
61
85
  };
62
86
 
63
87
  this.handlerMap = new Map();
88
+ this.handlerMap.set('lti.fetchWindowSize', handleFetchWindowSize);
64
89
  this.handlerMap.set('lti.frameResize', handleFrameResize);
65
90
  this.handlerMap.set('lti.capabilities', handleCapabilities);
66
91
  this.handlerMap.set('lti.setUnloadMessage', forwardMessage);
67
92
  this.handlerMap.set('lti.removeUnloadMessage', forwardMessage);
68
93
  this.handlerMap.set('lti.screenReaderAlert', forwardMessage);
69
94
  this.handlerMap.set('lti.showAlert', forwardMessage);
70
- this.handlerMap.set('lti.scrollToTop', handleScrollToTop);
95
+ this.handlerMap.set('lti.put_data', handlePutData);
96
+ this.handlerMap.set('lti.get_data', handleGetData);
97
+ this.handlerMap.set('requestFullWindowLaunch', handleRequestFullWindowLaunch);
71
98
  };
72
99
 
73
100
  export { PostMessageService as default };
@@ -1,6 +1,6 @@
1
1
  var forwardMessage = function forwardMessage(event, _) {
2
2
  if (window !== window.parent) {
3
- window.parent.postMessage(event.data, '*');
3
+ window.parent.postMessage(event === null || event === void 0 ? void 0 : event.data, '*');
4
4
  }
5
5
  };
6
6
 
@@ -4,7 +4,7 @@ var handleCapabilities = function handleCapabilities(event, postMessageService)
4
4
  var supported_messages = postMessageService.capabilities();
5
5
  postMessageService.sendResponse('lti.capabilities', {
6
6
  supported_messages: supported_messages
7
- }, sourceWindow);
7
+ }, sourceWindow, event.origin);
8
8
  return true;
9
9
  } catch (_unused) {
10
10
  return false;
@@ -0,0 +1,16 @@
1
+ var handleFetchWindowSize = function handleFetchWindowSize(event, postMessageService) {
2
+ var height = window.innerHeight;
3
+ var width = window.innerWidth;
4
+ var scrollY = window.scrollY;
5
+ var offset = 0;
6
+ var footer = 0;
7
+ postMessageService.sendSuccessPostMessageResponse('lti.fetchWindowSize', {
8
+ height: height,
9
+ width: width,
10
+ footer: footer,
11
+ scrollY: scrollY,
12
+ offset: offset
13
+ }, event.source, event.origin);
14
+ };
15
+
16
+ export default handleFetchWindowSize;
@@ -6,7 +6,7 @@ var handleFrameResize = function handleFrameResize(event, postMessageService) {
6
6
  if (ltiIframe && event.data.height > 0) {
7
7
  ltiIframe.height = event.data.height + 'px';
8
8
  ltiIframe.style.height = event.data.height + 'px';
9
- postMessageService.sendSuccessPostMessageResponse('lti.frameResize', void 0, event.source);
9
+ postMessageService.sendSuccessPostMessageResponse('lti.frameResize', void 0, event.source, event.origin);
10
10
  }
11
11
  };
12
12
 
@@ -0,0 +1,25 @@
1
+ import { localStorageAdapter } from "../LocalStorageAdapter.js";
2
+
3
+ var handleGetData = function handleGetData(event, postMessageService) {
4
+ var _event$data = event.data,
5
+ key = _event$data.key,
6
+ message_id = _event$data.message_id;
7
+
8
+ if (!key) {
9
+ postMessageService.sendBadRequestErrorPostMessageResponse('Missing required "key" field');
10
+ return true;
11
+ }
12
+
13
+ if (!message_id) {
14
+ postMessageService.sendBadRequestErrorPostMessageResponse('Missing required "message_id" field"');
15
+ return true;
16
+ }
17
+
18
+ var value = localStorageAdapter.getData(event.origin, key);
19
+ postMessageService.sendSuccessPostMessageResponse('lti.get_data', {
20
+ key: key,
21
+ value: value
22
+ }, event.source, event.origin);
23
+ };
24
+
25
+ export default handleGetData;
@@ -0,0 +1,43 @@
1
+ import StorageExhaustionError from "../StorageExhaustionError.js";
2
+ import { localStorageAdapter } from "../LocalStorageAdapter.js";
3
+ var SUBJECT = 'lti.put_data';
4
+
5
+ var handlePutData = function handlePutData(event, postMessageService) {
6
+ var _event$data = event.data,
7
+ key = _event$data.key,
8
+ value = _event$data.value,
9
+ message_id = _event$data.message_id;
10
+
11
+ if (!key) {
12
+ postMessageService.sendBadRequestErrorPostMessageResponse(SUBJECT, "Missing required 'key' field", event.source, event.origin);
13
+ return true;
14
+ }
15
+
16
+ if (!message_id) {
17
+ postMessageService.sendBadRequestErrorPostMessageResponse(SUBJECT, 'Missing required "message_id" field', event.source, event.origin);
18
+ return true;
19
+ }
20
+
21
+ if (value) {
22
+ try {
23
+ localStorageAdapter.putData(event.origin, key, value);
24
+ postMessageService.sendSuccessPostMessageResponse(SUBJECT, {
25
+ key: key,
26
+ value: value
27
+ }, event.source, event.origin);
28
+ } catch (e) {
29
+ if (e instanceof StorageExhaustionError) {
30
+ var code = e.code;
31
+ var message = e.message;
32
+ postMessageService.sendErrorPostMessageResponse(SUBJECT, message, code, event.source, event.origin);
33
+ }
34
+ }
35
+ } else {
36
+ localStorageAdapter.clearData(event.origin, key);
37
+ postMessageService.sendResponse(SUBJECT, {
38
+ key: key
39
+ }, event.source, event.origin);
40
+ }
41
+ };
42
+
43
+ export default handlePutData;
@@ -0,0 +1,14 @@
1
+ import forwardMessage from "./forwardMessage.js";
2
+ export var SAME_WINDOW_LAUNCH_TYPE = 'same_window';
3
+
4
+ var handleRequestFullWindowLaunch = function handleRequestFullWindowLaunch(event) {
5
+ var _event$data, _event$data$data;
6
+
7
+ if ((event === null || event === void 0 ? void 0 : (_event$data = event.data) === null || _event$data === void 0 ? void 0 : (_event$data$data = _event$data.data) === null || _event$data$data === void 0 ? void 0 : _event$data$data.launchType) === SAME_WINDOW_LAUNCH_TYPE) {
8
+ return;
9
+ }
10
+
11
+ forwardMessage(event);
12
+ };
13
+
14
+ export default handleRequestFullWindowLaunch;
@@ -68,7 +68,6 @@ var Page = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
68
68
  key: "render",
69
69
  value: function render() {
70
70
  var childrenWrapperStyles = (0, _classnames2.default)(styles.content, (0, _defineProperty2.default)({}, styles.scrollable, this.shouldRenderSidebar()));
71
- var scrollableToolContainerId = 'scrollable-tool-container';
72
71
  return /*#__PURE__*/_react.default.createElement("div", {
73
72
  className: styles.wrapper
74
73
  }, this.shouldRenderSidebar() ? this.renderSidebar() : null, /*#__PURE__*/_react.default.createElement("div", {
@@ -76,8 +75,7 @@ var Page = (_dec = (0, _uiThemeable.themeable)(_theme.default, styles), _dec(_cl
76
75
  tabIndex: "-1",
77
76
  ref: this.props.childrenWrapperRef,
78
77
  role: this.props.contentRole,
79
- className: childrenWrapperStyles,
80
- id: scrollableToolContainerId
78
+ className: childrenWrapperStyles
81
79
  }, this.props.children));
82
80
  }
83
81
  }]);
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.localStorageAdapter = exports.default = void 0;
9
+
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+
12
+ var _LocalStorageLimits = require("./LocalStorageLimits.js");
13
+
14
+ var LocalStorageAdapter = function LocalStorageAdapter() {
15
+ var _this = this;
16
+
17
+ var lsLimits = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : _LocalStorageLimits.localStorageLimits;
18
+ var ls = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : window.localStorage;
19
+ (0, _classCallCheck2.default)(this, LocalStorageAdapter);
20
+
21
+ this.putData = function (tool_id, key, value) {
22
+ _this.localStorageLimits.addToLimit(tool_id, key, value);
23
+
24
+ _this.localStorage.setItem(_this.getKey(tool_id, key), value);
25
+ };
26
+
27
+ this.getKey = function (tool_id, key) {
28
+ return "lti|platform_storage|".concat(tool_id, "|").concat(key);
29
+ };
30
+
31
+ this.getData = function (tool_id, key) {
32
+ return _this.localStorage.getItem(_this.getKey(tool_id, key));
33
+ };
34
+
35
+ this.clearData = function (tool_id, key) {
36
+ var value = _this.getData(tool_id, key);
37
+
38
+ if (value) {
39
+ _this.localStorageLimits.removeFromLimit(tool_id, key, value);
40
+
41
+ _this.localStorage.removeItem(_this.getKey(tool_id, key));
42
+ }
43
+ };
44
+
45
+ this.localStorageLimits = lsLimits;
46
+ this.localStorage = ls;
47
+ };
48
+
49
+ exports.default = LocalStorageAdapter;
50
+ var localStorageAdapter = new LocalStorageAdapter();
51
+ exports.localStorageAdapter = localStorageAdapter;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.localStorageLimits = void 0;
9
+
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+
12
+ var _StorageExhaustionError = _interopRequireDefault(require("./StorageExhaustionError.js"));
13
+
14
+ var LocalStorageLimits = // IMS minimum storage limit is 4096 bytes so 4096 chars is more than enough
15
+ function LocalStorageLimits() {
16
+ var _this = this;
17
+
18
+ (0, _classCallCheck2.default)(this, LocalStorageLimits);
19
+ this.STORAGE_CHAR_LIMIT = 4096;
20
+ this.STORAGE_KEY_LIMIT = 500;
21
+
22
+ this.changeKeyCount = function (tool_id, value) {
23
+ _this.limits.set(tool_id, {
24
+ charCount: _this.limits.get(tool_id).charCount,
25
+ keyCount: _this.limits.get(tool_id).keyCount + value
26
+ });
27
+ };
28
+
29
+ this.changeCharCount = function (tool_id, value) {
30
+ _this.limits.set(tool_id, {
31
+ charCount: _this.limits.get(tool_id).charCount + value,
32
+ keyCount: _this.limits.get(tool_id).keyCount
33
+ });
34
+ };
35
+
36
+ this.createLimit = function (tool_id) {
37
+ if (!_this.limits.get(tool_id)) {
38
+ _this.limits.set(tool_id, {
39
+ keyCount: 0,
40
+ charCount: 0
41
+ });
42
+ }
43
+ };
44
+
45
+ this.getLimit = function (tool_id) {
46
+ _this.createLimit(tool_id);
47
+
48
+ return _this.limits.get(tool_id);
49
+ };
50
+
51
+ this.clearLimit = function (tool_id) {
52
+ _this.limits.delete(tool_id);
53
+ };
54
+
55
+ this.addToLimit = function (tool_id, key, value) {
56
+ _this.createLimit(tool_id);
57
+
58
+ var length = key.length + value.length;
59
+
60
+ if (_this.limits.get(tool_id).keyCount >= _this.STORAGE_KEY_LIMIT) {
61
+ throw new _StorageExhaustionError.default('Reached key limit for tool');
62
+ }
63
+
64
+ if (_this.limits.get(tool_id).charCount + length > _this.STORAGE_CHAR_LIMIT) {
65
+ throw new _StorageExhaustionError.default('Reached byte limit for tool');
66
+ }
67
+
68
+ _this.changeKeyCount(tool_id, 1);
69
+
70
+ _this.changeCharCount(tool_id, length);
71
+ };
72
+
73
+ this.removeFromLimit = function (tool_id, key, value) {
74
+ _this.changeKeyCount(tool_id, -1);
75
+
76
+ _this.changeCharCount(tool_id, -key.length - value.length);
77
+
78
+ if (_this.limits.get(tool_id).keyCount < 0) {
79
+ _this.limits.set(tool_id, {
80
+ keyCount: 0,
81
+ charCount: _this.limits.get(tool_id).charCount
82
+ });
83
+ }
84
+
85
+ if (_this.limits.get(tool_id).charCount < 0) {
86
+ _this.limits.set(tool_id, {
87
+ keyCount: _this.limits.get(tool_id).keyCount,
88
+ charCount: 0
89
+ });
90
+ }
91
+ };
92
+
93
+ this.limits = new Map();
94
+ };
95
+
96
+ var localStorageLimits = new LocalStorageLimits();
97
+ exports.localStorageLimits = localStorageLimits;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+
12
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
13
+
14
+ var _createSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/createSuper"));
15
+
16
+ var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/wrapNativeSuper"));
17
+
18
+ var StorageExhaustionError = /*#__PURE__*/function (_Error) {
19
+ (0, _inherits2.default)(StorageExhaustionError, _Error);
20
+
21
+ var _super = (0, _createSuper2.default)(StorageExhaustionError);
22
+
23
+ function StorageExhaustionError(message) {
24
+ var _this;
25
+
26
+ (0, _classCallCheck2.default)(this, StorageExhaustionError);
27
+ _this = _super.call(this, message);
28
+ _this.code = 'storage_exhaustion';
29
+ return _this;
30
+ }
31
+
32
+ return StorageExhaustionError;
33
+ }( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
34
+
35
+ exports.default = StorageExhaustionError;
@@ -17,12 +17,20 @@ var _lti2 = _interopRequireDefault(require("./subjectHandlers/lti.capabilities")
17
17
 
18
18
  var _forwardMessage = _interopRequireDefault(require("./subjectHandlers/forwardMessage.js"));
19
19
 
20
- var _lti3 = _interopRequireDefault(require("./subjectHandlers/lti.scrollToTop"));
20
+ var _lti3 = _interopRequireDefault(require("./subjectHandlers/lti.put_data"));
21
+
22
+ var _lti4 = _interopRequireDefault(require("./subjectHandlers/lti.get_data"));
23
+
24
+ var _lti5 = _interopRequireDefault(require("./subjectHandlers/lti.fetchWindowSize"));
25
+
26
+ var _requestFullWindowLaunch = _interopRequireDefault(require("./subjectHandlers/requestFullWindowLaunch.js"));
21
27
 
22
28
  var PostMessageService = function PostMessageService() {
23
29
  var _this = this;
24
30
 
25
31
  (0, _classCallCheck2.default)(this, PostMessageService);
32
+ this.BAD_REQUEST_ERROR_CODE = 'bad_request';
33
+ this.GENERIC_ERROR_CODE = 'error';
26
34
 
27
35
  this.subjectNotAllowed = function (subject) {
28
36
  return !_this.handlerMap.has(subject);
@@ -56,32 +64,53 @@ var PostMessageService = function PostMessageService() {
56
64
  window.removeEventListener('message', _this.messageHandlerDispatcher);
57
65
  };
58
66
 
59
- this.sendResponse = function (subject, data, sourceWindow) {
67
+ this.sendResponse = function (subject, data, sourceWindow, origin) {
60
68
  sourceWindow.postMessage((0, _objectSpread2.default)({
61
69
  subject: subject + '.response'
62
- }, data));
70
+ }, data), origin);
63
71
  };
64
72
 
65
- this.sendSuccessPostMessageResponse = function (subject, message, sourceWindow) {
73
+ this.sendSuccessPostMessageResponse = function (subject, message, sourceWindow, origin) {
66
74
  _this.sendResponse(subject, {
67
75
  message: message
68
- }, sourceWindow);
76
+ }, sourceWindow, origin);
69
77
  };
70
78
 
71
- this.sendErrorPostMessageResponse = function (subject, error, sourceWindow) {
72
- _this.sendResponse(subject, {
73
- error: error
74
- }, sourceWindow);
79
+ this.sendErrorPostMessageResponse = function (subject, message, code, sourceWindow, origin) {
80
+ _this.sendResponse(subject, _this.buildError(code, message), sourceWindow, origin);
81
+ };
82
+
83
+ this.sendBadRequestErrorPostMessageResponse = function (subject, errorMessage, sourceWindow, origin) {
84
+ _this.sendErrorPostMessageResponse(subject, errorMessage, _this.BAD_REQUEST_ERROR_CODE, sourceWindow, origin);
85
+ };
86
+
87
+ this.sendGenericErrorPostMessageResponse = function (subject, errorMessage, sourceWindow, origin) {
88
+ _this.sendErrorPostMessageResponse(subject, errorMessage, _this.GENERIC_ERROR_CODE, sourceWindow, origin);
89
+ };
90
+
91
+ this.buildError = function (code, message) {
92
+ var error = {
93
+ code: code
94
+ };
95
+
96
+ if (message) {
97
+ error.message = message;
98
+ }
99
+
100
+ return error;
75
101
  };
76
102
 
77
103
  this.handlerMap = new Map();
104
+ this.handlerMap.set('lti.fetchWindowSize', _lti5.default);
78
105
  this.handlerMap.set('lti.frameResize', _lti.default);
79
106
  this.handlerMap.set('lti.capabilities', _lti2.default);
80
107
  this.handlerMap.set('lti.setUnloadMessage', _forwardMessage.default);
81
108
  this.handlerMap.set('lti.removeUnloadMessage', _forwardMessage.default);
82
109
  this.handlerMap.set('lti.screenReaderAlert', _forwardMessage.default);
83
110
  this.handlerMap.set('lti.showAlert', _forwardMessage.default);
84
- this.handlerMap.set('lti.scrollToTop', _lti3.default);
111
+ this.handlerMap.set('lti.put_data', _lti3.default);
112
+ this.handlerMap.set('lti.get_data', _lti4.default);
113
+ this.handlerMap.set('requestFullWindowLaunch', _requestFullWindowLaunch.default);
85
114
  };
86
115
 
87
116
  exports.default = PostMessageService;
@@ -7,7 +7,7 @@ exports.default = void 0;
7
7
 
8
8
  var forwardMessage = function forwardMessage(event, _) {
9
9
  if (window !== window.parent) {
10
- window.parent.postMessage(event.data, '*');
10
+ window.parent.postMessage(event === null || event === void 0 ? void 0 : event.data, '*');
11
11
  }
12
12
  };
13
13
 
@@ -11,7 +11,7 @@ var handleCapabilities = function handleCapabilities(event, postMessageService)
11
11
  var supported_messages = postMessageService.capabilities();
12
12
  postMessageService.sendResponse('lti.capabilities', {
13
13
  supported_messages: supported_messages
14
- }, sourceWindow);
14
+ }, sourceWindow, event.origin);
15
15
  return true;
16
16
  } catch (_unused) {
17
17
  return false;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var handleFetchWindowSize = function handleFetchWindowSize(event, postMessageService) {
9
+ var height = window.innerHeight;
10
+ var width = window.innerWidth;
11
+ var scrollY = window.scrollY;
12
+ var offset = 0;
13
+ var footer = 0;
14
+ postMessageService.sendSuccessPostMessageResponse('lti.fetchWindowSize', {
15
+ height: height,
16
+ width: width,
17
+ footer: footer,
18
+ scrollY: scrollY,
19
+ offset: offset
20
+ }, event.source, event.origin);
21
+ };
22
+
23
+ var _default = handleFetchWindowSize;
24
+ exports.default = _default;
@@ -13,7 +13,7 @@ var handleFrameResize = function handleFrameResize(event, postMessageService) {
13
13
  if (ltiIframe && event.data.height > 0) {
14
14
  ltiIframe.height = event.data.height + 'px';
15
15
  ltiIframe.style.height = event.data.height + 'px';
16
- postMessageService.sendSuccessPostMessageResponse('lti.frameResize', void 0, event.source);
16
+ postMessageService.sendSuccessPostMessageResponse('lti.frameResize', void 0, event.source, event.origin);
17
17
  }
18
18
  };
19
19
 
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _LocalStorageAdapter = require("../LocalStorageAdapter.js");
9
+
10
+ var handleGetData = function handleGetData(event, postMessageService) {
11
+ var _event$data = event.data,
12
+ key = _event$data.key,
13
+ message_id = _event$data.message_id;
14
+
15
+ if (!key) {
16
+ postMessageService.sendBadRequestErrorPostMessageResponse('Missing required "key" field');
17
+ return true;
18
+ }
19
+
20
+ if (!message_id) {
21
+ postMessageService.sendBadRequestErrorPostMessageResponse('Missing required "message_id" field"');
22
+ return true;
23
+ }
24
+
25
+ var value = _LocalStorageAdapter.localStorageAdapter.getData(event.origin, key);
26
+
27
+ postMessageService.sendSuccessPostMessageResponse('lti.get_data', {
28
+ key: key,
29
+ value: value
30
+ }, event.source, event.origin);
31
+ };
32
+
33
+ var _default = handleGetData;
34
+ exports.default = _default;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+
10
+ var _StorageExhaustionError = _interopRequireDefault(require("../StorageExhaustionError.js"));
11
+
12
+ var _LocalStorageAdapter = require("../LocalStorageAdapter.js");
13
+
14
+ var SUBJECT = 'lti.put_data';
15
+
16
+ var handlePutData = function handlePutData(event, postMessageService) {
17
+ var _event$data = event.data,
18
+ key = _event$data.key,
19
+ value = _event$data.value,
20
+ message_id = _event$data.message_id;
21
+
22
+ if (!key) {
23
+ postMessageService.sendBadRequestErrorPostMessageResponse(SUBJECT, "Missing required 'key' field", event.source, event.origin);
24
+ return true;
25
+ }
26
+
27
+ if (!message_id) {
28
+ postMessageService.sendBadRequestErrorPostMessageResponse(SUBJECT, 'Missing required "message_id" field', event.source, event.origin);
29
+ return true;
30
+ }
31
+
32
+ if (value) {
33
+ try {
34
+ _LocalStorageAdapter.localStorageAdapter.putData(event.origin, key, value);
35
+
36
+ postMessageService.sendSuccessPostMessageResponse(SUBJECT, {
37
+ key: key,
38
+ value: value
39
+ }, event.source, event.origin);
40
+ } catch (e) {
41
+ if (e instanceof _StorageExhaustionError.default) {
42
+ var code = e.code;
43
+ var message = e.message;
44
+ postMessageService.sendErrorPostMessageResponse(SUBJECT, message, code, event.source, event.origin);
45
+ }
46
+ }
47
+ } else {
48
+ _LocalStorageAdapter.localStorageAdapter.clearData(event.origin, key);
49
+
50
+ postMessageService.sendResponse(SUBJECT, {
51
+ key: key
52
+ }, event.source, event.origin);
53
+ }
54
+ };
55
+
56
+ var _default = handlePutData;
57
+ exports.default = _default;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = exports.SAME_WINDOW_LAUNCH_TYPE = void 0;
9
+
10
+ var _forwardMessage = _interopRequireDefault(require("./forwardMessage.js"));
11
+
12
+ var SAME_WINDOW_LAUNCH_TYPE = 'same_window';
13
+ exports.SAME_WINDOW_LAUNCH_TYPE = SAME_WINDOW_LAUNCH_TYPE;
14
+
15
+ var handleRequestFullWindowLaunch = function handleRequestFullWindowLaunch(event) {
16
+ var _event$data, _event$data$data;
17
+
18
+ if ((event === null || event === void 0 ? void 0 : (_event$data = event.data) === null || _event$data === void 0 ? void 0 : (_event$data$data = _event$data.data) === null || _event$data$data === void 0 ? void 0 : _event$data$data.launchType) === SAME_WINDOW_LAUNCH_TYPE) {
19
+ return;
20
+ }
21
+
22
+ (0, _forwardMessage.default)(event);
23
+ };
24
+
25
+ var _default = handleRequestFullWindowLaunch;
26
+ exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/quiz-core",
3
- "version": "17.53.1-rc.1+95e89c485",
3
+ "version": "17.53.1-rc.11+ddb9475ba",
4
4
  "license": "MIT",
5
5
  "description": "The Quiz React SDK by Instructure Inc.",
6
6
  "author": "Instructure, Inc. Engineering and Product Design",
@@ -41,11 +41,11 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@instructure/outcomes-ui": "^2.1.7",
44
- "@instructure/quiz-common": "17.53.1-rc.1+95e89c485",
45
- "@instructure/quiz-i18n": "17.53.1-rc.1+95e89c485",
46
- "@instructure/quiz-interactions": "17.53.1-rc.1+95e89c485",
47
- "@instructure/quiz-number-input": "17.53.1-rc.1+95e89c485",
48
- "@instructure/quiz-rce": "17.53.1-rc.1+95e89c485",
44
+ "@instructure/quiz-common": "17.53.1-rc.11+ddb9475ba",
45
+ "@instructure/quiz-i18n": "17.53.1-rc.11+ddb9475ba",
46
+ "@instructure/quiz-interactions": "17.53.1-rc.11+ddb9475ba",
47
+ "@instructure/quiz-number-input": "17.53.1-rc.11+ddb9475ba",
48
+ "@instructure/quiz-rce": "17.53.1-rc.11+ddb9475ba",
49
49
  "@instructure/ui-a11y-content": "^7.20.0",
50
50
  "@instructure/ui-alerts": "^7.20.0",
51
51
  "@instructure/ui-avatar": "^7.20.0",
@@ -106,7 +106,7 @@
106
106
  "eventemitter3": "^3.1.0",
107
107
  "humps": "^2.0.0",
108
108
  "immutable": "^3.8.1",
109
- "instructure-validations": "17.53.1-rc.1+95e89c485",
109
+ "instructure-validations": "17.53.1-rc.11+ddb9475ba",
110
110
  "ipaddr.js": "^1.5.4",
111
111
  "isomorphic-fetch": "^2.2.0",
112
112
  "isuuid": "^0.1.0",
@@ -156,7 +156,7 @@
156
156
  "intl": "^1.2.4",
157
157
  "jquery": "^2.2.3",
158
158
  "most-subject": "^5.3.0",
159
- "quiz-presets": "17.53.1-rc.1+95e89c485",
159
+ "quiz-presets": "17.53.1-rc.11+ddb9475ba",
160
160
  "react": "^16.8.6",
161
161
  "react-addons-test-utils": "^15.6.2",
162
162
  "react-dom": "^16.8.6",
@@ -172,5 +172,5 @@
172
172
  "publishConfig": {
173
173
  "access": "public"
174
174
  },
175
- "gitHead": "95e89c485d521d802218f90909273009f03d62bf"
175
+ "gitHead": "ddb9475ba46e701f3cdb2d80cb34a0713c0916c1"
176
176
  }
@@ -1,15 +0,0 @@
1
- var handleScrollToTop = function handleScrollToTop(event, postMessageService) {
2
- var container = document.getElementById('scrollable-tool-container');
3
-
4
- if (container) {
5
- container.scrollTo({
6
- top: 0,
7
- behavior: 'smooth'
8
- });
9
- postMessageService.sendSuccessPostMessageResponse('lti.scrollToTop', void 0, event.source);
10
- }
11
-
12
- return false;
13
- };
14
-
15
- export default handleScrollToTop;
@@ -1,23 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var handleScrollToTop = function handleScrollToTop(event, postMessageService) {
9
- var container = document.getElementById('scrollable-tool-container');
10
-
11
- if (container) {
12
- container.scrollTo({
13
- top: 0,
14
- behavior: 'smooth'
15
- });
16
- postMessageService.sendSuccessPostMessageResponse('lti.scrollToTop', void 0, event.source);
17
- }
18
-
19
- return false;
20
- };
21
-
22
- var _default = handleScrollToTop;
23
- exports.default = _default;