Custom widget edit screen

This commit is contained in:
Travis Ralston 2017-12-22 21:33:37 -07:00
parent 6740571183
commit dd02c6df2c
7 changed files with 116 additions and 40 deletions

View File

@ -32,6 +32,7 @@ import { DimensionApiService } from "./shared/services/dimension-api.service";
import { AdminApiService } from "./shared/services/admin-api.service"; import { AdminApiService } from "./shared/services/admin-api.service";
import { ServiceLocator } from "./shared/services/locator.service"; import { ServiceLocator } from "./shared/services/locator.service";
import { IboxComponent } from "./elements/ibox/ibox.component"; import { IboxComponent } from "./elements/ibox/ibox.component";
import { CustomWidgetConfigComponent } from "./configs/widget/custom/custom.widget.component";
@NgModule({ @NgModule({
imports: [ imports: [
@ -64,6 +65,7 @@ import { IboxComponent } from "./elements/ibox/ibox.component";
GCalWidgetWrapperComponent, GCalWidgetWrapperComponent,
RiotHomeComponent, RiotHomeComponent,
IboxComponent, IboxComponent,
CustomWidgetConfigComponent,
// Vendor // Vendor
], ],

View File

@ -6,6 +6,7 @@ import { VideoWidgetWrapperComponent } from "./widget_wrappers/video/video.compo
import { JitsiWidgetWrapperComponent } from "./widget_wrappers/jitsi/jitsi.component"; import { JitsiWidgetWrapperComponent } from "./widget_wrappers/jitsi/jitsi.component";
import { GCalWidgetWrapperComponent } from "./widget_wrappers/gcal/gcal.component"; import { GCalWidgetWrapperComponent } from "./widget_wrappers/gcal/gcal.component";
import { RiotHomeComponent } from "./riot/riot-home/home.component"; import { RiotHomeComponent } from "./riot/riot-home/home.component";
import { CustomWidgetConfigComponent } from "./configs/widget/custom/custom.widget.component";
const routes: Routes = [ const routes: Routes = [
{path: "", component: HomeComponent}, {path: "", component: HomeComponent},
@ -21,14 +22,13 @@ const routes: Routes = [
}, },
{ {
path: "widget", path: "widget",
children: [], children: [
// children: [ {
// { path: "custom",
// path: "custom", component: CustomWidgetConfigComponent,
// component: NewTestWidgetComponent, data: {breadcrumb: "Custom Widgets", name: "Custom Widgets"}
// data: {breadcrumb: "Custom Widgets", name: "Custom Widgets"} },
// }, ],
// ],
}, },
], ],
}, },

View File

@ -0,0 +1,58 @@
<my-ibox title="Add {{ defaultName }}">
<div class="my-ibox-content">
<form (submit)="addWidget()" novalidate name="addForm">
<label class="label-block">
Widget Name
<input type="text" class="form-control"
placeholder="{{ defaultName }}"
[(ngModel)]="newWidget.dimension.newName" name="widget-name-new"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Widget URL
<input type="text" class="form-control"
placeholder="https://matrix.org"
[(ngModel)]="newWidget.dimension.newUrl" name="widget-url-new"
[disabled]="isUpdating"/>
</label>
<button type="submit" class="btn btn-sm btn-success" [disabled]="isUpdating">
<i class="fa fa-plus"></i> Add Widget
</button>
</form>
</div>
</my-ibox>
<my-ibox *ngFor="let widget of widgets trackById"
[isCollapsible]="true" [defaultCollapsed]="widget.id !== defaultExpandedWidgetId"
title="{{ widget.name || widget.url || defaultName }}">
<div class="my-ibox-content">
<form (submit)="saveWidget(widget)" novalidate name="addForm">
<label class="label-block">
Widget Name
<input type="text" class="form-control"
placeholder="{{ defaultName }}"
[(ngModel)]="widget.dimension.newName" name="widget-name-{{widget.id}}"
[disabled]="isUpdating"/>
</label>
<label class="label-block">
Widget URL
<input type="text" class="form-control"
placeholder="https://matrix.org"
[(ngModel)]="widget.dimension.newUrl" name="widget-url-{{widget.id}}"
[disabled]="isUpdating"/>
</label>
<button type="submit" class="btn btn-sm btn-primary" [disabled]="isUpdating">
<i class="fa fa-save"></i> Save Widget
</button>
<button type="button" class="btn btn-sm btn-danger" [disabled]="isUpdating">
<i class="fa fa-times"></i> Remove Widget
</button>
<button type="button" class="btn btn-sm btn-white" [disabled]="isUpdating" (click)="resetWidget(widget)"
*ngIf="hasChanges(widget)">
<i class="fa fa-reset"></i> Undo Changes
</button>
</form>
</div>
</my-ibox>

View File

@ -0,0 +1,13 @@
import { NewWidgetComponent } from "../widget.component";
import { WIDGET_CUSTOM } from "../../../shared/models/widget";
import { Component } from "@angular/core";
@Component({
templateUrl: "custom.widget.component.html",
styleUrls: ["custom.widget.component.scss"],
})
export class CustomWidgetConfigComponent extends NewWidgetComponent {
constructor() {
super(WIDGET_CUSTOM, "Custom Widget", "generic");
}
}

View File

@ -18,8 +18,8 @@ export class NewWidgetComponent {
public isUpdating = false; public isUpdating = false;
public widgets: EditableWidget[]; public widgets: EditableWidget[];
public newWidget: EditableWidget; public newWidget: EditableWidget;
public defaultExpandedWidgetId: string;
private toggledWidgetIds: string[] = [];
private scalarWrapperUrls: string[] = []; private scalarWrapperUrls: string[] = [];
private wrapperUrl = ""; private wrapperUrl = "";
@ -38,7 +38,7 @@ export class NewWidgetComponent {
protected OnWidgetAfterDelete = new EventEmitter<EditableWidget>(); protected OnWidgetAfterDelete = new EventEmitter<EditableWidget>();
constructor(private widgetTypes: string[], constructor(private widgetTypes: string[],
private defaultName: string, public defaultName: string,
private wrapperId = "generic", private wrapperId = "generic",
private scalarWrapperId = null) { private scalarWrapperId = null) {
this.isLoading = true; this.isLoading = true;
@ -64,6 +64,12 @@ export class NewWidgetComponent {
this.isLoading = false; this.isLoading = false;
this.isUpdating = false; this.isUpdating = false;
// We reset after discovering to ensure that the widget component can correctly
// set the state of the widget prior to us unpacking it (again)
for (let widget of this.widgets) {
this.resetWidget(widget);
}
// See if we should request editing a particular widget // See if we should request editing a particular widget
if (SessionStorage.editWidgetId && SessionStorage.editsRequested === 1) { if (SessionStorage.editWidgetId && SessionStorage.editsRequested === 1) {
let editWidget: EditableWidget = null; let editWidget: EditableWidget = null;
@ -78,7 +84,7 @@ export class NewWidgetComponent {
console.log("Requesting edit for " + editWidget.id); console.log("Requesting edit for " + editWidget.id);
this.widgets = [editWidget]; this.widgets = [editWidget];
otherWidgets.forEach(w => this.widgets.push(w)); otherWidgets.forEach(w => this.widgets.push(w));
this.editWidget(editWidget); this.defaultExpandedWidgetId = editWidget.id;
} }
} }
}); });
@ -171,7 +177,6 @@ export class NewWidgetComponent {
* @return {string} The unwrapped URL * @return {string} The unwrapped URL
*/ */
private unwrapUrl(url: string): string { private unwrapUrl(url: string): string {
console.log(this.scalarWrapperUrls);
if (!this.wrapperUrl) return url; if (!this.wrapperUrl) return url;
const urls = [this.wrapperUrl].concat(this.scalarWrapperUrls); const urls = [this.wrapperUrl].concat(this.scalarWrapperUrls);
@ -225,6 +230,11 @@ export class NewWidgetComponent {
* with a new widget. * with a new widget.
*/ */
public addWidget(): Promise<any> { public addWidget(): Promise<any> {
if (!this.newWidget.dimension.newUrl || this.newWidget.dimension.newUrl.trim().length === 0) {
this.toaster.pop("warning", "Please enter a URL for the widget");
return;
}
this.packWidget(this.newWidget); this.packWidget(this.newWidget);
this.isUpdating = true; this.isUpdating = true;
@ -260,7 +270,6 @@ export class NewWidgetComponent {
this.isUpdating = true; this.isUpdating = true;
this.OnWidgetBeforeEdit.emit(widget); this.OnWidgetBeforeEdit.emit(widget);
return this.scalarApi.setWidget(SessionStorage.roomId, widget) return this.scalarApi.setWidget(SessionStorage.roomId, widget)
.then(() => this.toggleWidget(widget))
.then(() => { .then(() => {
this.isUpdating = false; this.isUpdating = false;
this.OnWidgetAfterEdit.emit(widget); this.OnWidgetAfterEdit.emit(widget);
@ -296,38 +305,28 @@ export class NewWidgetComponent {
} }
/** /**
* Puts a widget in the edit state. * Resets a widget to before it had changes made to it
* @param {EditableWidget} widget * @param {EditableWidget} widget The widget to reset
*/ */
public editWidget(widget: EditableWidget) { public resetWidget(widget: EditableWidget) {
this.toggleWidget(widget, "edit");
}
/**
* Toggles a widget between the "edit" and "canceled" state. If a targetState is
* defined, the widget is forced into that state.
* @param {EditableWidget} widget The widget to set the state of.
* @param {"edit"|"cancel"|null} targetState The target state, optional
*/
public toggleWidget(widget: EditableWidget, targetState: "edit" | "cancel" | null = null) {
let idx = this.toggledWidgetIds.indexOf(widget.id);
if (targetState === null) targetState = idx === -1 ? "edit" : "cancel";
if (targetState === "edit") {
this.unpackWidget(widget); this.unpackWidget(widget);
this.OnWidgetPreparedForEdit.emit(widget); this.OnWidgetPreparedForEdit.emit(widget);
if (idx === -1) this.toggledWidgetIds.push(widget.id);
}
else this.toggledWidgetIds.splice(idx, 1);
} }
/** /**
* Determines if a widget is in the edit state * Determines if a widget has had any changes made to it
* @param {EditableWidget} widget The widget to check * @param {EditableWidget} widget The widget to check
* @returns {boolean} true if the widget is in the edit state * @returns {boolean} True if the widget has been edited
*/ */
public isWidgetToggled(widget: EditableWidget) { public hasChanges(widget: EditableWidget):boolean {
return this.toggledWidgetIds.indexOf(widget.id) !== -1; if (widget.dimension.newUrl !== this.unwrapUrl(widget.url)) return true;
if (widget.dimension.newName !== widget.name) return true;
if (widget.dimension.newTitle !== widget.data.title) return true;
const currentData = JSON.parse(JSON.stringify(widget.data || "{}"));
const newData = JSON.parse(JSON.stringify(widget.dimension.newData || "{}"));
if (currentData !== newData) return true;
return false;
} }
} }

View File

@ -30,3 +30,7 @@ body {
button { button {
cursor: pointer; cursor: pointer;
} }
.label-block {
display: block;
}