@windward/core 0.0.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.
Files changed (113) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc.js +11 -0
  3. package/.prettierrc +4 -0
  4. package/README.md +86 -0
  5. package/babel.config.js +1 -0
  6. package/components/Content/Blocks/Accordion.vue +133 -0
  7. package/components/Content/Blocks/ClickableIcons.vue +98 -0
  8. package/components/Content/Blocks/Feedback.vue +323 -0
  9. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionLikert.vue +95 -0
  10. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.vue +45 -0
  11. package/components/Content/Blocks/FeedbackTemplates/FeedbackQuestionTrueFalse.vue +55 -0
  12. package/components/Content/Blocks/Image.vue +116 -0
  13. package/components/Content/Blocks/Math.vue +87 -0
  14. package/components/Content/Blocks/Tab.vue +89 -0
  15. package/components/Content/Blocks/Table.vue +68 -0
  16. package/components/Content/Blocks/UserUpload/DisplayUserFilesTable.vue +157 -0
  17. package/components/Content/Blocks/UserUpload/ManageDataTableUserFiles.vue +68 -0
  18. package/components/Content/Blocks/UserUpload.vue +240 -0
  19. package/components/Content/Blocks/Video.vue +245 -0
  20. package/components/Navigation/Items/CourseGlossaryToolNav.vue +39 -0
  21. package/components/Navigation/Items/GlossaryNav.vue +32 -0
  22. package/components/Navigation/Items/UserUploadNav.vue +35 -0
  23. package/components/Settings/AccordionSettings.vue +153 -0
  24. package/components/Settings/ClickableIconsSettings.vue +189 -0
  25. package/components/Settings/FeedbackSettings.vue +92 -0
  26. package/components/Settings/ImageSettings.vue +124 -0
  27. package/components/Settings/MathSettings.vue +81 -0
  28. package/components/Settings/TabSettings.vue +139 -0
  29. package/components/Settings/TextEditorSettings.vue +249 -0
  30. package/components/Settings/UserUploadSettings.vue +151 -0
  31. package/components/Settings/VideoSettings.vue +699 -0
  32. package/components/utils/ContentViewer.vue +69 -0
  33. package/components/utils/MathExpressionEditor.vue +294 -0
  34. package/components/utils/MathLiveWrapper.vue +86 -0
  35. package/components/utils/TinyMCEWrapper.vue +103 -0
  36. package/components/utils/glossary/CourseGlossary.vue +284 -0
  37. package/components/utils/glossary/CourseGlossaryForm.vue +106 -0
  38. package/components/utils/glossary/GlossaryToolTip.vue +87 -0
  39. package/config/tinymce.config.js +136 -0
  40. package/helpers/GlossaryHelper.ts +137 -0
  41. package/helpers/GlossaryTerm.ts +31 -0
  42. package/helpers/MathHelper.ts +236 -0
  43. package/helpers/tinymce/plugin.ts +83 -0
  44. package/i18n/en-US/components/content/blocks/feedback.ts +28 -0
  45. package/i18n/en-US/components/content/blocks/image.ts +5 -0
  46. package/i18n/en-US/components/content/blocks/index.ts +15 -0
  47. package/i18n/en-US/components/content/blocks/tab.ts +4 -0
  48. package/i18n/en-US/components/content/blocks/table.ts +4 -0
  49. package/i18n/en-US/components/content/blocks/user_upload.ts +12 -0
  50. package/i18n/en-US/components/content/blocks/video.ts +53 -0
  51. package/i18n/en-US/components/content/index.ts +5 -0
  52. package/i18n/en-US/components/index.ts +12 -0
  53. package/i18n/en-US/components/navigation/image.ts +4 -0
  54. package/i18n/en-US/components/navigation/index.ts +7 -0
  55. package/i18n/en-US/components/navigation/user_upload.ts +3 -0
  56. package/i18n/en-US/components/settings/clickable_icon.ts +9 -0
  57. package/i18n/en-US/components/settings/image.ts +1 -0
  58. package/i18n/en-US/components/settings/index.ts +13 -0
  59. package/i18n/en-US/components/settings/text_editor.ts +7 -0
  60. package/i18n/en-US/components/settings/user_upload.ts +11 -0
  61. package/i18n/en-US/components/settings/video.ts +13 -0
  62. package/i18n/en-US/components/utils/index.ts +5 -0
  63. package/i18n/en-US/components/utils/tiny_mce_wrapper.ts +7 -0
  64. package/i18n/en-US/index.ts +16 -0
  65. package/i18n/en-US/modules/index.ts +5 -0
  66. package/i18n/en-US/pages/glossary.ts +7 -0
  67. package/i18n/en-US/pages/index.ts +7 -0
  68. package/i18n/en-US/pages/user_upload.ts +3 -0
  69. package/i18n/en-US/shared/content_blocks.ts +20 -0
  70. package/i18n/en-US/shared/index.ts +11 -0
  71. package/i18n/en-US/shared/menu.ts +3 -0
  72. package/i18n/en-US/shared/permission.ts +15 -0
  73. package/i18n/en-US/shared/settings.ts +15 -0
  74. package/index.js +15 -0
  75. package/jest.config.js +15 -0
  76. package/models/SurveyResult.ts +8 -0
  77. package/models/SurveyTemplate.ts +8 -0
  78. package/models/UserFileAsset.ts +12 -0
  79. package/package.json +48 -0
  80. package/pages/glossary.vue +31 -0
  81. package/pages/userUpload.vue +204 -0
  82. package/plugin.js +299 -0
  83. package/test/Components/Content/Blocks/Accordion.spec.js +21 -0
  84. package/test/Components/Content/Blocks/ClickableIcons.spec.js +21 -0
  85. package/test/Components/Content/Blocks/Feedback.spec.js +31 -0
  86. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionLikert.spec.js +23 -0
  87. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionOpenResponse.spec.js +23 -0
  88. package/test/Components/Content/Blocks/FeedbackTemplates/FeedbackQuestionTrueFalse.spec.js +23 -0
  89. package/test/Components/Content/Blocks/Image.spec.js +34 -0
  90. package/test/Components/Content/Blocks/Math.spec.js +34 -0
  91. package/test/Components/Content/Blocks/Tab.spec.js +20 -0
  92. package/test/Components/Content/Blocks/Table.spec.js +21 -0
  93. package/test/Components/Content/Blocks/UserUpload.spec.js +25 -0
  94. package/test/Components/Content/Blocks/Video.spec.js +112 -0
  95. package/test/Components/Settings/AccordionSettings.spec.js +45 -0
  96. package/test/Components/Settings/ClickableIconsSettings.spec.js +20 -0
  97. package/test/Components/Settings/FeedbackSettings.spec.js +20 -0
  98. package/test/Components/Settings/ImageSettings.spec.js +20 -0
  99. package/test/Components/Settings/MathSettings.spec.js +20 -0
  100. package/test/Components/Settings/TabSettings.spec.js +45 -0
  101. package/test/Components/Settings/UserUploadSettings.spec.js +20 -0
  102. package/test/__mocks__/componentsMock.js +83 -0
  103. package/test/__mocks__/contentBlockMock.js +119 -0
  104. package/test/__mocks__/contentSettingsMock.js +54 -0
  105. package/test/__mocks__/fileMock.js +1 -0
  106. package/test/__mocks__/helpersMock.js +53 -0
  107. package/test/__mocks__/modelMock.js +82 -0
  108. package/test/__mocks__/styleMock.js +1 -0
  109. package/test/helpers/GlossaryHelper.spec.js +227 -0
  110. package/test/helpers/MathHelper.spec.js +128 -0
  111. package/test/mocks.js +140 -0
  112. package/tsconfig.json +15 -0
  113. package/utils/index.js +18 -0
