@instructure/canvas-rce 5.14.0 → 5.14.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/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+ ## 5.14.1 - 2024-10-28
8
+
9
+ ### Changed
10
+
11
+ - Forward along access token and inst_ui parameters from file URLs.
7
12
 
8
13
  ## 5.14.0 - 2024-10-18
9
14
 
@@ -19,6 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
24
 
20
25
  - Upgraded React to 18
21
26
 
27
+ ## 5.13.7 - 2024-10-28
28
+
29
+ ### Changed
30
+
31
+ - Forward along access token and inst_ui parameters from file URLs.
32
+
22
33
  ## 5.13.6 - 2024-09-25
23
34
 
24
35
  ### Fixed
@@ -36,6 +47,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
36
47
  - Added IDs to multiple objects missing IDs
37
48
  - Add loading spinners to image uploads
38
49
 
50
+ ## 5.13.5 - 2024-09-25
51
+
52
+ ### Fixed
53
+
54
+ - File links with data-canvas-previewable='false' will no longer try to preview
55
+ - Change backgroundless buttons to "primary" theme color to be more visible
56
+ - Fix LTI tool scrolling issue on small iOS devices
57
+ - Adding missing translation strings
58
+ - Fixed some types of non-Canvas files from trying to preview like Canvas files
59
+
60
+ ### Changed
61
+
62
+ - Allow links with data-old-link to replace the existing src or href with the contents
63
+ of the data-old-link attribute
64
+ - Added IDs to multiple objects missing IDs
65
+ - Add loading spinners to image uploads
66
+
39
67
  ## 5.13.5 - 2024-08-12
40
68
 
41
69
  ### Fixed
package/build.sh CHANGED
@@ -1,23 +1,23 @@
1
1
  #!/bin/bash
2
2
  export COMPOSE_FILE=./docker-compose.yml
3
3
 
4
- docker-compose build
5
- docker-compose up -d
4
+ docker compose build
5
+ docker compose up -d
6
6
 
7
7
  # run unit tests
8
- docker-compose exec -T module npm run test-cov
8
+ docker compose exec -T module npm run test-cov
9
9
  unit_status=$?
10
- docker cp $(docker-compose ps -q module):/usr/src/app/coverage coverage
10
+ docker cp $(docker compose ps -q module):/usr/src/app/coverage coverage
11
11
 
12
12
  # check code formatting
13
- docker-compose exec -T module npm run fmt:check
13
+ docker compose exec -T module npm run fmt:check
14
14
  fmt_status=$?
15
15
 
16
16
  # lint all the things
17
- docker-compose exec -T module npm run lint
17
+ docker compose exec -T module npm run lint
18
18
  lint_status=$?
19
19
 
20
- docker-compose stop
20
+ docker compose stop
21
21
 
22
22
  # jenkins uses the exit code to decide whether you passed or not
23
23
  ((unit_status)) && exit $unit_status
@@ -102,16 +102,25 @@ export function showFilePreviewInOverlay(event, canvasOrigin) {
102
102
  event.preventDefault();
103
103
  const url = new URL(target.href);
104
104
  const verifier = url === null || url === void 0 ? void 0 : url.searchParams.get('verifier');
105
- const file_id = matches[1]; // TODO:
106
- // 1. what window should be be using
105
+ const access_token = url === null || url === void 0 ? void 0 : url.searchParams.get('access_token');
106
+ const instfs_id = url === null || url === void 0 ? void 0 : url.searchParams.get('instfs_id');
107
+ const file_id = matches[1];
108
+ const params = {
109
+ subject: 'preview_file',
110
+ file_id
111
+ };
112
+ if (verifier) params.verifier = verifier;
113
+
114
+ if (access_token && instfs_id) {
115
+ params.access_token = access_token;
116
+ params.instfs_id = instfs_id;
117
+ } // TODO:
118
+ // 1. what window should we be using
107
119
  // 2. is that the right origin?
108
120
  // 3. this is temporary until we can decouple the file previewer from canvas
109
121
 
110
- window.top.postMessage({
111
- subject: 'preview_file',
112
- file_id,
113
- verifier
114
- }, canvasOrigin);
122
+
123
+ window.top.postMessage(params, canvasOrigin);
115
124
  }
