diff --git a/webapi/src/main/java/org/sakaiproject/webapi/controllers/DashboardController.java b/webapi/src/main/java/org/sakaiproject/webapi/controllers/DashboardController.java index 6afcba75aae3..9bb72c9d5d9b 100644 --- a/webapi/src/main/java/org/sakaiproject/webapi/controllers/DashboardController.java +++ b/webapi/src/main/java/org/sakaiproject/webapi/controllers/DashboardController.java @@ -144,21 +144,21 @@ public void init() { if (!tasksEnabled) defaultHomeLayout.remove("tasks"); List courseWidgetLayout1 = new ArrayList<>(serverConfigurationService.getStringList("dashboard.course.widget.layout1", null)); - if (courseWidgetLayout1 == null) { + if (courseWidgetLayout1.isEmpty()) { courseWidgetLayout1 = new ArrayList<>(List.of("tasks", "calendar", "announcements", "grades")); } if (!tasksEnabled) courseWidgetLayout1.remove("tasks"); defaultWidgetLayouts.put("1", courseWidgetLayout1); List courseWidgetLayout2 = new ArrayList<>(serverConfigurationService.getStringList("dashboard.course.widget.layout2", null)); - if (courseWidgetLayout2 == null) { + if (courseWidgetLayout2.isEmpty()) { courseWidgetLayout2 = new ArrayList<>(List.of("tasks", "calendar", "forums", "grades", "announcements")); } if (!tasksEnabled) courseWidgetLayout2.remove("tasks"); defaultWidgetLayouts.put("2", courseWidgetLayout2); List courseWidgetLayout3 = new ArrayList<>(serverConfigurationService.getStringList("dashboard.course.widget.layout3", null)); - if (courseWidgetLayout3 == null) { + if (courseWidgetLayout3.isEmpty()) { courseWidgetLayout3 = new ArrayList<>(List.of("tasks", "calendar", "announcements", "grades", "forums")); } if (!tasksEnabled) courseWidgetLayout3.remove("tasks"); diff --git a/webcomponents/bundle/src/main/bundle/tasks.properties b/webcomponents/bundle/src/main/bundle/tasks.properties index 0f7c0cc0c4cb..9859fdb6844f 100644 --- a/webcomponents/bundle/src/main/bundle/tasks.properties +++ b/webcomponents/bundle/src/main/bundle/tasks.properties @@ -44,7 +44,7 @@ edit_task=Edit Task trash=Trash text=Text task_url=Click to be taken to the task -add_task=Add a new task +add_new_task=Add more=More less=Less show_less=Show less detail about this task diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-course-dashboard/src/SakaiCourseDashboard.js b/webcomponents/tool/src/main/frontend/packages/sakai-course-dashboard/src/SakaiCourseDashboard.js index d0e3c94b9ce2..44135059b3b7 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-course-dashboard/src/SakaiCourseDashboard.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-course-dashboard/src/SakaiCourseDashboard.js @@ -1,7 +1,6 @@ import { html, nothing } from "lit"; import { SakaiElement } from "@sakai-ui/sakai-element"; import "@sakai-ui/sakai-button/sakai-button.js"; -import "@sakai-ui/sakai-widgets"; import "@sakai-ui/sakai-widgets/sakai-widget-panel.js"; import "@lion/dialog/define"; import "../sakai-course-dashboard-template-picker.js"; @@ -28,15 +27,14 @@ export class SakaiCourseDashboard extends SakaiElement { this.loadTranslations("dashboard").then(r => this.i18n = r); } - set siteId(value) { + connectedCallback() { - this._siteId = value; - this.loadData(); - } + super.connectedCallback(); - get siteId() { return this._siteId; } + this._loadData(); + } - loadData() { + _loadData() { const url = `/api/sites/${this.siteId}/dashboard`; fetch(url, { credentials: "include" }) @@ -52,10 +50,6 @@ export class SakaiCourseDashboard extends SakaiElement { .catch(error => console.error(error)); } - shouldUpdate() { - return this.i18n && this.data; - } - widgetLayoutChanged(e) { this.data.layout = e.detail.layout; } @@ -179,6 +173,10 @@ export class SakaiCourseDashboard extends SakaiElement { this.data.programme = e.target.innerText; } + shouldUpdate() { + return this.i18n && this.data; + } + titleBlock() { return html` @@ -204,7 +202,7 @@ export class SakaiCourseDashboard extends SakaiElement { ${this.i18n.edit} `} - ` : ""} + ` : nothing} `; @@ -259,7 +257,6 @@ export class SakaiCourseDashboard extends SakaiElement { `; } - template3() { return html` @@ -278,7 +275,10 @@ export class SakaiCourseDashboard extends SakaiElement { renderOverview() { return html` - + + `; } diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-element/src/SakaiShadowElement.js b/webcomponents/tool/src/main/frontend/packages/sakai-element/src/SakaiShadowElement.js index 09a065a8bda4..41ae2f285575 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-element/src/SakaiShadowElement.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-element/src/SakaiShadowElement.js @@ -1,5 +1,6 @@ import { css, LitElement } from "lit"; import { loadProperties, tr } from "@sakai-ui/sakai-i18n"; +import { getGlobalStyleSheets } from "./global-styles.js"; export class SakaiShadowElement extends LitElement { @@ -57,55 +58,12 @@ export class SakaiShadowElement extends LitElement { return !currentString ? null : JSON.parse(currentString)[name]; } - static styles = css` - button { - color: var(--sui-btn-color); - background: var(--sui-btn-bg-color); - padding: var(--sui-btn-padding); - border-radius: var(--sui-btn-border-radius); - border-width: var(--sui-btn-border-width); - border-color: var(--sui-btn-border-color); - box-shadow: var(--sui-btn-box-shadow); - font-family: var(--sui-btn-font-family); - font-size: var(--sui-btn-font-size); - font-weight: var(--sui-btn-font-weight); - line-height: var(--sui-btn-line-height); - } - - button:hover { - background: var(--sui-btn-hover-bg-color); - border-color: var(--sui-btn-hover-border-color); - box-shadow: var(--sui-btn-hover-box-shadow); - } - - select { - appearance: none; - background-color: var(--sakai-background-color-1); - background-image: var(--select-background-image-url); - background-position: right 50%; - background-repeat: no-repeat; - color: var(--sakai-text-color-1); - font-family: var(--sakai-font-family)y; - font-size: 13px; - padding: 0.3em 2.2em 0.3em 0.5em; - text-align: left; - max-width: 100%; - border: 1px solid var(--sakai-border-color); - } - - select[multiple], select[size]:not([size='1']) { - background-image: none; - } - - select:focus { - box-shadow: 0px 0px $focus-outline-width $focus-outline-width var(--focus-outline-color); - } - - select[disabled="disabled"], select[disabled], select[disabled="true"] { - opacity: 0.7; - background-color: var(--sakai-background-color-1); - color: var(--sakai-text-color-disabled); - cursor: not-allowed; - } - `; + static styles = [ + ...getGlobalStyleSheets(), + css` + select[multiple], select[size]:not([size='1']) { + background-image: none; + } + ` + ]; } diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-element/src/global-styles.js b/webcomponents/tool/src/main/frontend/packages/sakai-element/src/global-styles.js new file mode 100644 index 000000000000..e6fce16c8667 --- /dev/null +++ b/webcomponents/tool/src/main/frontend/packages/sakai-element/src/global-styles.js @@ -0,0 +1,21 @@ +let globalSheets = null; + +export function getGlobalStyleSheets() { + if (globalSheets === null) { + globalSheets = Array.from(document.styleSheets) + .map(x => { + const sheet = new CSSStyleSheet(); + const css = Array.from(x.cssRules).map(rule => rule.cssText).join(" "); + sheet.replaceSync(css); + return sheet; + }); + } + + return globalSheets; +} + +export function addGlobalStylesToShadowRoot(shadowRoot) { + shadowRoot.adoptedStyleSheets.push( + ...getGlobalStyleSheets() + ); +} diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-home-dashboard/src/SakaiHomeDashboard.js b/webcomponents/tool/src/main/frontend/packages/sakai-home-dashboard/src/SakaiHomeDashboard.js index b7fd27859f37..61fb7c9f6fc7 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-home-dashboard/src/SakaiHomeDashboard.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-home-dashboard/src/SakaiHomeDashboard.js @@ -161,7 +161,6 @@ export class SakaiHomeDashboard extends SakaiElement { .layout=${this._data.layout} site-id="" user-id="${ifDefined(this.userId)}" - columns="2" ?editing=${this._editing}> diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-tasks/src/SakaiTasks.js b/webcomponents/tool/src/main/frontend/packages/sakai-tasks/src/SakaiTasks.js index 2d37a5171808..254f445546af 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-tasks/src/SakaiTasks.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-tasks/src/SakaiTasks.js @@ -293,9 +293,9 @@ export class SakaiTasks extends SakaiPageableElement {
- - - +
diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiDashboardWidget.js b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiDashboardWidget.js index 6275460b5624..61478f39974b 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiDashboardWidget.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiDashboardWidget.js @@ -1,9 +1,10 @@ -import { css, html, LitElement } from "lit"; -import "@sakai-ui/sakai-icon"; +import { css, html } from "lit"; +import { ifDefined } from "lit/directives/if-defined.js"; +import { SakaiShadowElement } from "@sakai-ui/sakai-element"; import { loadProperties } from "@sakai-ui/sakai-i18n"; import "@sakai-ui/sakai-pager"; -export class SakaiDashboardWidget extends LitElement { +export class SakaiDashboardWidget extends SakaiShadowElement { static properties = { @@ -11,9 +12,11 @@ export class SakaiDashboardWidget extends LitElement { userId: { attribute: "user-id", type: String }, title: String, state: String, + editing: { type: Boolean }, + disableLeftAndUp: { attribute: "disable-left-and-up", type: Boolean }, + disableRightAndDown: { attribute: "disable-right-and-down", type: Boolean }, _baseI18n: { state: true }, _i18n: { state: true }, - editing: { type: Boolean }, }; constructor() { @@ -59,69 +62,66 @@ export class SakaiDashboardWidget extends LitElement { this.dispatchEvent(new CustomEvent("move", { detail: { widgetId: this.widgetId, direction }, bubbles: true })); } - moveUp() { - this.move("up"); - } + moveUp() { this.move("up"); } - moveDown() { - this.move("down"); - } + moveDown() { this.move("down"); } - moveLeft() { - this.move("left"); - } + moveLeft() { this.move("left"); } - moveRight() { - this.move("right"); - } + moveRight() { this.move("right"); } render() { return html`
-
+
${this.title}
${this.editing ? html` -
-
- + - - -
- - - + +
` : ""} @@ -135,68 +135,59 @@ export class SakaiDashboardWidget extends LitElement { `; } - static styles = css` - - :host { - width: 100%; - } - a { - color: var(--link-color); - } - a:hover { - color: var(--link-hover-color); - } - a:active { - color: var(--link-active-color); - } - a:visited { - color: var(--link-visited-color); - } - #topbar { - display: flex; - margin-top: 8px; - margin-bottom: 20px; - } - - #container { - display: flex; - flex-flow: column; - height: 100%; - background-color: var(--sakai-dashboard-widget-bg-color, white); - border-radius: var(--sakai-course-card-border-radius, 4px); - border: solid; - border-width: var(--sakai-dashboard-widget-border-width, 1px); - border-color: var(--sakai-dashboard-widget-border-color, rgb(224,224,224)); - } - - #title-bar { - display: flex; - padding: 10px; - background-color: var(--sakai-title-bar-bg-color, rgb(244, 244, 244)); - font-weight: var(--sakai-title-bar-font-weight, bold); - } - - #title-bar sakai-icon[type="close"] { - color: var(--sakai-close-icon-color, red); + static styles = [ + SakaiShadowElement.styles, + css` + :host { + width: 100%; + } + a { + color: var(--link-color); + } + a:hover { + color: var(--link-hover-color); + } + a:active { + color: var(--link-active-color); + } + a:visited { + color: var(--link-visited-color); } - #title { - flex: 2; - margin-left: 12px; + #container { + display: flex; + flex-flow: column; + height: 100%; + background-color: var(--sakai-dashboard-widget-bg-color, white); + border-radius: var(--sakai-course-card-border-radius, 4px); + border: solid; + border-width: var(--sakai-dashboard-widget-border-width, 1px); + border-color: var(--sakai-dashboard-widget-border-color, rgb(224,224,224)); } - #content { - padding: 10px; - padding-bottom: 0; - flex-grow: 1; - border-radius: 0 0 var(--sakai-course-card-border-radius, 4px) var(--sakai-course-card-border-radius, 4px); - } - - #widget-mover { - display: flex; - } - #widget-mover div { - padding: 5px; - flex: 1; + + #title-bar { + background-color: var(--sakai-title-bar-bg-color, rgb(244, 244, 244)); + font-weight: var(--sakai-title-bar-font-weight, bold); + } + + #title { + flex: 2; + margin-left: 12px; + } + #content { + padding: 10px; + padding-bottom: 0; + flex-grow: 1; + border-radius: 0 0 var(--sakai-course-card-border-radius, 4px) var(--sakai-course-card-border-radius, 4px); + } + + #widget-mover { + display: flex; } - `; + #widget-mover div { + padding: 5px; + flex: 1; + } + ` + ]; } diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPanel.js b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPanel.js index 44e12bbbe032..2a7b06bbd919 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPanel.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPanel.js @@ -1,4 +1,5 @@ -import { html, css, LitElement } from "lit"; +import { html, css, nothing } from "lit"; +import { SakaiShadowElement } from "@sakai-ui/sakai-element"; import { ifDefined } from "lit/directives/if-defined.js"; import { repeat } from "lit/directives/repeat.js"; import "../sakai-calendar-widget.js"; @@ -9,7 +10,7 @@ import "../sakai-forums-widget.js"; import "../sakai-widget-picker.js"; import { loadProperties } from "@sakai-ui/sakai-i18n"; -export class SakaiWidgetPanel extends LitElement { +export class SakaiWidgetPanel extends SakaiShadowElement { static properties = { @@ -21,13 +22,11 @@ export class SakaiWidgetPanel extends LitElement { state: String, editing: { type: Boolean }, _widgets: { state: true }, - columns: { type: Number }, }; constructor() { super(); - this.columns = 2; this.state = "view"; loadProperties("widgetpanel").then(r => this.i18n = r); } @@ -146,39 +145,23 @@ export class SakaiWidgetPanel extends LitElement { const tmpWidgetId = this.layout[currentIndex]; switch (e.detail.direction) { + case "up": case "left": this.layout[currentIndex] = this.layout[currentIndex - 1]; this.layout[currentIndex - 1] = tmpWidgetId; break; + case "down": case "right": this.layout[currentIndex] = this.layout[currentIndex + 1]; this.layout[currentIndex + 1] = tmpWidgetId; break; - case "up": - if (this.columns === 1) { - this.layout[currentIndex] = this.layout[currentIndex - 1]; - this.layout[currentIndex - 1] = tmpWidgetId; - } else { - this.layout[currentIndex] = this.layout[currentIndex - this.columns]; - this.layout[currentIndex - this.columns] = tmpWidgetId; - } - break; - case "down": - if (this.columns === 1) { - this.layout[currentIndex] = this.layout[currentIndex + 1]; - this.layout[currentIndex + 1] = tmpWidgetId; - } else { - this.layout[currentIndex] = this.layout[currentIndex + this.columns]; - this.layout[currentIndex + this.columns] = tmpWidgetId; - } - break; default: } this.requestUpdate(); this.fireChanged(); } - getWidget(r) { + getWidget(r, index) { const w = this._widgets.find(widget => widget.id === r); @@ -194,6 +177,8 @@ export class SakaiWidgetPanel extends LitElement { state="${w.state}" @remove=${this.removeWidget} @move=${this.moveWidget} + ?disable-left-and-up=${index === 0} + ?disable-right-and-down=${index === this._widgets.length - 1} ?editing=${this.editing}>
@@ -209,6 +194,8 @@ export class SakaiWidgetPanel extends LitElement { state="${w.state}" @remove=${this.removeWidget} @move=${this.moveWidget} + ?disable-left-and-up=${index === 0} + ?disable-right-and-down=${index === this._widgets.length - 1} ?editing=${this.editing}>
@@ -224,6 +211,8 @@ export class SakaiWidgetPanel extends LitElement { state="${w.state}" @remove=${this.removeWidget} @move=${this.moveWidget} + ?disable-left-and-up=${index === 0} + ?disable-right-and-down=${index === this._widgets.length - 1} ?editing=${this.editing}>
@@ -239,6 +228,8 @@ export class SakaiWidgetPanel extends LitElement { state="${w.state}" @remove=${this.removeWidget} @move=${this.moveWidget} + ?disable-left-and-up=${index === 0} + ?disable-right-and-down=${index === this._widgets.length - 1} ?editing=${this.editing}>
@@ -254,12 +245,20 @@ export class SakaiWidgetPanel extends LitElement { class="widget" @remove=${this.removeWidget} @move=${this.moveWidget} + ?disable-left-and-up=${index === 0} + ?disable-right-and-down=${index === this._widgets.length - 1} ?editing=${this.editing}> `; case "picker": - return this.editing ? html`
` : ""; + return this.editing ? html` +
+ +
+ ` : nothing; default: return ""; } @@ -270,61 +269,64 @@ export class SakaiWidgetPanel extends LitElement { return html` ${this.editing ? html`
-
- - -
${this.i18n.add_a_widget}
-
-
+
- ` : ""} + ` : nothing}
- ${repeat(this.layout, w => w, w => html` - ${this.getWidget(w)} + ${repeat(this.layout, w => w, (w, i) => html` + ${this.getWidget(w, i)} `)}
`; } - static styles = css` - :host { - display: block; - width: var(--sakai-widget-panel-width); - background-color: var(--sakai-tool-bg-color); - } - #add-button { - text-align: right; - margin-bottom: 10px; - display: flex; - align-items: center; - justify-content: flex-end; - } - #add-button sakai-icon { - color: var(--sakai-widget-panel-add-button-color, green); - } - a { - color: var(--link-color); - } - #add-text { - display: inline-block; - font-weight: bold; - color: var(--sakai-widget-panel-add-text-color); - font-size: var(--sakai-widget-panel-add-text-size, 14px); - margin-left: 6px; - } - .faded { - pointer-events: none; - opacity: 0.4; - } + static styles = [ + SakaiShadowElement.styles, + css` + :host { + display: block; + width: var(--sakai-widget-panel-width); + background-color: var(--sakai-tool-bg-color); + } + #add-button { + text-align: right; + margin-bottom: 10px; + display: flex; + align-items: center; + justify-content: flex-end; + } + #add-button i { + font-size: 16px; + font-weight: bold; + } + a { + color: var(--link-color); + } + #add-text { + display: inline-block; + font-weight: bold; + color: var(--sakai-widget-panel-add-text-color); + font-size: var(--sakai-widget-panel-add-text-size, 14px); + margin-left: 6px; + } + .faded { + pointer-events: none; + opacity: 0.4; + } - #grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(var(--sakai-widget-panel-min-widget-width, 320px), 1fr)); - grid-gap: var(--sakai-widget-panel-gutter-width, 1rem); - } - `; + #grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(var(--sakai-widget-panel-min-widget-width, 320px), 1fr)); + grid-gap: var(--sakai-widget-panel-gutter-width, 1rem); + } + ` + ]; } diff --git a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPicker.js b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPicker.js index 8fe51d28cd9f..24a2213834f7 100644 --- a/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPicker.js +++ b/webcomponents/tool/src/main/frontend/packages/sakai-widgets/src/SakaiWidgetPicker.js @@ -69,7 +69,7 @@ export class SakaiWidgetPicker extends SakaiDashboardWidget { return html` ${this.available.length ? html` -
${this._i18n.pick_instruction}
+
${this._i18n.pick_instruction}
${this.available.map(w => html` `)}