entcore 4.5.0 → 4.5.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,6 +1,6 @@
1
1
  {
2
2
  "name": "entcore",
3
- "version": "4.5.0",
3
+ "version": "4.5.1",
4
4
  "description": "",
5
5
  "main": "gulpfile.js",
6
6
  "types": "./types/src/ts/entcore.d.ts",
@@ -35,6 +35,7 @@
35
35
  "webpack-stream": "^3.2.0"
36
36
  },
37
37
  "devDependencies": {
38
+ "@types/angular": "1.7.4",
38
39
  "@types/ua-parser-js": "^0.7.35",
39
40
  "@types/core-js": "0.9.46",
40
41
  "@types/jasmine": "2.8.8",
@@ -31,13 +31,24 @@
31
31
  <div class="row reduce-block-four search-image">
32
32
  <input type="search" ng-model="display.search" i18n-placeholder="search" ng-change="updateSearch()" class="six cell" />
33
33
  <div class="cell six">
34
- <button type="button" class="right-magnet" ng-disabled="display.loading || selectedDocuments().length === 0" ng-click="selectDocuments()">
34
+ <!-- default nav -->
35
+ <button ng-if="display.listFrom" type="button" class="right-magnet" ng-disabled="display.loading || selectedDocuments().length === 0" ng-click="selectDocuments()">
35
36
  <i18n>library.browse.add</i18n>
36
37
  </button>
38
+
39
+ <!-- virtual document add button -->
40
+ <virtual-media-library-button
41
+ ng-if="!display.listFrom"
42
+ documents="documents"
43
+ folders="folders"
44
+ selected-virtual-folder="selectedVirtualFolder"
45
+ on-click="selectDocuments()">
46
+ </virtual-media-library-button>
37
47
  </div>
38
48
  </div>
39
49
 
40
50
  <div class="row browse">
51
+ <!-- nav folder -->
41
52
  <nav class="four cell vertical zero-mobile">
42
53
  <ul class="height-minus300">
43
54
  <li workflow="workspace.create">
@@ -75,22 +86,38 @@
75
86
  <i18n>workspace.publicDocuments</i18n>
76
87
  </a>
77
88
  </li>
89
+
90
+ <!-- virtual folder -->
91
+ <virtual-media-library
92
+ selected-virtual-folder="selectedVirtualFolder"
93
+ on-click="resetRegularDisplay()">
94
+ </virtual-media-library>
78
95
  </ul>
79
96
  </nav>
80
97
 
81
- <!--VIEW MODE-->
82
- <div class="cell right-magnet">
83
- <div class="choice-view">
84
- <i class="show-icons" ng-class="{ selected: isViewMode('icons') }" ng-click="changeViewMode('icons')"></i>
85
- <i class="show-list" ng-class="{ selected: isViewMode('list') }" ng-click="changeViewMode('list')"></i>
86
- </div>
98
+ <!--VIEW MODE-->
99
+ <div ng-if="display.listFrom" class="cell right-magnet">
100
+ <div class="choice-view">
101
+ <i class="show-icons" ng-class="{ selected: isViewMode('icons') }" ng-click="changeViewMode('icons')"></i>
102
+ <i class="show-list" ng-class="{ selected: isViewMode('list') }" ng-click="changeViewMode('list')"></i>
87
103
  </div>
104
+ </div>
88
105
 
89
- <div class="cell eight height-five twelve-mobile browse-list height-minus300 overflowx-hd" on-bottom-scroll="documentList.increment()">
106
+ <!-- documents view by icons or list -->
107
+ <div ng-if="display.listFrom" class="cell eight height-five twelve-mobile browse-list height-minus300 overflowx-hd" on-bottom-scroll="documentList.increment()">
90
108
  <div class="reduce-block-eight" ng-if="!documents.length && !folders.length" style="text-align: center; margin-top: 40px">
91
109
  <i18n>library.browse.notfound</i18n>
92
110
  </div>
93
111
  <container ng-hide="!documents.length && !folders.length" template="documents-view" guard-ignore-template></container>
94
112
  </div>
113
+
114
+ <!-- virtual folder document view -->
115
+ <virtual-media-library-document-view class="cell eight height-five twelve-mobile browse-list height-minus300 overflowx-hd"
116
+ ng-if="!display.listFrom"
117
+ search="display.search"
118
+ selected-virtual-folder="selectedVirtualFolder">
119
+ </virtual-media-library-document-view>
120
+
121
+
95
122
  </div>
96
123
  <div class="row"></div>
@@ -1 +1 @@
1
- <recorder ng-model="record" on-upload="insertRecord()" protected></recorder>
1
+ <recorder ng-model="record" on-upload="insertRecord" protected></recorder>
@@ -0,0 +1,56 @@
1
+ <div class="icons-view" style="overflow: auto" ng-if="vm.selectedVirtualFolder">
2
+
3
+ <!-- empty state message -->
4
+ <div class="reduce-block-eight" ng-if="!vm.folders.length && !vm.documents.length" style="text-align: center; margin-top: 40px">
5
+ <i18n>library.browse.notfound</i18n>
6
+ </div>
7
+
8
+ <!-- folder part area -->
9
+ <div class="element reduce-block-six" ng-repeat="folder in vm.folders | orderBy: orderFieldFolder">
10
+ <explorer ng-model="folder.selected" on-open="vm.mediaServiceLibrary.openedTree.openFolder(folder)">
11
+ <div class="img container">
12
+ <i class="folder-large"></i>
13
+ </div>
14
+ <legend>
15
+ <a class="medium-text">[[folder.name]]</a>
16
+ </legend>
17
+ </explorer>
18
+ </div>
19
+
20
+ <!-- documents part area -->
21
+ <div class="element reduce-block-six" ng-repeat="document in vm.documents">
22
+ <explorer ng-model="document.selected"
23
+ ng-click="vm.updateSelection(document)" on-open="selectDocument(document)"
24
+ ng-switch="vm.getRole(document)">
25
+
26
+ <!-- img content -->
27
+ <div class="img container" ng-switch-when="img">
28
+ <div class="clip">
29
+ <img image-lazy-load="vm.getThumbUrl(document)"/>
30
+ <div class="absolute" ng-if="display.loading && display.loading.indexOf(document) !== -1">
31
+ <img skin-src="/img/illustrations/loading.gif" />
32
+ </div>
33
+ </div>
34
+ </div>
35
+
36
+ <!-- container video -->
37
+ <div class="img container video" ng-switch-when="video"
38
+ ng-style="{'background-image': videoThumbUrl(document)}">
39
+ <svg class="icon-video" width="48" height="48">
40
+ <use xlink:href="/workspace/public/img/illustrations.svg#icon-play"></use>
41
+ </svg>
42
+ </div>
43
+
44
+ <!-- default file -->
45
+ <div class="img container" ng-switch-default>
46
+ <i class="[[vm.getRole(document)]]-large"></i>
47
+ </div>
48
+
49
+ <!-- legend content -->
50
+ <legend>
51
+ <a class="medium-text">[[document.name]]</a>
52
+ <a><strong class="small-text">[[document.ownerName]]</strong></a>
53
+ </legend>
54
+ </explorer>
55
+ </div>
56
+ </div>
@@ -0,0 +1,7 @@
1
+ <nav class="vertical mobile-navigation" ng-if="vm.folderServiceTree.trees.length > 0">
2
+ <ul style="border-left: none;">
3
+ <li data-ng-repeat="folder in vm.folderServiceTree.trees">
4
+ <folder-tree-inner folder="folder" tree-props="vm.folderServiceTree"></folder-tree-inner>
5
+ </li>
6
+ </ul>
7
+ </nav>
@@ -0,0 +1,209 @@
1
+ ## Virtual Folder
2
+
3
+ Virtual Folder is an extension of Media-Library component in order to create your own virtual documents
4
+ if you wish to make it exportable to all apps.
5
+
6
+ Each Virtual Folder must be implemented by an App using Behaviours.
7
+
8
+ ### 1. Requirement
9
+
10
+ Must add public configuration to Workspace App :
11
+ <pre>
12
+ ## Workspace configuration
13
+ {
14
+ ...
15
+ "config": {
16
+ ...
17
+ "publicConf": {
18
+ "folder-service": ["appName", "appName2", ...]
19
+ }
20
+ }
21
+ }
22
+ </pre>
23
+
24
+ Note : `appName` (`or appName2`) must be written correctly in order to load their behaviours (e.g `Behaviours.load(appName)`)
25
+
26
+
27
+ ## Implementation usage as an App
28
+
29
+ In your behaviours, you must add a field named `mediaLibraryService` (could be an object/class)
30
+
31
+ It should be accessible via `Behaviours.applicationsBehaviours[appName].mediaLibraryService`
32
+
33
+ `mediaLibraryService` must implement `VirtualMediaLibraryScope` as an object or class
34
+
35
+
36
+ ### 1. Interface
37
+
38
+ This is the interface that each app must implement :
39
+ ```
40
+ interface IVirtualMediaLibraryScope{
41
+ folders: Array<Document>;
42
+
43
+ documents: Array<Document>;
44
+
45
+ openedTree: FolderTreeProps;
46
+
47
+ enableInitFolderTree(): boolean;
48
+
49
+ initFolderTree(): Promise<void>;
50
+
51
+ openFolder(folder: Document): Promise<void>;
52
+
53
+ onSelectVirtualDocumentsBefore(documents: Array<any>): Promise<Array<Document>>;
54
+
55
+ clearCopiedDocumentsAfterSelect(documents: Array<Document>): Promise<void>;
56
+ }
57
+ ```
58
+ ### 2. Interface Description
59
+
60
+ Each app must implement these scopes in their own behaviours as `mediaLibraryservice` (using `object` or `class` typescript)
61
+
62
+
63
+ | Scope | Type | Description - Ideal implementation
64
+ | ------------------------- | ----- | -----------------------------------------------------------------------------------
65
+ | `folders` | ` Array<Document>` | An Array of documents that must contain folder type
66
+ | `documents` | `Array<Document>` | An Array of documents that must contain simply documents type
67
+ | `openedTree` | `FolderTreeProps` | The current opened tree loaded from behaviours (will store your current behaviours media library service)
68
+ | `enableInitFolderTree` | `boolean` | Method that will allow your virtual folder to be displayed as a `tree` service in media-library
69
+ | `initFolderTree` | `Promise<void>` | Initialize your folder `tree` service (using `folder-tree` directive). this method **requires** `folders` and `documents` members to be populated
70
+ | `openFolder` | `Promise<void>` | open folder children from your `tree` service. this method **requires** `folders` and `documents` members to be populated
71
+ | `onSelectVirtualDocumentsBefore` | `Promise<Array<Document>>` | This method will execute the behaviour's action before its executes the media library scope `selectDocuments()`.
72
+ | `clearCopiedDocumentsAfterSelect` | `Promise<void>` | Allows clear copied documents (if you decided in your method `onSelectVirtualDocumentsBefore()`)
73
+
74
+ ### 3. Interface Implementation example
75
+
76
+ ```
77
+ Behaviours.register(appName, {
78
+ right {
79
+ ...
80
+ }
81
+ mediaLibraryService: new MediaLibraryService(), // mediaLibraryService
82
+ ...
83
+ })
84
+ ```
85
+
86
+ Creation object :
87
+ ```
88
+ export const mediaLibraryService: IVirtualMediaLibraryScope = {
89
+ // implements all methods
90
+ };
91
+ ```
92
+ or class :
93
+ ```
94
+ export class MediaLibraryService implements VirtualMediaLibraryScope {
95
+ // implements all methods
96
+ };
97
+ ```
98
+
99
+ ### 4. Example implementation for each method
100
+
101
+ Say we are implementing `MediaLibraryService` from a specific module that needs to display its own tree to the media library
102
+
103
+ ```typescript
104
+ export class MediaLibraryService implements IVirtualMediaLibraryScope {
105
+ openedTree: any;
106
+ folders: Array<Document>;
107
+ documents: Array<Document>;
108
+
109
+ constructor() {
110
+ this.folders = [];
111
+ this.documents = [];
112
+ }
113
+
114
+ enableInitFolderTree(): boolean {
115
+ return true // or anything, you make your own condition to determine whether it should be displayed in your virtual folder tree
116
+ }
117
+
118
+ async initFolderTree(): Promise<void> {
119
+ // apicall() or method() from your own that will fetch data and use for assigning your folders and this documents
120
+ // (e.g):
121
+ let documents: any = apiCall();
122
+
123
+ // populate folder content to media library behaviours
124
+ this.folders = documents.filter(filterFoldersOnly());
125
+
126
+ // populate file content to media library behaviours
127
+ this.documents = documents.filter(filterDocumentsOnly()); // See below the example of field Document object must have
128
+ }
129
+
130
+ async openFolder(folder: models.Element): Promise<void> {
131
+ // apicall() or method() from your own that will fetch data and use for assigning your folders and this documents
132
+ // you can add extra business logic, it will depend what you seek for
133
+ // (e.g):
134
+ let documents: any = anotherCall();
135
+
136
+ // populate folder content to media library behaviours
137
+ this.folders = documents.filter(filterFoldersOnly());
138
+
139
+ // populate file content to media library behaviours
140
+ this.documents = documents.filter(filterDocumentsOnly()); // See below the example of field Document object must have
141
+ }
142
+
143
+ async onSelectVirtualDocumentsBefore(documents: Array<any>): Promise<Array<Document>> {
144
+ // apicall() or method() from your own that will do any action you like
145
+ // IMPORTANT this must return {Promise<Array<Document>>} containing a "real" document since this will be used for media library ng model
146
+
147
+ let resDocuments = await anotherCall(documents); // could be calling your own API/method to duplicate or choose different documents
148
+ return resDocuments;
149
+
150
+ }
151
+
152
+ async clearCopiedDocumentsAfterSelect(documents: Array<Document>): Promise<void> {
153
+ if (documents && documents.length)
154
+ service.deleteAll(documents); // SUGGESTED method that will clear any documents
155
+ // note: service.deleteAll comes from workspaceService
156
+ }
157
+
158
+ }
159
+ ```
160
+
161
+ As for the `Document` model, these fields should be available :
162
+ ```
163
+ {
164
+ name: {string}
165
+ comments: {string},
166
+ metadata: {
167
+ 'content-type': {string},
168
+ role: {string},
169
+ extension: {string},
170
+ filename: {string},
171
+ size: {number}
172
+ }, // metadata as the workspace object
173
+ owner: {string},
174
+ ownerName: {string}
175
+ }
176
+ ```
177
+ Example fictive data of a document
178
+ ```
179
+ {
180
+ "_id": {string} (e.g "id"),
181
+ "name": {string} (e.g "name"),
182
+ "title": {string} (e.g "title"),
183
+ "created": {string} (e.g "2022-06-02T12:06:00.000Z"),
184
+ "children": {Array<this} file/folder content (recommanded to avoid TypeError)
185
+ "documents": {Array<this>} file content
186
+ "folders": {Array<this>} folder content // not mandatory if you decide to lazy load your current folder
187
+ "eParent": {string},
188
+ "eType": {string}, "file" | "folder"
189
+ "metadata":{
190
+ "name": {string} (e.g "insert title"),
191
+ "filename": {string}, (e.g "insert title.png"),
192
+ "content-type": {string} (e.g "image/png"),
193
+ "charset": {string} (e.g "UTF-8"),
194
+ "size": {number} (e.g 77287),
195
+ "extension": {string} (e.g "png"),
196
+ "role": {string}, (e.g "img")
197
+ },
198
+ "version": {number} (e.g 50),
199
+ "link": {string} (e.g "/workspace/document/id"),
200
+ "icon":" {string} (e.g "/workspace/document/id"),
201
+ "owner":{
202
+ "userId": {string} (e.g "user id"),
203
+ "displayName": {string} (e.g "display name")
204
+ },
205
+ "shared":[]
206
+ }
207
+ ```
208
+
209
+
@@ -65,3 +65,4 @@ export * from "./libraryPrompt";
65
65
  export * from "./dragndrop";
66
66
  export * from "./structureTree";
67
67
  export * from "./toast";
68
+ export * from "./virtual-folder";
@@ -0,0 +1,4 @@
1
+ export * from "./virtual-media-library-document-view.directive";
2
+ export * from "./virtual-media-library.directive";
3
+ export * from "./virtual-media-library-button.directive";
4
+ export * from "./virtual-media-library.model";
@@ -0,0 +1,2 @@
1
+ import { Directive } from "../../ng-start";
2
+ export declare const virtualMediaLibraryButton: Directive;
@@ -0,0 +1,2 @@
1
+ import { Directive } from "../../ng-start";
2
+ export declare const virtualMediaLibraryDocumentView: Directive;
@@ -0,0 +1,2 @@
1
+ import { Directive } from "../../ng-start";
2
+ export declare const virtualMediaLibrary: Directive;
@@ -25,4 +25,5 @@ export * from "./tracking";
25
25
  export { Embedder } from "./embedder";
26
26
  export { DatepickerDelegate } from "./ng-app";
27
27
  export { FolderTreeProps } from "./directives/folderTree";
28
+ export { IVirtualMediaLibraryScope } from "./directives/virtual-folder";
28
29
  export { FolderPickerProps, FolderPickerSource, FolderPickerSourceBlob, FolderPickerSourceFile } from "./directives/folderPicker";