mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-02-20 17:52:46 +00:00
Saving edited text
This commit is contained in:
parent
fb14e657bb
commit
1b2206852b
@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatMenuModule, MatIconModule } from '@angular/material';
|
||||
|
||||
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component';
|
||||
import { CssFixer } from './helpers/css-fixer';
|
||||
import { FontFixer } from './helpers/font-fixer';
|
||||
import { MultiLinkCalculatorHelper } from './helpers/multi-link-calculator-helper';
|
||||
@ -41,6 +40,8 @@ import { SelectionControlComponent } from './components/selection-control/select
|
||||
import { SelectionSelectComponent } from './components/selection-select/selection-select.component';
|
||||
import { DraggableSelectionComponent } from './components/draggable-selection/draggable-selection.component';
|
||||
import { MapSettingsManager } from './managers/map-settings-manager';
|
||||
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component';
|
||||
import { TextEditingComponent } from './components/text-editing/text-editing.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -53,6 +54,7 @@ import { MapSettingsManager } from './managers/map-settings-manager';
|
||||
D3MapComponent,
|
||||
ExperimentalMapComponent,
|
||||
DrawingResizingComponent,
|
||||
TextEditingComponent,
|
||||
...ANGULAR_MAP_DECLARATIONS,
|
||||
SelectionControlComponent,
|
||||
SelectionSelectComponent,
|
||||
|
@ -11,4 +11,5 @@
|
||||
<app-drawing-resizing></app-drawing-resizing>
|
||||
<app-selection-control></app-selection-control>
|
||||
<app-selection-select></app-selection-select>
|
||||
<app-text-editing></app-text-editing>
|
||||
<app-draggable-selection [svg]="svg"></app-draggable-selection>
|
||||
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 410 B |
@ -28,4 +28,4 @@ export class DrawingResizingComponent implements OnInit, OnDestroy{
|
||||
ngOnDestroy() {
|
||||
this.resizingFinished.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Subscription } from 'rxjs';
|
||||
import { TextEditingTool } from '../../tools/text-editing-tool';
|
||||
import { DrawingsEventSource } from '../../events/drawings-event-source';
|
||||
import { TextEditedDataEvent } from '../../events/event-source';
|
||||
|
||||
@Component({
|
||||
selector: 'app-text-editing',
|
||||
template: `<ng-content></ng-content>`,
|
||||
styleUrls: ['./text-editing.component.scss']
|
||||
})
|
||||
export class TextEditingComponent implements OnInit, OnDestroy{
|
||||
textEditingFinished: Subscription;
|
||||
|
||||
constructor(
|
||||
private textEditingTool: TextEditingTool,
|
||||
private drawingEventSource: DrawingsEventSource
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.textEditingFinished = this.textEditingTool.editingFinished.subscribe((evt: TextEditedDataEvent) => {
|
||||
this.drawingEventSource.textEdited.emit(evt);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.textEditingFinished.unsubscribe();
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import { DrawingsWidget } from './widgets/drawings';
|
||||
import { DrawingLineWidget } from './widgets/drawing-line';
|
||||
import { SelectionTool } from './tools/selection-tool';
|
||||
import { MovingTool } from './tools/moving-tool';
|
||||
import {TextEditingTool} from './tools/text-editing-tool';
|
||||
import { LayersWidget } from './widgets/layers';
|
||||
import { LinkWidget } from './widgets/link';
|
||||
import { InterfaceStatusWidget } from './widgets/interface-status';
|
||||
@ -28,6 +29,7 @@ export const D3_MAP_IMPORTS = [
|
||||
DrawingLineWidget,
|
||||
SelectionTool,
|
||||
MovingTool,
|
||||
TextEditingTool,
|
||||
LayersWidget,
|
||||
LinkWidget,
|
||||
InterfaceStatusWidget,
|
||||
|
@ -7,4 +7,5 @@ import { MapDrawing } from "../models/map/map-drawing";
|
||||
export class DrawingsEventSource {
|
||||
public dragged = new EventEmitter<DraggedDataEvent<MapDrawing>>();
|
||||
public resized = new EventEmitter<ResizedDataEvent<MapDrawing>>();
|
||||
public textEdited = new EventEmitter<any>();
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { TextElement } from '../models/drawings/text-element';
|
||||
|
||||
export class DataEventSource<T> {
|
||||
constructor(
|
||||
public datum: T,
|
||||
@ -26,9 +28,10 @@ export class ClickedDataEvent<T> {
|
||||
) {}
|
||||
}
|
||||
|
||||
export class EditedDataEvent {
|
||||
export class TextEditedDataEvent {
|
||||
constructor(
|
||||
public id: string,
|
||||
public editedText: string
|
||||
public textDrawingId: string,
|
||||
public editedText: string,
|
||||
public textElement: TextElement
|
||||
) {}
|
||||
}
|
||||
|
@ -23,9 +23,7 @@ export class SelectionManager {
|
||||
|
||||
this.selection = dictItems;
|
||||
|
||||
if (selected.length > 0) {
|
||||
//console.log(selected);
|
||||
|
||||
if (selected.length > 0) {
|
||||
this.selected.emit(selected);
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ export class SelectionTool {
|
||||
private activate(selection) {
|
||||
const self = this;
|
||||
|
||||
console.log("test!!!", selection);
|
||||
|
||||
selection.on("mousedown", function() {
|
||||
const subject = select(window);
|
||||
const parent = this.parentElement;
|
||||
|
@ -1,18 +1,78 @@
|
||||
import { Injectable, EventEmitter } from "@angular/core";
|
||||
import { SVGSelection } from '../models/types';
|
||||
import { select } from 'd3-selection';
|
||||
import { TextElement } from '../models/drawings/text-element';
|
||||
import { TextEditedDataEvent } from '../events/event-source';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class TextEditingTool {
|
||||
static readonly EDITING_CLASS = '.text-editing';
|
||||
|
||||
private enabled = true;
|
||||
private editingDrawingId: string;
|
||||
private editedElement: any;
|
||||
public editingFinished = new EventEmitter<any>();
|
||||
|
||||
public setEnabled(enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public activate(){
|
||||
public draw(selection: SVGSelection){
|
||||
if (!this.enabled){
|
||||
return;
|
||||
}
|
||||
|
||||
selection.selectAll<SVGTextElement, TextElement>('text.text_element')
|
||||
.on("dblclick", (elem, index, textElements) => {
|
||||
|
||||
this.editedElement = elem;
|
||||
|
||||
select(textElements[index])
|
||||
.attr("visibility", "hidden");
|
||||
|
||||
select(textElements[index])
|
||||
.classed("editingMode", true);
|
||||
|
||||
this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute("drawing_id");
|
||||
//simply get canvas
|
||||
select(textElements[index].parentElement.parentElement.parentElement)
|
||||
.append("foreignObject")
|
||||
.attr("width", '1000px')
|
||||
.attr("min-width", 'fit-content')
|
||||
.attr("height", '100px')
|
||||
.attr("id", "temporaryText")
|
||||
.attr("transform", textElements[index].parentElement.getAttribute("transform"))
|
||||
.append("xhtml:div")
|
||||
.attr("width", "fit-content")
|
||||
.attr("height", "fit-content")
|
||||
.attr("class", "temporaryTextInside")
|
||||
.attr('style', () => {
|
||||
const styles: string[] = [];
|
||||
styles.push(`white-space: pre-line`)
|
||||
styles.push(`outline: 0px solid transparent`)
|
||||
styles.push(`font-family: ${elem.font_family}`)
|
||||
styles.push(`font-size: ${elem.font_size}pt!important`);
|
||||
styles.push(`font-weight: ${elem.font_weight}`)
|
||||
styles.push(`color: ${elem.fill}`);
|
||||
return styles.join("; ");
|
||||
})
|
||||
.attr('text-decoration', elem.text_decoration)
|
||||
.attr('contenteditable', 'true')
|
||||
.text(elem.text)
|
||||
.on("focusout", () => {
|
||||
let temporaryText = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||
let savedText = temporaryText.innerText;
|
||||
this.editingFinished.emit(new TextEditedDataEvent(this.editingDrawingId, savedText, this.editedElement));
|
||||
|
||||
var temporaryElement = document.getElementById("temporaryText") as HTMLElement;
|
||||
temporaryElement.remove();
|
||||
|
||||
selection.selectAll<SVGTextElement, TextElement>('text.editingMode')
|
||||
.attr("visibility", "visible")
|
||||
.classed("editingMode", false);
|
||||
});
|
||||
|
||||
var txtInside = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||
txtInside.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -90,9 +90,7 @@ export class DrawingsWidget implements Widget {
|
||||
if ((datum.element.height + evt.dy) < 0) {
|
||||
isReflectedVertical = true;
|
||||
y = topEdge;
|
||||
console.log(y);
|
||||
datum.element.height = Math.abs(datum.element.height + evt.dy);
|
||||
console.log(datum.element.height);
|
||||
} else {
|
||||
datum.element.height += evt.dy;
|
||||
|
||||
@ -108,9 +106,7 @@ export class DrawingsWidget implements Widget {
|
||||
if ((datum.element.height + dy) < 0){
|
||||
isReflectedVertical = false;
|
||||
y = topEdge;
|
||||
console.log(y);
|
||||
datum.element.height = Math.abs(datum.element.height + evt.dy);
|
||||
console.log(datum.element.height);
|
||||
} else {
|
||||
datum.y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y;
|
||||
datum.element.height += dy;
|
||||
|
@ -27,57 +27,7 @@ export class TextDrawingWidget implements DrawingShapeWidget {
|
||||
const drawing_enter = drawing
|
||||
.enter()
|
||||
.append<SVGTextElement>('text')
|
||||
.attr('class', 'text_element noselect')
|
||||
.on("dblclick", (elem, index, textElements) => {
|
||||
console.log("Id: ", textElements[index].parentElement.parentElement.getAttribute("drawing_id"));
|
||||
|
||||
select(textElements[index])
|
||||
.attr("visibility", "hidden");
|
||||
|
||||
select(textElements[index])
|
||||
.classed("editingMode", true);
|
||||
|
||||
select(textElements[index].parentElement.parentElement.parentElement)
|
||||
.append("foreignObject")
|
||||
.attr("width", '1000px')
|
||||
.attr("min-width", 'fit-content')
|
||||
.attr("height", '100px')
|
||||
.attr("id", "temporaryText")
|
||||
.attr("transform", textElements[index].parentElement.getAttribute("transform"))
|
||||
.append("xhtml:div")
|
||||
.attr("width", "fit-content")
|
||||
.attr("height", "fit-content")
|
||||
.attr("class", "temporaryTextInside")
|
||||
.attr('style', () => {
|
||||
const styles: string[] = [];
|
||||
styles.push(`white-space: pre-line`)
|
||||
styles.push(`outline: 0px solid transparent`)
|
||||
styles.push(`font-family: ${elem.font_family}`)
|
||||
styles.push(`font-size: ${elem.font_size}pt!important`);
|
||||
styles.push(`font-weight: ${elem.font_weight}`)
|
||||
styles.push(`color: ${elem.fill}`);
|
||||
return styles.join("; ");
|
||||
})
|
||||
.attr('text-decoration', elem.text_decoration)
|
||||
.attr('contenteditable', 'true')
|
||||
.text(elem.text)
|
||||
.on("focusout", (elem, index, textElements) => {
|
||||
let temporaryText = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||
let savedText = temporaryText.innerText;
|
||||
|
||||
//let splittedText = savedText.split(/\r?\n/);
|
||||
var temporaryElement = document.getElementById("temporaryText") as HTMLElement;
|
||||
temporaryElement.remove();
|
||||
|
||||
view.selectAll<SVGTextElement, TextElement>('text.editingMode')
|
||||
.attr("visibility", "visible")
|
||||
.classed("editingMode", false)
|
||||
.text(savedText);
|
||||
});
|
||||
|
||||
var txtInside = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||
txtInside.focus();
|
||||
});
|
||||
.attr('class', 'text_element noselect');
|
||||
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
merge
|
||||
|
@ -8,6 +8,7 @@ import { MovingTool } from "../tools/moving-tool";
|
||||
import { LayersWidget } from "./layers";
|
||||
import { LayersManager } from "../managers/layers-manager";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { TextEditingTool } from '../tools/text-editing-tool';
|
||||
|
||||
|
||||
@Injectable()
|
||||
@ -17,6 +18,7 @@ export class GraphLayout implements Widget {
|
||||
private drawingLineTool: DrawingLineWidget,
|
||||
private selectionTool: SelectionTool,
|
||||
private movingTool: MovingTool,
|
||||
private textEditingTool: TextEditingTool,
|
||||
private layersWidget: LayersWidget,
|
||||
private layersManager: LayersManager
|
||||
) {
|
||||
@ -67,6 +69,7 @@ export class GraphLayout implements Widget {
|
||||
this.drawingLineTool.draw(view, context);
|
||||
this.selectionTool.draw(view, context);
|
||||
this.movingTool.draw(view, context);
|
||||
this.textEditingTool.draw(view);
|
||||
}
|
||||
|
||||
disconnect(view: SVGSelection) {
|
||||
|
@ -27,7 +27,7 @@ import { MapChangeDetectorRef } from '../../cartography/services/map-change-dete
|
||||
import { NodeContextMenu } from '../../cartography/events/nodes';
|
||||
import { MapLinkCreated } from '../../cartography/events/links';
|
||||
import { NodeWidget } from '../../cartography/widgets/node';
|
||||
import { DraggedDataEvent, ResizedDataEvent, EditedDataEvent } from '../../cartography/events/event-source';
|
||||
import { DraggedDataEvent, ResizedDataEvent, EditedDataEvent, TextEditedDataEvent } from '../../cartography/events/event-source';
|
||||
import { DrawingService } from '../../services/drawing.service';
|
||||
import { MapNodeToNodeConverter } from '../../cartography/converters/map/map-node-to-node-converter';
|
||||
import { NodesEventSource } from '../../cartography/events/nodes-event-source';
|
||||
@ -195,6 +195,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
this.drawingsEventSource.resized.subscribe((evt) => this.onDrawingResized(evt))
|
||||
);
|
||||
|
||||
this.subscriptions.push(
|
||||
this.drawingsEventSource.textEdited.subscribe((evt) => this.onTextEdited(evt))
|
||||
);
|
||||
|
||||
this.subscriptions.push(
|
||||
this.linksEventSource.created.subscribe((evt) => this.onLinkCreated(evt))
|
||||
);
|
||||
@ -348,8 +352,21 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
public onDrawingEdited(editedEvent: EditedDataEvent){
|
||||
public onTextEdited(evt: TextEditedDataEvent){
|
||||
//<svg height=\"100\" width=\"100\"><text fill=\"#000000\" fill-opacity=\"0\" font-family=\"Noto Sans\" font-size=\"11\" font-weight=\"bold\">this is one another text\nto save\n</text></svg>
|
||||
//let splittedText = evt.editedText.split(/\r?\n/);
|
||||
let mapDrawing: MapDrawing = new MapDrawing();
|
||||
mapDrawing.element = evt.textElement;
|
||||
(mapDrawing.element as TextElement).text = evt.editedText;
|
||||
let svgString = this.mapDrawingToSvgConverter.convert(mapDrawing);
|
||||
|
||||
let drawing = this.drawingsDataSource.get(evt.textDrawingId);
|
||||
|
||||
this.drawingService
|
||||
.updateText(this.server, drawing, svgString)
|
||||
.subscribe((serverDrawing: Drawing) => {
|
||||
this.drawingsDataSource.update(serverDrawing);
|
||||
});
|
||||
}
|
||||
|
||||
public set readonly(value) {
|
||||
|
@ -38,6 +38,16 @@ export class DrawingService {
|
||||
})
|
||||
}
|
||||
|
||||
updateText(server: Server, drawing: Drawing, svg: string): Observable<Drawing> {
|
||||
return this.httpServer
|
||||
.put<Drawing>(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, {
|
||||
'svg': svg,
|
||||
'x': drawing.x,
|
||||
'y': drawing.y,
|
||||
'z': drawing.z
|
||||
});
|
||||
}
|
||||
|
||||
update(server: Server, drawing: Drawing): Observable<Drawing> {
|
||||
return this.httpServer
|
||||
.put<Drawing>(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, {
|
||||
|
Loading…
x
Reference in New Issue
Block a user