116
125
  }
117
126
  export function showFilePreviewInline(event, canvasOrigin, disableGooglePreviews) {
@@ -0,0 +1,124 @@
1
+ /*
2
+ * Copyright (C) 2023 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ export default {
19
+ lib: {
20
+ Base: {},
21
+ WordArray: {},
22
+ BufferedBlockAlgorithm: {},
23
+ Hasher: {},
24
+ Cipher: {},
25
+ StreamCipher: {},
26
+ BlockCipherMode: {},
27
+ BlockCipher: {},
28
+ CipherParams: {},
29
+ SerializableCipher: {},
30
+ PasswordBasedCipher: {}
31
+ },
32
+ x64: {
33
+ Word: {},
34
+ WordArray: {}
35
+ },
36
+ enc: {
37
+ Hex: {},
38
+ Latin1: {},
39
+ Utf8: {
40
+ parse: () => {}
41
+ },
42
+ Utf16: {},
43
+ Utf16BE: {},
44
+ Utf16LE: {},
45
+ Base64: {},
46
+ Base64url: {}
47
+ },
48
+ algo: {
49
+ HMAC: {},
50
+ MD5: {},
51
+ SHA1: {},
52
+ SHA224: {},
53
+ SHA256: {},
54
+ SHA384: {},
55
+ SHA512: {},
56
+ SHA3: {},
57
+ RIPEMD160: {},
58
+ PBKDF2: {},
59
+ EvpKDF: {},
60
+ AES: {},
61
+ DES: {},
62
+ TripleDES: {},
63
+ Rabbit: {},
64
+ RabbitLegacy: {},
65
+ RC4: {},
66
+ RC4Drop: {},
67
+ Blowfish: {}
68
+ },
69
+ mode: {
70
+ CBC: {},
71
+ CFB: {},
72
+ CTR: {},
73
+ CTRGladman: {},
74
+ ECB: {},
75
+ OFB: {}
76
+ },
77
+ pad: {
78
+ Pkcs7: {},
79
+ AnsiX923: {},
80
+ Iso10126: {},
81
+ Iso97971: {},
82
+ NoPadding: {},
83
+ ZeroPadding: {}
84
+ },
85
+ format: {
86
+ OpenSSL: {},
87
+ Hex: {}
88
+ },
89
+ kdf: {
90
+ OpenSSL: {}
91
+ },
92
+ MD5: {},
93
+ HmacMD5: {},
94
+ SHA1: {},
95
+ HmacSHA1: {},
96
+ SHA224: {},
97
+ HmacSHA224: {},
98
+ SHA256: {},
99
+ HmacSHA256: {},
100
+ SHA384: {},
101
+ HmacSHA384: {},
102
+ SHA512: {},
103
+ HmacSHA512: {},
104
+ SHA3: {},
105
+ HmacSHA3: {},
106
+ RIPEMD160: {},
107
+ HmacRIPEMD160: {},
108
+ PBKDF2: {},
109
+ EvpKDF: {},
110
+ AES: {},
111
+ DES: {},
112
+ TripleDES: {},
113
+ Rabbit: {},
114
+ RabbitLegacy: {},
115
+ RC4: {
116
+ encrypt: () => {},
117
+ decrypt: () => {}
118
+ },
119
+ RC4Drop: {
120
+ encrypt: () => {},
121
+ decrypt: () => {}
122
+ },
123
+ Blowfish: {}
124
+ };
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright (C) 2024 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ module.exports = {
19
+ StudioPlayer: () => null
20
+ };
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (C) 2022 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ module.export = {};
@@ -0,0 +1,55 @@
1
+ /*
2
+ * Copyright (C) 2021 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ /*
20
+ * This is a mock for the @tinymce/tinymce-react Editor component
21
+ * and the inner tinymce editor object
22
+ * jest.config.js moduleNameMapper has jest load this
23
+ * file in response to
24
+ * import {Editor} from '@tinymce/tinymce-react'
25
+ * in RCEWrapper.js
26
+ */
27
+ import React, { useEffect, useRef } from 'react';
28
+ import FakeEditor from '../__tests__/FakeEditor';
29
+ export function Editor(props) {
30
+ const editorRef = useRef(null);
31
+ const textareaRef = useRef(null);
32
+ const tinymceEditor = useRef(new FakeEditor(props));
33
+ window.tinymce.editors[0] = tinymceEditor.current;
34
+ useEffect(() => {
35
+ tinymceEditor.current.on('change', handleChange);
36
+ props.onInit && props.onInit({}, tinymceEditor.current); // eslint-disable-next-line react-hooks/exhaustive-deps
37
+ }, []);
38
+
39
+ function handleChange(event) {
40
+ var _props$onEditorChange;
41
+
42
+ (_props$onEditorChange = props.onEditorChange) === null || _props$onEditorChange === void 0 ? void 0 : _props$onEditorChange.call(props, event.target.value);
43
+ }
44
+
45
+ return /*#__PURE__*/React.createElement("div", {
46
+ ref: editorRef
47
+ }, /*#__PURE__*/React.createElement("textarea", {
48
+ ref: textareaRef,
49
+ id: props.id,
50
+ name: props.textareaName,
51
+ value: props.initialValue,
52
+ onInput: handleChange,
53
+ onChange: handleChange
54
+ }));
55
+ }
@@ -88,7 +88,7 @@ export default function CanvasContentTray(props) {
88
88
  const [hidingTrayOnAction, setHidingTrayOnAction] = useState(true);
89
89
  const trayRef = useRef(null);
90
90
  const scrollingAreaRef = useRef(null);
91
- const closeButtonRef = useRef(null);
91
+ const [closeButtonRef, setCloseButtonRef] = useState(null);
92
92
  const [filterSettings, setFilterSettings] = useFilterSettings();
93
93
  const [isEditTray, setIsEditTray] = useState(false);
94
94
  const [link, setLink] = useState(null);
@@ -111,12 +111,17 @@ export default function CanvasContentTray(props) {
111
111
  onTrayClosing && onTrayClosing(CanvasContentTray.globalOpenCount); // tell RCEWrapper we're closing if we're open
112
112
 
113
113
  setIsOpen(false);
114
- }, [bridge, onTrayClosing]);
114
+ }, [bridge, onTrayClosing]); // this shouldn't be necessary, but INSTUI isn't focusing the close button
115
+ // like it should.
116
+
117
+ useEffect(() => {
118
+ if (isOpen && closeButtonRef) {
119
+ closeButtonRef.focus();
120
+ }
121
+ }, [closeButtonRef, isOpen]);
115
122
  useEffect(() => {
116
123
  const controller = {
117
124
  showTrayForPlugin(plugin) {
118
- var _closeButtonRef$curre;
119
-
120
125
  // increment a counter that's used as the key when rendering
121
126
  // this gets us a new instance everytime, which is necessary
122
127
  // to get the queries run so we have up to date data.
@@ -144,8 +149,6 @@ export default function CanvasContentTray(props) {
144
149
  } else {
145
150
  setIsEditTray(false);
146
151
  }
147
-
148
- (_closeButtonRef$curre = closeButtonRef.current) === null || _closeButtonRef$curre === void 0 ? void 0 : _closeButtonRef$curre.focus();
149
152
  },
150
153
 
151
154
  hideTray(forceClose) {
@@ -290,6 +293,17 @@ export default function CanvasContentTray(props) {
290
293
  return isEditTray ? formatMessage('Edit Course Link') : formatMessage('Add');
291
294
  }
292
295
 
296
+ function renderLinkDisplay() {
297
+ return isEditTray && /*#__PURE__*/React.createElement(LinkDisplay, {
298
+ linkText: linkText,
299
+ placeholderText: (link === null || link === void 0 ? void 0 : link.title) || placeholderText,
300
+ linkFileName: (link === null || link === void 0 ? void 0 : link.title) || '',
301
+ published: (link === null || link === void 0 ? void 0 : link.published) || false,
302
+ handleTextChange: setLinkText,
303
+ linkType: link === null || link === void 0 ? void 0 : link.type
304
+ });
305
+ }
306
+
293
307
  return /*#__PURE__*/React.createElement(Tray, {
294
308
  "data-mce-component": true,
295
309
  "data-testid": "CanvasContentTray",
@@ -306,7 +320,7 @@ export default function CanvasContentTray(props) {
306
320
  onExit: handleExitTray,
307
321
  onOpen: handleOpenTray,
308
322
  contentRef: el => trayRef.current = el
309
- }, isOpen && hasOpened ? /*#__PURE__*/React.createElement(Flex, {
323
+ }, /*#__PURE__*/React.createElement(Flex, {
310
324
  direction: "column",
311
325
  as: "div",
312
326
  height: getTrayHeight(),
@@ -327,15 +341,8 @@ export default function CanvasContentTray(props) {
327
341
  onClick: handleDismissTray,
328
342
  "data-testid": "CloseButton_ContentTray",
329
343
  screenReaderLabel: formatMessage('Close'),
330
- elementRef: el => closeButtonRef.current = el
331
- })), isEditTray && /*#__PURE__*/React.createElement(LinkDisplay, {
332
- linkText: linkText,
333
- placeholderText: (link === null || link === void 0 ? void 0 : link.title) || placeholderText,
334
- linkFileName: (link === null || link === void 0 ? void 0 : link.title) || '',
335
- published: (link === null || link === void 0 ? void 0 : link.published) || false,
336
- handleTextChange: setLinkText,
337
- linkType: link === null || link === void 0 ? void 0 : link.type
338
- }), /*#__PURE__*/React.createElement(Filter, Object.assign({}, filterSettings, {
344
+ elementRef: el => setCloseButtonRef(el)
345
+ })), renderLinkDisplay(), /*#__PURE__*/React.createElement(Filter, Object.assign({}, filterSettings, {
339
346
  mountNode: props.mountNode,
340
347
  userContextType: props.contextType,
341
348
  containingContextType: props.containingContext.contextType,
@@ -344,7 +351,7 @@ export default function CanvasContentTray(props) {
344
351
  },
345
352
  isContentLoading: isLoading(storeProps),
346
353
  use_rce_icon_maker: props.use_rce_icon_maker
347
- }))), /*#__PURE__*/React.createElement(Flex.Item, {
354
+ }))), isOpen && hasOpened ? /*#__PURE__*/React.createElement(Flex.Item, {
348
355
  shouldGrow: true,
349
356
  shouldShrink: true,
350
357
  margin: "xx-small xxx-small 0",
@@ -372,7 +379,7 @@ export default function CanvasContentTray(props) {
372
379
  editing: isEditTray,
373
380
  onEditClick: setLink,
374
381
  selectedLink: link
375
- }, storeProps)))), isEditTray && renderFooter()))) : null);
382
+ }, storeProps)))), isEditTray && renderFooter())) : null));
376
383
  }
