ngx-edu-sharing-ui 0.7.0
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/.browserslistrc +16 -0
- package/.eslintrc.json +44 -0
- package/README.md +40 -0
- package/assets/scss/mixins.scss +95 -0
- package/assets/scss/variables.scss +33 -0
- package/karma.conf.js +42 -0
- package/ng-package.json +10 -0
- package/package.json +19 -0
- package/src/lib/actionbar/actionbar.component.html +59 -0
- package/src/lib/actionbar/actionbar.component.scss +123 -0
- package/src/lib/actionbar/actionbar.component.ts +174 -0
- package/src/lib/common/edu-sharing-ui-common.module.ts +80 -0
- package/src/lib/directives/border-box-observer.directive.ts +75 -0
- package/src/lib/directives/check-text-overflow.directive.ts +61 -0
- package/src/lib/directives/drag-nodes/drag-nodes.ts +32 -0
- package/src/lib/directives/drag-nodes/nodes-drag-source.directive.ts +79 -0
- package/src/lib/directives/drag-nodes/nodes-drag.directive.ts +43 -0
- package/src/lib/directives/drag-nodes/nodes-drop-target.directive.ts +116 -0
- package/src/lib/directives/focus-state.directive.ts +34 -0
- package/src/lib/directives/icon.directive.ts +142 -0
- package/src/lib/directives/nodes-drop-target-legacy.directive.ts +155 -0
- package/src/lib/dropdown/dropdown.component.html +32 -0
- package/src/lib/dropdown/dropdown.component.scss +67 -0
- package/src/lib/dropdown/dropdown.component.ts +71 -0
- package/src/lib/edu-sharing-ui-configuration.ts +47 -0
- package/src/lib/edu-sharing-ui.module.ts +49 -0
- package/src/lib/list-items/available-widgets.ts +30 -0
- package/src/lib/list-items/format-duration.pipe.ts +17 -0
- package/src/lib/list-items/list-base/list-base.component.html +52 -0
- package/src/lib/list-items/list-base/list-base.component.ts +44 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.html +48 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.scss +8 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.ts +24 -0
- package/src/lib/list-items/list-counts/list-counts.component.html +1 -0
- package/src/lib/list-items/list-counts/list-counts.component.scss +3 -0
- package/src/lib/list-items/list-counts/list-counts.component.ts +59 -0
- package/src/lib/list-items/list-items.module.ts +33 -0
- package/src/lib/list-items/list-node-license/list-node-license.component.html +8 -0
- package/src/lib/list-items/list-node-license/list-node-license.component.ts +47 -0
- package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.html +11 -0
- package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.ts +60 -0
- package/src/lib/list-items/list-node-workflow/list-node-workflow.component.html +3 -0
- package/src/lib/list-items/list-node-workflow/list-node-workflow.component.ts +21 -0
- package/src/lib/list-items/list-text/list-text.component.html +176 -0
- package/src/lib/list-items/list-text/list-text.component.scss +3 -0
- package/src/lib/list-items/list-text/list-text.component.ts +107 -0
- package/src/lib/list-items/list-widget.ts +52 -0
- package/src/lib/list-items/node-row/node-row.component.html +31 -0
- package/src/lib/list-items/node-row/node-row.component.scss +50 -0
- package/src/lib/list-items/node-row/node-row.component.ts +16 -0
- package/src/lib/list-items/node-source.pipe.ts +48 -0
- package/src/lib/node-entries/combined-data-source.ts +51 -0
- package/src/lib/node-entries/custom-templates-data-source.ts +6 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.html +6 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.scss +35 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.ts +15 -0
- package/src/lib/node-entries/entries-model.ts +120 -0
- package/src/lib/node-entries/items-cap.ts +54 -0
- package/src/lib/node-entries/list-item-label.pipe.ts +28 -0
- package/src/lib/node-entries/mixins.scss +23 -0
- package/src/lib/node-entries/node-cache.spec.ts +199 -0
- package/src/lib/node-entries/node-cache.ts +81 -0
- package/src/lib/node-entries/node-data-source-remote.ts +33 -0
- package/src/lib/node-entries/node-data-source.ts +148 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.html +167 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.scss +28 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.ts +132 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.main.scss +261 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.html +205 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.scss +181 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.ts +361 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.html +100 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.scss +46 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.ts +40 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.html +23 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.scss +58 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.ts +16 -0
- package/src/lib/node-entries/node-entries-global.service.ts +79 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.html +25 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.scss +32 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.ts +31 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.html +270 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.scss +169 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.ts +333 -0
- package/src/lib/node-entries/node-entries-templates.service.ts +31 -0
- package/src/lib/node-entries/node-entries-wrapper.component.ts +363 -0
- package/src/lib/node-entries/node-entries.component.html +33 -0
- package/src/lib/node-entries/node-entries.component.scss +13 -0
- package/src/lib/node-entries/node-entries.component.ts +151 -0
- package/src/lib/node-entries/node-entries.module.ts +93 -0
- package/src/lib/node-entries/node-rating/node-rating.component.html +53 -0
- package/src/lib/node-entries/node-rating/node-rating.component.scss +31 -0
- package/src/lib/node-entries/node-rating/node-rating.component.ts +105 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.html +39 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.scss +44 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.ts +43 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.html +31 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.scss +5 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.ts +36 -0
- package/src/lib/node-entries/option-button/option-button.component.ts +42 -0
- package/src/lib/node-entries/preview-image/preview-image.component.html +19 -0
- package/src/lib/node-entries/preview-image/preview-image.component.scss +31 -0
- package/src/lib/node-entries/preview-image/preview-image.component.ts +47 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.html +27 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.scss +9 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.ts +26 -0
- package/src/lib/node-url/node-url.component.html +66 -0
- package/src/lib/node-url/node-url.component.scss +32 -0
- package/src/lib/node-url/node-url.component.ts +136 -0
- package/src/lib/pipes/file-size.pipe.ts +24 -0
- package/src/lib/pipes/format-date.pipe.ts +39 -0
- package/src/lib/pipes/node-icon.pipe.ts +11 -0
- package/src/lib/pipes/node-image-size.pipe.ts +18 -0
- package/src/lib/pipes/node-image.pipe.ts +71 -0
- package/src/lib/pipes/node-person-name.pipe.ts +41 -0
- package/src/lib/pipes/node-title.pipe.ts +12 -0
- package/src/lib/pipes/option-tooltip.pipe.ts +32 -0
- package/src/lib/pipes/replace-chars.pipe.ts +21 -0
- package/src/lib/pipes/vcard-name.pipe.ts +11 -0
- package/src/lib/services/abstract/app.service.ts +4 -0
- package/src/lib/services/abstract/keyboard-shortcuts.service.ts +10 -0
- package/src/lib/services/abstract/options-helper.service.ts +29 -0
- package/src/lib/services/abstract/toast.service.ts +5 -0
- package/src/lib/services/accessibility.service.ts +101 -0
- package/src/lib/services/local-events.service.ts +29 -0
- package/src/lib/services/node-entries.service.ts +172 -0
- package/src/lib/services/node-helper.service.ts +239 -0
- package/src/lib/services/nodes-drag-drop.service.ts +165 -0
- package/src/lib/services/options-helper-data.service.ts +186 -0
- package/src/lib/services/repo-url.service.ts +46 -0
- package/src/lib/services/temporary-storage.service.ts +58 -0
- package/src/lib/services/ui.service.ts +182 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.html +22 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.scss +47 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.ts +42 -0
- package/src/lib/spinner/spinner.component.html +14 -0
- package/src/lib/spinner/spinner.component.scss +141 -0
- package/src/lib/spinner/spinner.component.ts +12 -0
- package/src/lib/translations/README.md +44 -0
- package/src/lib/translations/fallback-translation-handler.ts +7 -0
- package/src/lib/translations/languages.ts +6 -0
- package/src/lib/translations/translation-loader.spec.ts +352 -0
- package/src/lib/translations/translation-loader.ts +189 -0
- package/src/lib/translations/translation-source.ts +9 -0
- package/src/lib/translations/translations.module.ts +49 -0
- package/src/lib/translations/translations.service.spec.ts +152 -0
- package/src/lib/translations/translations.service.ts +188 -0
- package/src/lib/types/accessibillity.ts +15 -0
- package/src/lib/types/api-models.ts +4 -0
- package/src/lib/types/drag-drop.ts +22 -0
- package/src/lib/types/keyboard-shortcuts.ts +29 -0
- package/src/lib/types/list-item.ts +67 -0
- package/src/lib/types/option-item.ts +247 -0
- package/src/lib/types/workflow.ts +35 -0
- package/src/lib/util/DateHelper.spec.ts +112 -0
- package/src/lib/util/DateHelper.ts +197 -0
- package/src/lib/util/VCard.ts +277 -0
- package/src/lib/util/color-helper.ts +125 -0
- package/src/lib/util/duration-helper.spec.ts +35 -0
- package/src/lib/util/duration-helper.ts +98 -0
- package/src/lib/util/functions.ts +15 -0
- package/src/lib/util/helper.ts +60 -0
- package/src/lib/util/isNumeric.ts +13 -0
- package/src/lib/util/rest-helper.ts +28 -0
- package/src/lib/util/ui-animation.ts +154 -0
- package/src/lib/util/ui-constants.ts +20 -0
- package/src/module.ts +76 -0
- package/src/test.ts +28 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +17 -0
package/.browserslistrc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
|
2
|
+
# For additional information regarding the format and rule options, please see:
|
|
3
|
+
# https://github.com/browserslist/browserslist#queries
|
|
4
|
+
|
|
5
|
+
# For the full list of supported browsers by the Angular framework, please see:
|
|
6
|
+
# https://angular.io/guide/browser-support
|
|
7
|
+
|
|
8
|
+
# You can see what browsers were selected by your queries by running:
|
|
9
|
+
# npx browserslist
|
|
10
|
+
|
|
11
|
+
last 1 Chrome version
|
|
12
|
+
last 1 Firefox version
|
|
13
|
+
last 2 Edge major versions
|
|
14
|
+
last 2 Safari major versions
|
|
15
|
+
last 2 iOS major versions
|
|
16
|
+
Firefox ESR
|
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../.eslintrc.json",
|
|
3
|
+
"ignorePatterns": [
|
|
4
|
+
"!**/*"
|
|
5
|
+
],
|
|
6
|
+
"overrides": [
|
|
7
|
+
{
|
|
8
|
+
"files": [
|
|
9
|
+
"*.ts"
|
|
10
|
+
],
|
|
11
|
+
"parserOptions": {
|
|
12
|
+
"project": [
|
|
13
|
+
"projects/edu-sharing-ui/tsconfig.lib.json",
|
|
14
|
+
"projects/edu-sharing-ui/tsconfig.spec.json"
|
|
15
|
+
],
|
|
16
|
+
"createDefaultProgram": true
|
|
17
|
+
},
|
|
18
|
+
"rules": {
|
|
19
|
+
"@angular-eslint/directive-selector": [
|
|
20
|
+
"error",
|
|
21
|
+
{
|
|
22
|
+
"type": "attribute",
|
|
23
|
+
"prefix": "lib",
|
|
24
|
+
"style": "camelCase"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"@angular-eslint/component-selector": [
|
|
28
|
+
"error",
|
|
29
|
+
{
|
|
30
|
+
"type": "element",
|
|
31
|
+
"prefix": "lib",
|
|
32
|
+
"style": "kebab-case"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"files": [
|
|
39
|
+
"*.html"
|
|
40
|
+
],
|
|
41
|
+
"rules": {}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# EduSharingUi
|
|
2
|
+
|
|
3
|
+
This library bundles base ui components from edu-sharing.
|
|
4
|
+
|
|
5
|
+
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.3.0.
|
|
6
|
+
|
|
7
|
+
## Required Init tasks
|
|
8
|
+
|
|
9
|
+
Your project must provide a Toast service (for message viewing). You may use a mat-snackbar for displaying.
|
|
10
|
+
|
|
11
|
+
in your app.module.ts:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Toast as ToastAbstract } from 'ngx-edu-sharing-ui';
|
|
15
|
+
providers: [
|
|
16
|
+
{ provide: ToastAbstract, useClass: Toast },
|
|
17
|
+
// ...
|
|
18
|
+
];
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Make sure that your `Toast`-Service extends the abstract Toast service.
|
|
22
|
+
|
|
23
|
+
You might also provide other services for extended functionality, including
|
|
24
|
+
`Toast`, `OptionsHelperService`, `KeyboardShortcutsService`, `AppService`.
|
|
25
|
+
|
|
26
|
+
Check out our sample angular application for a full example
|
|
27
|
+
Check the `app.module.ts` for registration.
|
|
28
|
+
|
|
29
|
+
In one of your primary components (i.e. router) you need to initalize the material theme and translations:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
async ngOnInit() {
|
|
33
|
+
this.materialCssVarsService.setPrimaryColor('#2e9e9b');
|
|
34
|
+
this.materialCssVarsService.setAccentColor('#2e9e9b');
|
|
35
|
+
await this.translationsService.initialize().toPromise()
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
In your scss, make sure to include the global variables via
|
|
40
|
+
`@import "node-modules/ngx-edu-sharing-ui/assets/scss/variables";`
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
@mixin clickable() {
|
|
2
|
+
cursor: pointer;
|
|
3
|
+
-webkit-user-select: none;
|
|
4
|
+
-moz-user-select: none;
|
|
5
|
+
-ms-user-select: none;
|
|
6
|
+
user-select: none;
|
|
7
|
+
-webkit-tap-highlight-color: transparent;
|
|
8
|
+
}
|
|
9
|
+
@mixin limitLineCount($count, $lineHeight: 1) {
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
text-overflow: ellipsis;
|
|
12
|
+
display: -webkit-box;
|
|
13
|
+
line-height: $lineHeight + em;
|
|
14
|
+
max-height: $count * $lineHeight + em;
|
|
15
|
+
-webkit-line-clamp: $count; /* number of lines to show */
|
|
16
|
+
-webkit-box-orient: vertical;
|
|
17
|
+
/* autoprefixer: off */
|
|
18
|
+
}
|
|
19
|
+
@mixin materialShadow($important: false) {
|
|
20
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3) if($important, !important, null);
|
|
21
|
+
}
|
|
22
|
+
@mixin materialShadowBottom($opacity: 0.1) {
|
|
23
|
+
box-shadow: 0 3px 3px rgba(0, 0, 0, $opacity);
|
|
24
|
+
}
|
|
25
|
+
@mixin materialShadowSmall($important: false) {
|
|
26
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3) if($important, !important, null);
|
|
27
|
+
}
|
|
28
|
+
@mixin materialShadowMediumLarge($important: false, $opacity: 0.6) {
|
|
29
|
+
box-shadow: 0 0 25px rgba(0, 0, 0, $opacity) if($important, !important, null);
|
|
30
|
+
}
|
|
31
|
+
@mixin materialScrollbar() {
|
|
32
|
+
&::-webkit-scrollbar-track {
|
|
33
|
+
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
|
34
|
+
border-radius: 10px;
|
|
35
|
+
background-color: transparent;
|
|
36
|
+
}
|
|
37
|
+
&::-webkit-scrollbar {
|
|
38
|
+
height: 10px;
|
|
39
|
+
background-color: transparent;
|
|
40
|
+
}
|
|
41
|
+
&::-webkit-scrollbar-thumb {
|
|
42
|
+
max-width: 20px;
|
|
43
|
+
border-radius: 10px;
|
|
44
|
+
// -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
|
45
|
+
background-color: var(--primary);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
@mixin removeDefaultFocus() {
|
|
49
|
+
outline: none;
|
|
50
|
+
}
|
|
51
|
+
@mixin setGlobalKeyboardFocus($mode: 'outline') {
|
|
52
|
+
//respect element border radius
|
|
53
|
+
@include removeDefaultFocus();
|
|
54
|
+
@if $mode== 'outline' {
|
|
55
|
+
outline: var(--focusWidth) solid var(--palette-primary-300);
|
|
56
|
+
outline-offset: 2px;
|
|
57
|
+
} @else if $mode== 'border' {
|
|
58
|
+
border: var(--focusWidth) solid var(--palette-primary-300);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Apply the content styles in contrast mode. This is just enough contrast to be WCAG complient ---
|
|
62
|
+
// not a high-contrast mode.
|
|
63
|
+
//
|
|
64
|
+
// Call without arguments for use in encapsulated component styles, e.g.,
|
|
65
|
+
// @include contrastMode {
|
|
66
|
+
// // Styles to apply in contrast mode
|
|
67
|
+
// }
|
|
68
|
+
// To us in global context, pass 'global' as first argument, e.g.,
|
|
69
|
+
// @include contrastMode(global) { /* ... */ }
|
|
70
|
+
@mixin contrastMode($scope: encapsulated) {
|
|
71
|
+
$contrastModeSelector: 'body.es-contrast-mode';
|
|
72
|
+
@if $scope == encapsulated {
|
|
73
|
+
:host-context(#{$contrastModeSelector}) & {
|
|
74
|
+
@content;
|
|
75
|
+
}
|
|
76
|
+
} @else if $scope == global {
|
|
77
|
+
#{if(&, '#{$contrastModeSelector} &', $contrastModeSelector)} {
|
|
78
|
+
@content;
|
|
79
|
+
}
|
|
80
|
+
} @else {
|
|
81
|
+
@error "Invalid scope #{$scope}.";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
@mixin blurImage($blurStrength: 25px) {
|
|
85
|
+
position: absolute;
|
|
86
|
+
left: -$blurStrength * 2;
|
|
87
|
+
top: -$blurStrength * 2;
|
|
88
|
+
width: calc(100% + #{$blurStrength * 4});
|
|
89
|
+
height: calc(100% + #{$blurStrength * 4});
|
|
90
|
+
z-index: 0;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
filter: blur($blurStrength);
|
|
93
|
+
object-fit: cover;
|
|
94
|
+
opacity: 0.7;
|
|
95
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
declarations of dynamic css variabled
|
|
3
|
+
will only be included once via angular to prevent duplicate :root entries
|
|
4
|
+
*/
|
|
5
|
+
:root {
|
|
6
|
+
--primary: var(--palette-primary-500);
|
|
7
|
+
--warning: #cd2457;
|
|
8
|
+
--tableIconSize: 38px;
|
|
9
|
+
--textLight: #585858;
|
|
10
|
+
--textMediumLight: #888;
|
|
11
|
+
--textMain: #383838;
|
|
12
|
+
--cardWidth: 240px;
|
|
13
|
+
--colorStatusPositive: #40bf8e;
|
|
14
|
+
--colorStatusNegative: var(--warning);
|
|
15
|
+
--colorStarActive: #ba7c00;
|
|
16
|
+
--nodeVirtualColor: #42ca8d;
|
|
17
|
+
--nodeVirtualColorLight: #b8fcdd;
|
|
18
|
+
--transitionNormal: 0.2s;
|
|
19
|
+
--focusWidth: 2px;
|
|
20
|
+
--fontSizeXSmall: 85%;
|
|
21
|
+
--mobileWidth: 700px;
|
|
22
|
+
--mobileStage: 100px;
|
|
23
|
+
--itemSelectedTextColor: var(--palette-primary-700);
|
|
24
|
+
--listItemSelectedBackground: var(--palette-primary-50);
|
|
25
|
+
--listItemSelectedBackgroundEffect: linear-gradient(
|
|
26
|
+
to right,
|
|
27
|
+
var(--primary) 0,
|
|
28
|
+
var(--primary) 5px,
|
|
29
|
+
var(--palette-primary-50) 5px,
|
|
30
|
+
var(--palette-primary-50) 5px
|
|
31
|
+
)
|
|
32
|
+
no-repeat;
|
|
33
|
+
}
|
package/karma.conf.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Karma configuration file, see link for more information
|
|
2
|
+
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
3
|
+
|
|
4
|
+
module.exports = function (config) {
|
|
5
|
+
config.set({
|
|
6
|
+
basePath: '',
|
|
7
|
+
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
8
|
+
plugins: [
|
|
9
|
+
require('karma-jasmine'),
|
|
10
|
+
require('karma-chrome-launcher'),
|
|
11
|
+
require('karma-jasmine-html-reporter'),
|
|
12
|
+
require('karma-coverage'),
|
|
13
|
+
require('@angular-devkit/build-angular/plugins/karma'),
|
|
14
|
+
],
|
|
15
|
+
client: {
|
|
16
|
+
jasmine: {
|
|
17
|
+
// you can add configuration options for Jasmine here
|
|
18
|
+
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
|
19
|
+
// for example, you can disable the random execution with `random: false`
|
|
20
|
+
// or set a specific seed with `seed: 4321`
|
|
21
|
+
},
|
|
22
|
+
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
|
23
|
+
},
|
|
24
|
+
jasmineHtmlReporter: {
|
|
25
|
+
suppressAll: true, // removes the duplicated traces
|
|
26
|
+
},
|
|
27
|
+
coverageReporter: {
|
|
28
|
+
dir: require('path').join(__dirname, '../../coverage/edu-sharing-ui'),
|
|
29
|
+
subdir: '.',
|
|
30
|
+
reporters: [{ type: 'html' }, { type: 'text-summary' }],
|
|
31
|
+
},
|
|
32
|
+
reporters: ['progress', 'kjhtml'],
|
|
33
|
+
browsers: ['Chrome'],
|
|
34
|
+
customLaunchers: {
|
|
35
|
+
ChromeHeadlessCI: {
|
|
36
|
+
base: 'ChromeHeadless',
|
|
37
|
+
flags: ['--no-sandbox'],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
restartOnFileChange: true,
|
|
41
|
+
});
|
|
42
|
+
};
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ngx-edu-sharing-ui",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"license": "GNU GPL v2",
|
|
5
|
+
"description": "Angular components for Edu-Sharing UX parts",
|
|
6
|
+
"peerDependencies": {
|
|
7
|
+
"@angular/cdk": "~13.3.9",
|
|
8
|
+
"@angular/common": "^13.3.0",
|
|
9
|
+
"@angular/core": "^13.3.0",
|
|
10
|
+
"@angular/material": "13.3.9",
|
|
11
|
+
"material-design-icons": "^3.0.1",
|
|
12
|
+
"@ngx-translate/core": "^14.0.0",
|
|
13
|
+
"angular-material-css-vars": "^3.0.0",
|
|
14
|
+
"rxjs": "^6.6.7"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"tslib": "^2.3.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<es-dropdown
|
|
2
|
+
#dropdownRef
|
|
3
|
+
[options]="optionsMenu"
|
|
4
|
+
[showDisabled]="showDisabled"
|
|
5
|
+
[position]="dropdownPosition"
|
|
6
|
+
></es-dropdown>
|
|
7
|
+
<div
|
|
8
|
+
class="actionbar"
|
|
9
|
+
[class.actionbar-all-flat]="style === 'flat'"
|
|
10
|
+
[class.actionbar-background-dark]="backgroundType === 'dark'"
|
|
11
|
+
[class.actionbar-background-primary]="backgroundType === 'primary'"
|
|
12
|
+
[class.actionbar-round]="appearance === 'round'"
|
|
13
|
+
[class.actionbar-icon-button]="appearance === 'icon-button'"
|
|
14
|
+
>
|
|
15
|
+
<button
|
|
16
|
+
*ngFor="let option of optionsAlways; let i = index"
|
|
17
|
+
mat-button
|
|
18
|
+
color="primary"
|
|
19
|
+
[disabled]="!option.isEnabled"
|
|
20
|
+
[class.display-none]="!option.isEnabled && !showDisabled"
|
|
21
|
+
[class.mat-flat-button]="shouldHighlight(i, option)"
|
|
22
|
+
matTooltip="{{ option | optionTooltip }}"
|
|
23
|
+
[attr.aria-label]="option.name | translate"
|
|
24
|
+
(click)="click(option)"
|
|
25
|
+
>
|
|
26
|
+
<i [esIcon]="option.icon"></i>
|
|
27
|
+
<span class="action-always-caption" *ngIf="option.showName && appearance === 'button'">
|
|
28
|
+
{{ option.name | translate }}</span
|
|
29
|
+
>
|
|
30
|
+
</button>
|
|
31
|
+
<button
|
|
32
|
+
mat-button
|
|
33
|
+
color="primary"
|
|
34
|
+
class="more"
|
|
35
|
+
[attr.aria-label]="'OPTIONS.SHOW_ALL_OPTIONS' | translate"
|
|
36
|
+
[matMenuTriggerFor]="dropdownRef.menu"
|
|
37
|
+
*ngIf="canShowDropdown()"
|
|
38
|
+
data-test="more-actions-button"
|
|
39
|
+
>
|
|
40
|
+
<i esIcon="more_vert" [aria]="false"></i>
|
|
41
|
+
</button>
|
|
42
|
+
<div
|
|
43
|
+
*ngIf="optionsToggle.length"
|
|
44
|
+
class="actionToggle"
|
|
45
|
+
[class.actionToggleDivider]="optionsAlways.length"
|
|
46
|
+
>
|
|
47
|
+
<button
|
|
48
|
+
*ngFor="let option of optionsToggle"
|
|
49
|
+
mat-icon-button
|
|
50
|
+
matTooltip="{{ option.name | translate }}"
|
|
51
|
+
[attr.aria-label]="option.name | translate"
|
|
52
|
+
(click)="click(option)"
|
|
53
|
+
[class.disabled]="!option.isEnabled"
|
|
54
|
+
attr.data-test="toggle-{{ option.name }}"
|
|
55
|
+
>
|
|
56
|
+
<i [esIcon]="option.icon" [aria]="false"></i>
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
@import '../../../assets/scss/mixins';
|
|
2
|
+
|
|
3
|
+
.actionbar {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 10px;
|
|
7
|
+
}
|
|
8
|
+
.actionToggle > button {
|
|
9
|
+
color: var(--textLight);
|
|
10
|
+
}
|
|
11
|
+
button {
|
|
12
|
+
min-width: unset;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.light {
|
|
16
|
+
color: #fff;
|
|
17
|
+
background: transparent;
|
|
18
|
+
}
|
|
19
|
+
.disabled {
|
|
20
|
+
pointer-events: all;
|
|
21
|
+
}
|
|
22
|
+
.light a {
|
|
23
|
+
color: #fff;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.actionToggleDivider {
|
|
27
|
+
padding-left: 10px;
|
|
28
|
+
border-left: 1px solid #ddd;
|
|
29
|
+
}
|
|
30
|
+
.more {
|
|
31
|
+
color: var(--primary);
|
|
32
|
+
background-color: transparent;
|
|
33
|
+
}
|
|
34
|
+
.actionbar-background-dark {
|
|
35
|
+
.mat-button {
|
|
36
|
+
color: rgb(var(--palette-foreground-text-dark));
|
|
37
|
+
&:disabled {
|
|
38
|
+
color: rgba(var(--palette-foreground-text-dark), 0.75);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
.actionbar-background-primary {
|
|
43
|
+
.mat-button {
|
|
44
|
+
color: rgb(var(--palette-foreground-text-dark));
|
|
45
|
+
}
|
|
46
|
+
.mat-flat-button {
|
|
47
|
+
background-color: #fff;
|
|
48
|
+
color: var(--primary);
|
|
49
|
+
&:disabled {
|
|
50
|
+
color: var(--textLight);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
.actionbar-round {
|
|
55
|
+
.mat-button,
|
|
56
|
+
.mat-flat-button {
|
|
57
|
+
width: 45px;
|
|
58
|
+
height: 45px;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
}
|
|
61
|
+
button {
|
|
62
|
+
border-radius: 50%;
|
|
63
|
+
@include materialShadow();
|
|
64
|
+
}
|
|
65
|
+
&.actionbar-background-primary {
|
|
66
|
+
.mat-button {
|
|
67
|
+
background-color: #fff;
|
|
68
|
+
color: var(--primary);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
&.actionbar-all-flat button {
|
|
72
|
+
background: white;
|
|
73
|
+
color: var(--primary);
|
|
74
|
+
&:disabled {
|
|
75
|
+
color: var(--textLight);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
.more,
|
|
79
|
+
.actionAlways {
|
|
80
|
+
background: white;
|
|
81
|
+
color: var(--primary);
|
|
82
|
+
display: flex;
|
|
83
|
+
width: 45px;
|
|
84
|
+
height: 45px;
|
|
85
|
+
line-height: 45px;
|
|
86
|
+
text-align: center;
|
|
87
|
+
align-items: center;
|
|
88
|
+
.edu-icons,
|
|
89
|
+
.material-icons {
|
|
90
|
+
position: relative;
|
|
91
|
+
font-size: 24px;
|
|
92
|
+
}
|
|
93
|
+
span {
|
|
94
|
+
display: none;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
.action-always {
|
|
98
|
+
.edu-icons,
|
|
99
|
+
.material-icons {
|
|
100
|
+
right: 4px !important;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@mixin icon-button() {
|
|
106
|
+
.action-always {
|
|
107
|
+
padding: 0 1rem;
|
|
108
|
+
}
|
|
109
|
+
.action-always-caption {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
112
|
+
.mat-flat-button {
|
|
113
|
+
padding: 5px;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media screen and (max-width: (calc(var(--mobileWidth) + var(--mobileStage) * 4))) {
|
|
118
|
+
@include icon-button();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.actionbar-icon-button {
|
|
122
|
+
@include icon-button();
|
|
123
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { trigger } from '@angular/animations';
|
|
2
|
+
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
|
3
|
+
import { TranslateService } from '@ngx-translate/core';
|
|
4
|
+
import { UIAnimation } from '../util/ui-animation';
|
|
5
|
+
import { UIConstants } from '../util/ui-constants';
|
|
6
|
+
import { OptionItem } from '../types/option-item';
|
|
7
|
+
import { UIService } from '../services/ui.service';
|
|
8
|
+
import { Helper } from '../util/helper';
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: 'es-actionbar',
|
|
12
|
+
templateUrl: 'actionbar.component.html',
|
|
13
|
+
styleUrls: ['actionbar.component.scss'],
|
|
14
|
+
animations: [trigger('openOverlay', UIAnimation.openOverlay(UIAnimation.ANIMATION_TIME_FAST))],
|
|
15
|
+
})
|
|
16
|
+
/**
|
|
17
|
+
* The action bar provides several icons, usually at the top right, with actions for a current context
|
|
18
|
+
*/
|
|
19
|
+
export class ActionbarComponent implements OnChanges {
|
|
20
|
+
/**
|
|
21
|
+
* The amount of options which are not hidden inside an overflow menu
|
|
22
|
+
* (default: depending on mobile (1) or not (2))
|
|
23
|
+
* Also use numberOfAlwaysVisibleOptionsMobile to control the amount of mobile options visible
|
|
24
|
+
*/
|
|
25
|
+
@Input() numberOfAlwaysVisibleOptions = 2;
|
|
26
|
+
@Input() numberOfAlwaysVisibleOptionsMobile = 1;
|
|
27
|
+
/**
|
|
28
|
+
* Visual style of the actionbar
|
|
29
|
+
*
|
|
30
|
+
* Values:
|
|
31
|
+
* - 'button': material buttons with icons and text on medium to large screens
|
|
32
|
+
* - 'icon-button': material buttons without text
|
|
33
|
+
* - 'round': circular buttons without text
|
|
34
|
+
* @default 'button'
|
|
35
|
+
*/
|
|
36
|
+
@Input() appearance: 'round' | 'button' | 'icon-button' = 'button';
|
|
37
|
+
/**
|
|
38
|
+
* dropdownPosition is for position of dropdown (default = left)
|
|
39
|
+
* Values 'left' or 'right'
|
|
40
|
+
*/
|
|
41
|
+
@Input() dropdownPosition: 'left' | 'right' = 'left';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* backgroundType for color matching, either bright, dark or primary
|
|
45
|
+
*/
|
|
46
|
+
@Input() backgroundType: 'bright' | 'dark' | 'primary' = 'bright';
|
|
47
|
+
/**
|
|
48
|
+
* Style, currently default or 'flat' if all always visible icons should get a flat look
|
|
49
|
+
*/
|
|
50
|
+
@Input() style: 'default' | 'flat' = 'default';
|
|
51
|
+
/**
|
|
52
|
+
* Highlight one or more of the always-visible buttons as primary action.
|
|
53
|
+
*
|
|
54
|
+
* - `first`, `last`: The first / last of `optionsAlways` by order.
|
|
55
|
+
* - `manual`: Highlight all options that set `isPrimary = true`.
|
|
56
|
+
*/
|
|
57
|
+
@Input() highlight: 'first' | 'last' | 'manual' = 'first';
|
|
58
|
+
/**
|
|
59
|
+
* Should disabled ("greyed out") options be shown or hidden?
|
|
60
|
+
*/
|
|
61
|
+
@Input() showDisabled = true;
|
|
62
|
+
/**
|
|
63
|
+
* Set the options, see @OptionItem
|
|
64
|
+
*/
|
|
65
|
+
@Input() set options(options: OptionItem[]) {
|
|
66
|
+
this.optionsIn = options;
|
|
67
|
+
this.prepareOptions(options);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
optionsIn: OptionItem[] = [];
|
|
71
|
+
optionsAlways: OptionItem[] = [];
|
|
72
|
+
optionsMenu: OptionItem[] = [];
|
|
73
|
+
optionsToggle: OptionItem[] = [];
|
|
74
|
+
|
|
75
|
+
constructor(private uiService: UIService, private translate: TranslateService) {}
|
|
76
|
+
|
|
77
|
+
private prepareOptions(options: OptionItem[]) {
|
|
78
|
+
options = this.uiService.filterValidOptions(Helper.deepCopyArray(options));
|
|
79
|
+
if (options == null) {
|
|
80
|
+
this.optionsAlways = [];
|
|
81
|
+
this.optionsMenu = [];
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.optionsToggle = this.uiService.filterToggleOptions(options, true);
|
|
85
|
+
this.optionsAlways = this.getActionOptions(
|
|
86
|
+
this.uiService.filterToggleOptions(options, false),
|
|
87
|
+
).slice(0, this.getNumberOptions());
|
|
88
|
+
if (!this.optionsAlways.length) {
|
|
89
|
+
this.optionsAlways = this.uiService
|
|
90
|
+
.filterToggleOptions(options, false)
|
|
91
|
+
.slice(0, this.getNumberOptions());
|
|
92
|
+
}
|
|
93
|
+
this.optionsMenu = this.hideActionOptions(
|
|
94
|
+
this.uiService.filterToggleOptions(options, false),
|
|
95
|
+
this.optionsAlways,
|
|
96
|
+
);
|
|
97
|
+
// may causes weird looking
|
|
98
|
+
/*if(this.optionsMenu.length<2) {
|
|
99
|
+
this.optionsAlways = this.optionsAlways.concat(this.optionsMenu);
|
|
100
|
+
this.optionsMenu = [];
|
|
101
|
+
}*/
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public getNumberOptions() {
|
|
105
|
+
if (window.innerWidth < UIConstants.MOBILE_WIDTH) {
|
|
106
|
+
return this.numberOfAlwaysVisibleOptionsMobile;
|
|
107
|
+
}
|
|
108
|
+
return this.numberOfAlwaysVisibleOptions;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
click(option: OptionItem) {
|
|
112
|
+
if (!option.isEnabled) {
|
|
113
|
+
if (option.disabledCallback) {
|
|
114
|
+
option.disabledCallback();
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
option.callback();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private getActionOptions(options: OptionItem[]) {
|
|
122
|
+
const result: OptionItem[] = [];
|
|
123
|
+
for (const option of options) {
|
|
124
|
+
if (option.showAsAction) result.push(option);
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private hideActionOptions(options: OptionItem[], optionsAlways: OptionItem[]) {
|
|
130
|
+
const result: OptionItem[] = [];
|
|
131
|
+
for (const option of options) {
|
|
132
|
+
if (optionsAlways.indexOf(option) === -1) result.push(option);
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Invalidate / refreshes all options based on their current callbacks
|
|
139
|
+
*/
|
|
140
|
+
public invalidate() {
|
|
141
|
+
this.prepareOptions(this.optionsIn);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private filterDisabled(options: OptionItem[]) {
|
|
145
|
+
if (options == null) return null;
|
|
146
|
+
const filtered = [];
|
|
147
|
+
for (const option of options) {
|
|
148
|
+
if (option.isEnabled || this.showDisabled) filtered.push(option);
|
|
149
|
+
}
|
|
150
|
+
return filtered;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
canShowDropdown() {
|
|
154
|
+
if (!this.optionsMenu.length) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return this.optionsMenu.filter((o) => o.isEnabled).length > 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
shouldHighlight(optionIndex: number, option: OptionItem): boolean {
|
|
161
|
+
switch (this.highlight) {
|
|
162
|
+
case 'first':
|
|
163
|
+
return optionIndex === 0;
|
|
164
|
+
case 'last':
|
|
165
|
+
return optionIndex === this.optionsAlways.length - 1;
|
|
166
|
+
case 'manual':
|
|
167
|
+
return option.isPrimary;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
172
|
+
this.invalidate();
|
|
173
|
+
}
|
|
174
|
+
}
|