@@ -0,0 +1,284 @@
1
+ <template>
2
+ <v-container justify="center">
3
+ <v-row justify="center" align="center">
4
+ <v-col cols="12">
5
+ <v-data-table
6
+ :key="tableKey"
7
+ :headers="headers"
8
+ :items="glossaryTerms"
9
+ :search="search"
10
+ class="elevation-1"
11
+ >
12
+ <template #top>
13
+ <v-toolbar flat>
14
+ <Dialog
15
+ v-model="dialog"
16
+ color="primary"
17
+ max-width="600px"
18
+ :trigger="
19
+ $PermissionService.userHasAccessTo(
20
+ 'windward.global.course,windward.organization.course.contentBlock',
21
+ 'writable'
22
+ )
23
+ "
24
+ :action-save-new="
25
+ $PermissionService.userHasAccessTo(
26
+ 'windward.global.course,windward.organization.course.contentBlock',
27
+ 'writable'
28
+ )
29
+ "
30
+ :action-save="
31
+ $PermissionService.userHasAccessTo(
32
+ 'windward.global.course,windward.organization.course.contentBlock',
33
+ 'writable'
34
+ )
35
+ "
36
+ @click:save="save"
37
+ @click:save-new="saveNew"
38
+ @click:trigger="addTerm"
39
+ @click:outside="close"
40
+ @click:close="close"
41
+ @keydown.esc="close"
42
+ >
43
+ <template #title>
44
+ {{
45
+ $t('shared.forms.add') +
46
+ ' ' +
47
+ $t('windward.core.pages.glossary.term')
48
+ }}
49
+ </template>
50
+ <template #trigger>
51
+ <v-icon>mdi-plus</v-icon>
52
+ {{ $t('shared.forms.add') }}
53
+ </template>
54
+ <template #form="{ on, attrs }">
55
+ <course-glossary-form
56
+ v-model="selectedTerm"
57
+ :glossary="glossaryTerms"
58
+ :edit-mode="editMode"
59
+ v-bind="attrs"
60
+ v-on="on"
61
+ />
62
+ </template>
63
+ </Dialog>
64
+ <v-spacer></v-spacer>
65
+ <v-text-field
66
+ v-model="search"
67
+ class="ml-5 flex-grow-1"
68
+ append-icon="mdi-magnify"
69
+ :label="$t('shared.forms.search')"
70
+ single-line
71
+ hide-details
72
+ ></v-text-field>
73
+ </v-toolbar>
74
+ </template>
75
+
76
+ <template #item="{ item }">
77
+ <tr>
78
+ <td>{{ item.term }}</td>
79
+ <td>{{ item.definition }}</td>
80
+ <td>{{ item.alternate_forms }}</td>
81
+ <td>{{ item.related_term }}</td>
82
+
83
+ <td>
84
+ <v-btn
85
+ class="primary"
86
+ :disabled="
87
+ !$PermissionService.userHasAccessTo(
88
+ 'windward.global.course,windward.organization.course.contentBlock',
89
+ 'writable'
90
+ )
91
+ "
92
+ @click="editTerm(item)"
93
+ >
94
+ <v-icon small> mdi-pencil </v-icon>
95
+ <span class="sr-only">{{
96
+ $t('forms.edit')
97
+ }}</span>
98
+ </v-btn>
99
+ <v-btn
100
+ class="primary"
101
+ :disabled="
102
+ !$PermissionService.userHasAccessTo(
103
+ 'windward.global.course,windward.organization.course.contentBlock',
104
+ 'writable'
105
+ )
106
+ "
107
+ @click="onDelete(item)"
108
+ >
109
+ <v-icon small> mdi-delete </v-icon>
110
+ <span class="sr-only">{{
111
+ $t('shared.forms.delete')
112
+ }}</span>
113
+ </v-btn>
114
+ </td>
115
+ </tr>
116
+ </template>
117
+ </v-data-table>
118
+ </v-col>
119
+ </v-row>
120
+ </v-container>
121
+ </template>
122
+
123
+ <script>
124
+ import { mapGetters, mapMutations } from 'vuex'
125
+ import _ from 'lodash'
126
+ import Crypto from '~/helpers/Crypto'
127
+ import Course from '~/models/Course'
128
+
129
+ import CourseGlossaryForm from './CourseGlossaryForm'
130
+ export default {
131
+ name: 'CourseGlossary',
132
+ components: { CourseGlossaryForm },
133
+ layout: 'course',
134
+ middleware: ['auth'],
135
+ props: {},
136
+
137
+ data() {
138
+ return {
139
+ headers: [
140
+ {
141
+ text: this.$t('windward.core.pages.glossary.term'),
142
+ align: 'start',
143
+ sortable: false,
144
+ value: 'glossaryTerms.term',
145
+ },
146
+ {
147
+ text: this.$t('windward.core.pages.glossary.definition'),
148
+ align: 'start',
149
+ sortable: true,
150
+ value: 'glossaryTerms.definition',
151
+ },
152
+ {
153
+ text: this.$t(
154
+ 'windward.core.pages.glossary.alternate_forms'
155
+ ),
156
+ align: 'start',
157
+ sortable: true,
158
+ value: 'glossaryTerms.alternate_forms',
159
+ },
160
+ {
161
+ text: this.$t('windward.core.pages.glossary.related_term'),
162
+ align: 'start',
163
+ sortable: true,
164
+ value: 'glossaryTerms.related_term',
165
+ },
166
+ ],
167
+ dialog: false,
168
+ editMode: false,
169
+ glossaryTerms: [],
170
+ selectedTerm: {},
171
+ search: '',
172
+ tableKey: Crypto.id(),
173
+ defaultTerm: {
174
+ term: '',
175
+ definition: '',
176
+ alternate_forms: '',
177
+ related_term: '',
178
+ },
179
+ }
180
+ },
181
+
182
+ computed: {
183
+ ...mapGetters({
184
+ course: 'course/get',
185
+ }),
186
+ ...mapMutations({
187
+ saveCourse: 'course/set',
188
+ }),
189
+ },
190
+
191
+ beforeMount() {
192
+ if (this.course.metadata && _.isArray(this.course.metadata.glossary)) {
193
+ this.glossaryTerms = _.cloneDeep(this.course.metadata.glossary)
194
+ }
195
+ },
196
+ methods: {
197
+ async save() {
198
+ let currentGlossaryItemIndex = -1
199
+ this.glossaryTerms.filter((item, index) => {
200
+ if (item.term === this.selectedTerm.term) {
201
+ currentGlossaryItemIndex = index
202
+ return item
203
+ }
204
+ })
205
+ if (currentGlossaryItemIndex > -1) {
206
+ this.glossaryTerms[currentGlossaryItemIndex] = this.selectedTerm
207
+ } else {
208
+ this.glossaryTerms.push(this.selectedTerm)
209
+ }
210
+ const course = new Course(this.course)
211
+ if (!_.isSet(course.metadata)) {
212
+ course.metadata = {}
213
+ course.metadata.glossary = {}
214
+ }
215
+ if (!_.isSet(course.metadata.glossary)) {
216
+ course.metadata.glossary = this.glossaryTerms
217
+ }
218
+ const updatedCourse = await course.save()
219
+ this.$store.commit('course/set', updatedCourse)
220
+ this.$toast.success(this.$t('shared.forms.saved'))
221
+ //force update on datatable
222
+ this.tableKey = Crypto.id()
223
+ },
224
+ saveNew() {
225
+ this.save()
226
+ this.selectedTerm = _.cloneDeep(this.defaultTerm)
227
+ },
228
+ addTerm() {
229
+ this.editMode = false
230
+ this.selectedTerm = {}
231
+ this.selectedTerm = _.cloneDeep(this.defaultTerm)
232
+ },
233
+ editTerm(item) {
234
+ this.editMode = true
235
+ const selectedIndex = this.glossaryTerms.indexOf(item)
236
+ this.selectedTerm = _.cloneDeep(this.glossaryTerms[selectedIndex])
237
+ this.dialog = true
238
+ },
239
+
240
+ onDelete(term) {
241
+ const self = this
242
+ const confirmText = this.$t('shared.forms.confirm_delete_text')
243
+ this.$dialog.show(confirmText, {
244
+ icon: 'mdi-delete',
245
+ duration: null,
246
+ action: [
247
+ {
248
+ text: this.$t('shared.forms.cancel'),
249
+ onClick: (e, toastObject) => {
250
+ toastObject.goAway(0)
251
+ },
252
+ },
253
+ {
254
+ text: this.$t('shared.forms.confirm'),
255
+ // router navigation
256
+ onClick: (e, toastObject) => {
257
+ self.deleteTerm(term)
258
+ toastObject.goAway(0)
259
+ },
260
+ },
261
+ ],
262
+ })
263
+ },
264
+ async deleteTerm(item) {
265
+ const deleteIndex = this.glossaryTerms.indexOf(item)
266
+ this.glossaryTerms.splice(deleteIndex, 1)
267
+ const course = new Course(this.course)
268
+ if (!_.isSet(course.metadata)) {
269
+ course.metadata = {}
270
+ course.metadata.glossary = {}
271
+ }
272
+ course.metadata.glossary = this.glossaryTerms
273
+ const updatedCourse = await course.save()
274
+ this.$store.commit('course/set', updatedCourse)
275
+ this.$toast.success(this.$t('shared.response.deleted'))
276
+ },
277
+ close() {
278
+ this.dialog = false
279
+ },
280
+ },
281
+ }
282
+ </script>
283
+
284
+ <!--<style scoped></style>-->
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <v-form ref="form" v-model="formValid" class="pa-6">
3
+ <v-text-field
4
+ v-model="selectedTerm.term"
5
+ :counter="50"
6
+ :label="$t('windward.core.pages.glossary.term')"
7
+ required
8
+ :rules="validation.termRules"
9
+ ></v-text-field>
10
+ <br />
11
+ <v-textarea
12
+ v-model="selectedTerm.definition"
13
+ :counter="255"
14
+ :label="$t('windward.core.pages.glossary.definition')"
15
+ outlined
16
+ required
17
+ :rules="validation.definitionRules"
18
+ ></v-textarea>
19
+ <br />
20
+ <v-textarea
21
+ v-model="selectedTerm.alternate_forms"
22
+ :counter="50"
23
+ :label="$t('windward.core.pages.glossary.alternate_forms')"
24
+ outlined
25
+ ></v-textarea>
26
+ <br />
27
+ <v-select
28
+ v-model="selectedTerm.related_term"
29
+ :items="termList"
30
+ outlined
31
+ clearable
32
+ :label="$t('windward.core.pages.glossary.related_term')"
33
+ ></v-select>
34
+ </v-form>
35
+ </template>
36
+
37
+ <script>
38
+ import Form from '~/components/Form'
39
+ export default {
40
+ name: 'CourseGlossaryForm',
41
+ extends: Form,
42
+ props: {
43
+ value: { type: Object, required: true },
44
+ glossary: { type: Array, required: true },
45
+ editMode: { type: Boolean, required: false, default: false },
46
+ },
47
+ data() {
48
+ return {
49
+ selectedTerm: {},
50
+ relatedTerm: [],
51
+ validation: {
52
+ termRules: [
53
+ (v) => !!v || this.$t('shared.forms.errors.required'),
54
+ (v) =>
55
+ (v && v.length <= 50) ||
56
+ this.$t('forms.errors.text_lt', [50]),
57
+ (v) =>
58
+ (v && this.termIsUnique(v)) ||
59
+ this.$t('shared.forms.errors.field_unique'),
60
+ ],
61
+ definitionRules: [
62
+ (v) => !!v || this.$t('shared.forms.errors.required'),
63
+ (v) =>
64
+ (v && v.length <= 255) ||
65
+ this.$t('shared.forms.errors.text_lt', [255]),
66
+ ],
67
+ },
68
+ }
69
+ },
70
+ computed: {
71
+ termList() {
72
+ return this.glossary.flatMap((item) => {
73
+ if (this.selectedTerm.term !== item.term) return item.term
74
+ })
75
+ },
76
+ },
77
+ watch: {
78
+ value() {
79
+ // Refresh the question model when we open / close the dialog
80
+ this.selectedTerm = this.value
81
+ },
82
+ },
83
+ mounted() {
84
+ this.selectedTerm = this.value
85
+ },
86
+ methods: {
87
+ termIsUnique(term) {
88
+ const result = this.glossary.filter((item) => {
89
+ if (_.lowerCase(item.term) === _.lowerCase(term)) {
90
+ return item
91
+ }
92
+ })
93
+
94
+ if (result.length > 0 && !this.editMode) {
95
+ return false
96
+ } else {
97
+ return true
98
+ }
99
+ },
100
+ },
101
+ }
102
+ </script>
103
+
104
+ <!--
105
+ <style scoped></style>
106
+ -->
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <div
3
+ class="glossary-word"
4
+ v-click-outside="onClickOutside"
5
+ @click="show = !show"
6
+ >
7
+ <v-tooltip
8
+ top
9
+ v-model="show"
10
+ :open-on-hover="false"
11
+ color="primary"
12
+ max-width="200px"
13
+ >
14
+ <template #activator="{ on }">
15
+ <span v-on="on">
16
+ <slot name="term"></slot>
17
+ </span>
18
+ </template>
19
+ <div>
20
+ <div v-if="this.$slots['definition']">
21
+ <h4 class="text-capitalize">
22
+ {{
23
+ $t(
24
+ 'windward.core.components.utils.tiny_mce_wrapper.definition'
25
+ )
26
+ }}
27
+ :
28
+ </h4>
29
+ <p>
30
+ <slot name="definition"></slot>
31
+ </p>
32
+ </div>
33
+ <div v-if="this.$slots['alternate_forms']">
34
+ <h4 class="text-capitalize">
35
+ {{
36
+ $t(
37
+ 'windward.core.components.utils.tiny_mce_wrapper.alternate_forms'
38
+ )
39
+ }}
40
+ :
41
+ </h4>
42
+ <p><slot name="alternate_forms"></slot></p>
43
+ </div>
44
+
45
+ <div v-if="this.$slots['related_terms']">
46
+ <h4 class="text-capitalize">
47
+ {{
48
+ $t(
49
+ 'windward.core.components.utils.tiny_mce_wrapper.related_terms'
50
+ )
51
+ }}
52
+ :
53
+ </h4>
54
+ <p><slot name="related_terms"></slot></p>
55
+ </div>
56
+ </div>
57
+ </v-tooltip>
58
+ </div>
59
+ </template>
60
+
61
+ <script>
62
+ export default {
63
+ name: 'GlossaryToolTip',
64
+ data() {
65
+ return {
66
+ show: false,
67
+ }
68
+ },
69
+ methods: {
70
+ onClickOutside() {
71
+ this.show = false
72
+ },
73
+ },
74
+ }
75
+ </script>
76
+
77
+ <style scoped>
78
+ .glossary-word {
79
+ display: inline-block;
80
+ border-radius: 12px;
81
+ cursor: pointer;
82
+ padding: 0px 7px;
83
+ background-color: var(--v-warning-lighten1);
84
+ font-weight: bold;
85
+ color: var(--v-dark-text-base);
86
+ }
87
+ </style>
@@ -0,0 +1,136 @@
1
+ export default {
2
+ plugins: [
3
+ {
4
+ name: 'math',
5
+ tag: 'plugin-core-math-expression-editor',
6
+ buttons: {
7
+ groups: [
8
+ {
9
+ name: 'shared.math.trigonometry',
10
+ buttons: [
11
+ {
12
+ cmd: false,
13
+ text: '\\sec',
14
+ },
15
+ {
16
+ cmd: false,
17
+ text: '\\sec^{-1}',
18
+ },
19
+ {
20
+ cmd: false,
21
+ text: '\\csc',
22
+ },
23
+ {
24
+ cmd: false,
25
+ text: '\\csc^{-1}',
26
+ },
27
+ {
28
+ cmd: false,
29
+ text: '\\cot',
30
+ },
31
+ {
32
+ cmd: false,
33
+ text: '\\cot^{-1}',
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ name: 'shared.math.statistic',
39
+ buttons: [
40
+ {
41
+ cmd: false,
42
+ text: '\\mu',
43
+ },
44
+ {
45
+ cmd: false,
46
+ text: '\\overline{x}',
47
+ },
48
+ {
49
+ cmd: false,
50
+ text: '\\overline{y}',
51
+ },
52
+ {
53
+ cmd: false,
54
+ text: 'x^i',
55
+ },
56
+ {
57
+ cmd: false,
58
+ text: 'x_i',
59
+ },
60
+ {
61
+ cmd: false,
62
+ text: 'x!',
63
+ },
64
+ {
65
+ cmd: false,
66
+ text: '\\Sigma',
67
+ },
68
+ ],
69
+ },
70
+ {
71
+ name: 'shared.math.matrix',
72
+ buttons: [
73
+ {
74
+ cmd: false,
75
+ text: '\\begin{bmatrix} a & b \\\\ c & d \\end{bmatrix}',
76
+ },
77
+ {
78
+ cmd: false,
79
+ text: '\\begin{bmatrix} a & b & c \\\\ d & e & f \\\\ g & h & i \\end{bmatrix}',
80
+ },
81
+ ],
82
+ },
83
+ {
84
+ name: 'shared.math.group',
85
+ buttons: [
86
+ {
87
+ cmd: true,
88
+ latex: '(\\placeholder{})',
89
+ text: '(\\cdot)',
90
+ },
91
+ {
92
+ cmd: true,
93
+ latex: '[\\placeholder{}]',
94
+ text: '[\\cdot]',
95
+ },
96
+ {
97
+ cmd: true,
98
+ latex: '|\\placeholder{}|',
99
+ text: '|\\cdot|',
100
+ },
101
+ {
102
+ cmd: false,
103
+ text: '(x,y)',
104
+ },
105
+ {
106
+ cmd: false,
107
+ text: '[x,y]',
108
+ },
109
+ {
110
+ cmd: false,
111
+ text: '(x,y]',
112
+ },
113
+ {
114
+ cmd: false,
115
+ text: '[x,y)',
116
+ },
117
+ ],
118
+ },
119
+ {
120
+ name: 'shared.math.equation_system',
121
+ buttons: [
122
+ {
123
+ cmd: false,
124
+ text: '\\begin{cases} x + y \\\\ x + y \\end{cases}',
125
+ },
126
+ {
127
+ cmd: false,
128
+ text: '\\begin{cases} x + y \\\\ x – y \\end{cases}',
129
+ },
130
+ ],
131
+ },
132
+ ],
133
+ },
134
+ },
135
+ ],
136
+ }