377
384
  CanvasContentTray.globalOpenCount = 0;
378
385
 
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright (C) 2019 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ const screenfull = {
19
+ on() {},
20
+
21
+ off() {}
22
+
23
+ };
24
+ export default screenfull;
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Copyright (C) 2023 - present Instructure, Inc.
3
+ *
4
+ * This file is part of Canvas.
5
+ *
6
+ * Canvas is free software: you can redistribute it and/or modify it under
7
+ * the terms of the GNU Affero General Public License as published by the Free
8
+ * Software Foundation, version 3 of the License.
9
+ *
10
+ * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ * details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License along
16
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ export default [{
19
+ test: jest.fn().mockReturnValue(false),
20
+ data: jest.fn().mockReturnValue({
21
+ select: 'a',
22
+ checkbox: true,
23
+ color: 'rgba(40, 100, 200, 0.6)',
24
+ text: 'Text'
25
+ }),
26
+ form: jest.fn().mockReturnValue([{
27
+ label: 'Select Field',
28
+ dataKey: 'select',
29
+ options: [['a', 'A'], ['b', 'B']]
30
+ }, {
31
+ label: 'Select Field',
32
+ dataKey: 'checkbox',
33
+ checkbox: true
34
+ }, {
35
+ label: 'Select Field',
36
+ dataKey: 'color',
37
+ color: true
38
+ }, {
39
+ label: 'Text Field',
40
+ dataKey: 'text',
41
+ disabledIf: () => true
42
+ }, {
43
+ label: 'Text Area',
44
+ dataKey: 'textarea',
45
+ textarea: true
46
+ }]),
47
+ rootNode: jest.fn(),
48
+ update: jest.fn(),
49
+ message: jest.fn().mockReturnValue('Error Message'),
50
+ why: jest.fn().mockReturnValue('Why Text'),
51
+ link: 'http://some-url',
52
+ linkText: jest.fn().mockReturnValue('Link for learning more')
53
+ }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/canvas-rce",
3
- "version": "5.14.0",
3
+ "version": "5.14.1",
4
4
  "description": "A component wrapping Canvas's usage of Tinymce",
5
5
  "main": "es/index.js",
6
6
  "owner": "LF",
@@ -32,7 +32,7 @@
32
32
  "demo": "scripts/demo.sh",
33
33
  "demo:clean": "rm -f github-pages/dist/*",
34
34
  "demo:build": "wp -c ./webpack.demo.config.js",
35
- "demo:dev": "yarn demo:clean && mkdir -p ./github-pages/dist && cp ./github-pages/index.html ./github-pages/dist && wp -c ./webpack.dev.config.js",
35
+ "demo:dev": "yarn demo:clean && mkdir -p ./github-pages/dist && cp ./github-pages/index.html ./github-pages/dist && wp -c ./webpack.dev.config.js",
36
36
  "installTranslations": "scripts/installTranslations.js",
37
37
  "commitTranslations": "scripts/commitTranslations.sh",
38
38
  "build:all": "scripts/build.js",
@@ -34,7 +34,7 @@ if [ -z "$SKIP_ALERT" ]; then
34
34
  # runs the get-user command and throws away output
35
35
  # checks for nonzero exit code to determine if the
36
36
  # user is logged in or not
37
- aws iam get-user > /dev/null 2>&1
37
+ aws sts get-caller-identity > /dev/null 2>&1
38
38
  if [[ ! $? -eq 0 ]]; then
39
39
  echo -e "\n⚠️ Please log into AWS and try again. ⚠️\n"
40
40
  exit 1
@@ -1,64 +0,0 @@
1
- /*
2
- * Copyright (C) 2018 - present Instructure, Inc.
3
- *
4
- * This file is part of Canvas.
5
- *
6
- * Canvas is free software: you can redistribute it and/or modify it under
7
- * the terms of the GNU Affero General Public License as published by the Free
8
- * Software Foundation, version 3 of the License.
9
- *
10
- * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
- * details.
14
- *
15
- * You should have received a copy of the GNU Affero General Public License along
16
- * with this program. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
- import React, { Component } from 'react';
19
- import { number, string, shape, func } from 'prop-types';
20
- import { css } from 'aphrodite';
21
- import styles from './styles';
22
- import { IconDocumentLine } from '@instructure/ui-icons';
23
- export default class File extends Component {
24
- constructor() {
25
- super(...arguments);
26
-
27
- this.handleSelect = () => {
28
- const {
29
- onSelect,
30
- file
31
- } = this.props;
32
-
33
- if (onSelect) {
34
- onSelect(file.id);
35
- }
36
- };
37
- }
38
-
39
- icon() {
40
- switch (this.props.file.type) {
41
- default:
42
- return /*#__PURE__*/React.createElement(IconDocumentLine, null);
43
- }
44
- }
45
-
46
- render() {
47
- const {
48
- name
49
- } = this.props.file;
50
- return /*#__PURE__*/React.createElement("button", {
51
- className: css(styles.button, styles.file),
52
- onClick: this.handleSelect
53
- }, this.icon(), " ", name);
54
- }
55
-
56
- }
57
- File.propTypes = {
58
- file: shape({
59
- id: number,
60
- name: string,
61
- type: string
62
- }).isRequired,
63
- onSelect: func
64
- };
@@ -1,110 +0,0 @@
1
- /*
2
- * Copyright (C) 2018 - present Instructure, Inc.
3
- *
4
- * This file is part of Canvas.
5
- *
6
- * Canvas is free software: you can redistribute it and/or modify it under
7
- * the terms of the GNU Affero General Public License as published by the Free
8
- * Software Foundation, version 3 of the License.
9
- *
10
- * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
- * details.
14
- *
15
- * You should have received a copy of the GNU Affero General Public License along
16
- * with this program. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
- import PropTypes from 'prop-types';
19
- import React, { Component } from 'react';
20
- import File from './File';
21
- import Loading from '../Loading';
22
- import { css } from 'aphrodite';
23
- import styles from './styles';
24
- import { IconMiniArrowDownLine, IconMiniArrowEndLine, IconFolderLine } from '@instructure/ui-icons';
25
- export default class Folder extends Component {
26
- constructor() {
27
- super(...arguments);
28
-
29
- this.handleToggle = () => {
30
- const {
31
- onToggle,
32
- folder
33
- } = this.props;
34
-
35
- if (onToggle) {
36
- onToggle(folder.id);
37
- }
38
- };
39
- }
40
-
41
- files() {
42
- return this.props.folder.fileIds.map(id => this.props.files[id]).filter(file => file != null);
43
- }
44
-
45
- subFolders() {
46
- return this.props.folder.folderIds.map(id => this.props.folders[id]).filter(folder => folder != null);
47
- }
48
-
49
- toggleIcon() {
50
- const {
51
- expanded
52
- } = this.props.folder;
53
- return expanded ? /*#__PURE__*/React.createElement(IconMiniArrowDownLine, null) : /*#__PURE__*/React.createElement(IconMiniArrowEndLine, null);
54
- }
55
-
56
- render() {
57
- const {
58
- folders,
59
- folder,
60
- files,
61
- onSelect,
62
- onToggle
63
- } = this.props;
64
- return /*#__PURE__*/React.createElement("div", {
65
- className: css(styles.node)
66
- }, /*#__PURE__*/React.createElement("button", {
67
- className: css(styles.button),
68
- onClick: this.handleToggle,
69
- "aria-expanded": !!folder.expanded
70
- }, this.toggleIcon(), " ", /*#__PURE__*/React.createElement(IconFolderLine, null), " ", folder.name), folder.expanded && /*#__PURE__*/React.createElement("ul", {
71
- className: css(styles.list)
72
- }, this.subFolders().map(folder => /*#__PURE__*/React.createElement("li", {
73
- key: `folder-${folder.id}`,
74
- className: css(styles.node)
75
- }, /*#__PURE__*/React.createElement(Folder, {
76
- folders: folders,
77
- files: files,
78
- folder: folder,
79
- onToggle: onToggle,
80
- onSelect: onSelect
81
- }))), this.files().map(file => /*#__PURE__*/React.createElement("li", {
82
- key: `file-${file.id}`,
83
- className: css(styles.node)
84
- }, /*#__PURE__*/React.createElement(File, {
85
- onSelect: onSelect,
86
- file: file
87
- })))), folder.expanded && folder.loading && /*#__PURE__*/React.createElement(Loading, {
88
- className: css(styles.loading)
89
- }));
90
- }
91
-
92
- }
93
- const folderPropType = PropTypes.shape({
94
- id: PropTypes.number,
95
- name: PropTypes.string,
96
- loading: PropTypes.bool,
97
- fileIds: PropTypes.arrayOf(PropTypes.number),
98
- folderIds: PropTypes.arrayOf(PropTypes.number)
99
- });
100
- Folder.propTypes = {
101
- folders: PropTypes.objectOf(folderPropType),
102
- files: PropTypes.objectOf(File.propTypes.file),
103
- folder: folderPropType.isRequired,
104
- onToggle: PropTypes.func,
105
- onSelect: File.propTypes.onSelect
106
- };
107
- Folder.defaultProps = {
108
- files: [],
109
- folders: []
110
- };
@@ -1,84 +0,0 @@
1
- /*
2
- * Copyright (C) 2018 - present Instructure, Inc.
3
- *
4
- * This file is part of Canvas.
5
- *
6
- * Canvas is free software: you can redistribute it and/or modify it under
7
- * the terms of the GNU Affero General Public License as published by the Free
8
- * Software Foundation, version 3 of the License.
9
- *
10
- * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
- * details.
14
- *
15
- * You should have received a copy of the GNU Affero General Public License along
16
- * with this program. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
- import PropTypes from 'prop-types';
19
- import React, { Component } from 'react';
20
- import Folder from './Folder';
21
- import { css } from 'aphrodite';
22
- import styles from './styles';
23
- const DOWN_KEY = 40;
24
- const UP_KEY = 38;
25
- const J_KEY = 74;
26
- const K_KEY = 75;
27
- export default class FileTree extends Component {
28
- constructor() {
29
- super(...arguments);
30
-
31
- this.handleKeyDown = event => {
32
- switch (event.keyCode) {
33
- case DOWN_KEY:
34
- case J_KEY:
35
- this.moveFocus(1);
36
- break;
37
-
38
- case UP_KEY:
39
- case K_KEY:
40
- this.moveFocus(-1);
41
- break;
42
-
43
- default:
44
- return;
45
- }
46
-
47
- event.stopPropagation();
48
- };
49
- }
50
-
51
- navigableNodes() {
52
- return Array.from(this.containerNode.querySelectorAll('button'));
53
- }
54
-
55
- moveFocus(delta) {
56
- const nodes = this.navigableNodes();
57
- const active = nodes.indexOf(window.document.activeElement);
58
- let next = active + delta;
59
-
60
- if (next < 0) {
61
- next = 0;
62
- } else if (next >= nodes.length) {
63
- next = nodes.length - 1;
64
- }
65
-
66
- nodes[next].focus();
67
- }
68
-
69
- render() {
70
- const inlineStyles = {
71
- maxHeight: this.props.maxHeight
72
- };
73
- return /*#__PURE__*/React.createElement("div", {
74
- className: css(styles.container),
75
- ref: c => this.containerNode = c,
76
- onKeyDown: this.handleKeyDown,
77
- style: inlineStyles
78
- }, /*#__PURE__*/React.createElement(Folder, this.props));
79
- }
80
-
81
- }
82
- FileTree.propTypes = { ...Folder.propTypes,
83
- maxHeight: PropTypes.string
84
- };
@@ -1,72 +0,0 @@
1
- /*
2
- * Copyright (C) 2018 - present Instructure, Inc.
3
- *
4
- * This file is part of Canvas.
5
- *
6
- * Canvas is free software: you can redistribute it and/or modify it under
7
- * the terms of the GNU Affero General Public License as published by the Free
8
- * Software Foundation, version 3 of the License.
9
- *
10
- * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
- * details.
14
- *
15
- * You should have received a copy of the GNU Affero General Public License along
16
- * with this program. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
- import { StyleSheet } from 'aphrodite';
19
- export default StyleSheet.create({
20
- container: {
21
- marginBottom: '1em',
22
- overflow: 'auto'
23
- },
24
- list: {
25
- margin: '0 0 0 .8em',
26
- padding: '0 0 0 .2em',
27
- borderLeft: '1px dotted #ccc',
28
- listStyle: 'none outside',
29
- flex: 1
30
- },
31
- node: {
32
- margin: 0,
33
- padding: 0,
34
- display: 'block'
35
- },
36
- loading: {
37
- marginLeft: '.8em',
38
- borderLeft: '1px dotted #ccc',
39
- padding: '.5em .7em'
40
- },
41
- button: {
42
- display: 'block',
43
- padding: '.3em',
44
- borderRadius: '.3em',
45
- backgroundColor: 'transparent',
46
- textAlign: 'left',
47
- margin: 0,
48
- fontFamily: 'inherit',
49
- fontSize: 'inherit',
50
- flex: 1,
51
- width: '100%',
52
- boxSizing: 'border-box',
53
- border: '1px solid transparent',
54
- transition: 'background-color 0.3s',
55
- wordBreak: 'break-all',
56
- ':hover': {
57
- backgroundColor: '#eee'
58
- },
59
- ':focus': {
60
- border: '1px solid #000',
61
- outline: 0
62
- },
63
- ':active': {
64
- backgroundColor: '#ddd'
65
- }
66
- },
67
- file: {
68
- ':active': {
69
- backgroundColor: '#008a14'
70
- }
71
- }
72
- });
@@ -1,83 +0,0 @@
1
- /*
2
- * Copyright (C) 2018 - present Instructure, Inc.
3
- *
4
- * This file is part of Canvas.
5
- *
6
- * Canvas is free software: you can redistribute it and/or modify it under
7
- * the terms of the GNU Affero General Public License as published by the Free
8
- * Software Foundation, version 3 of the License.
9
- *
10
- * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
- * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
- * details.
14
- *
15
- * You should have received a copy of the GNU Affero General Public License along
16
- * with this program. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
- import PropTypes from 'prop-types';
19
- import React, { Component } from 'react';
20
- import formatMessage from '../../format-message';
21
- import { ScreenReaderContent } from '@instructure/ui-a11y-content';
22
- import { StyleSheet, css } from 'aphrodite';
23
-
24
- function Loading(props) {
25
- const className = (css(styles.loading) + ' ' + props.className).trim();
26
- return /*#__PURE__*/React.createElement("span", {
27
- className: className
28
- }, /*#__PURE__*/React.createElement(ScreenReaderContent, null, formatMessage('Loading...')), /*#__PURE__*/React.createElement("span", {
29
- className: css(styles.dot, styles.dot0)
30
- }), /*#__PURE__*/React.createElement("span", {
31
- className: css(styles.dot, styles.dot1)
32
- }), /*#__PURE__*/React.createElement("span", {
33
- className: css(styles.dot, styles.dot2)
34
- }));
35
- }
36
-
37
- Loading.propTypes = {
38
- className: PropTypes.string
39
- };
40
- Loading.defaultProps = {
41
- className: ''
42
- };
43
- const opacityKeyframes = {
44
- '0%': {
45
- opacity: 0
46
- },
47
- '50%': {
48
- opacity: 1
49
- },
50
- '100%': {
51
- opacity: 0
52
- }
53
- };
54
- const styles = StyleSheet.create({
55
- loading: {
56
- display: 'inline-flex',
57
- alignItems: 'center',
58
- justifyContent: 'space-around',
59
- width: '48px',
60
- height: '10px'
61
- },
62
- dot: {
63
- animationName: [opacityKeyframes],
64
- animationDuration: '1.95s',
65
- animationIterationCount: 'infinite',
66
- animationDirection: 'linear',
67
- background: '#666',
68
- borderRadius: '8px',
69
- width: '10px',
70
- height: '10px',
71
- flex: 'none'
72
- },
73
- dot0: {
74
- animationDelay: '-1.8s'
75
- },
76
- dot1: {
77
- animationDelay: '-1.6s'
78
- },
79
- dot2: {
80
- animationDelay: '-1.4s'
81
- }
82
- });
83
- export default Loading;