mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 14:47:56 +01:00
Migration start of the mindplot module
This commit is contained in:
parent
3ca7840dcf
commit
cbc461e760
@ -25,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/styled-components": "^5.1.4",
|
"@types/styled-components": "^5.1.4",
|
||||||
|
"@wismapping/core-js": "^0.0.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"styled-components": "^5.2.1"
|
"styled-components": "^5.2.1"
|
||||||
|
@ -20,8 +20,8 @@ const core = Core();
|
|||||||
const web2D = require('@wismapping/web2d');
|
const web2D = require('@wismapping/web2d');
|
||||||
const web2d = web2D();
|
const web2d = web2D();
|
||||||
|
|
||||||
const INodeModel,
|
const INodeModel = require('./model/INodeModel').default;
|
||||||
{ TopicShape } = require('./model/INodeModel').default;
|
const { TopicShape } = require('./model/INodeModel').default;
|
||||||
const Topic = require('./Topic').default;
|
const Topic = require('./Topic').default;
|
||||||
|
|
||||||
const ConnectionLine = new Class({
|
const ConnectionLine = new Class({
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
const Events = new Class({
|
const Events = new Class({
|
||||||
|
|
||||||
$events: {},
|
$events: {},
|
||||||
|
|
||||||
_removeOn: function (string) {
|
_removeOn: function (string) {
|
||||||
@ -20,11 +19,15 @@ const Events = new Class({
|
|||||||
type = this._removeOn(type);
|
type = this._removeOn(type);
|
||||||
var events = this.$events[type];
|
var events = this.$events[type];
|
||||||
if (!events) return this;
|
if (!events) return this;
|
||||||
args = Array.from(args);
|
args = Array.isArray(args) ? args : [args];
|
||||||
_.each(events, function (fn) {
|
_.each(
|
||||||
if (delay) fn.delay(delay, this, args);
|
events,
|
||||||
else fn.apply(this, args);
|
function (fn) {
|
||||||
}, this);
|
if (delay) fn.delay(delay, this, args);
|
||||||
|
else fn.apply(this, args);
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -36,8 +39,7 @@ const Events = new Class({
|
|||||||
if (index != -1) events.splice(index, 1);
|
if (index != -1) events.splice(index, 1);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Events;
|
export default Events;
|
||||||
|
@ -15,180 +15,177 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const Topic = require('./Topic').default
|
const Topic = require('./Topic').default;
|
||||||
const DragTopic = require('./DragTopic').default;
|
const DragTopic = require('./DragTopic').default;
|
||||||
const INodeModel = require('./model/INodeModel').default;
|
const INodeModel = require('./model/INodeModel').default;
|
||||||
const CentralTopic = require('./CentralTopic').default;
|
|
||||||
const MainTopic = require('./MainTopic').default;
|
|
||||||
|
|
||||||
const NodeGraph = new Class(/** @lends NodeGraph */{
|
const NodeGraph = new Class(
|
||||||
/**
|
/** @lends NodeGraph */ {
|
||||||
* @constructs
|
/**
|
||||||
* @param {mindplot.model.NodeModel} nodeModel
|
* @constructs
|
||||||
* @param {Object<Number, String, Boolean>} options
|
* @param {mindplot.model.NodeModel} nodeModel
|
||||||
* @throws will throw an error if nodeModel is null or undefined
|
* @param {Object<Number, String, Boolean>} options
|
||||||
*/
|
* @throws will throw an error if nodeModel is null or undefined
|
||||||
initialize: function (nodeModel, options) {
|
*/
|
||||||
$assert(nodeModel, "model can not be null");
|
initialize: function (nodeModel, options) {
|
||||||
|
$assert(nodeModel, 'model can not be null');
|
||||||
|
|
||||||
this._options = options;
|
this._options = options;
|
||||||
this._mouseEvents = true;
|
this._mouseEvents = true;
|
||||||
this.setModel(nodeModel);
|
this.setModel(nodeModel);
|
||||||
this._onFocus = false;
|
this._onFocus = false;
|
||||||
this._size = {width: 50, height: 20};
|
this._size = { width: 50, height: 20 };
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @return true if option is set to read-only */
|
/** @return true if option is set to read-only */
|
||||||
isReadOnly: function () {
|
isReadOnly: function () {
|
||||||
return this._options.readOnly;
|
return this._options.readOnly;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @return model type */
|
/** @return model type */
|
||||||
getType: function () {
|
getType: function () {
|
||||||
var model = this.getModel();
|
var model = this.getModel();
|
||||||
return model.getType();
|
return model.getType();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} id
|
* @param {String} id
|
||||||
* @throws will throw an error if the topic id is not a number
|
* @throws will throw an error if the topic id is not a number
|
||||||
*/
|
*/
|
||||||
setId: function (id) {
|
setId: function (id) {
|
||||||
$assert(typeof topic.getId() == "number", "id is not a number:" + id);
|
$assert(typeof topic.getId() == 'number', 'id is not a number:' + id);
|
||||||
this.getModel().setId(id);
|
this.getModel().setId(id);
|
||||||
},
|
},
|
||||||
|
|
||||||
_set2DElement: function (elem2d) {
|
_set2DElement: function (elem2d) {
|
||||||
this._elem2d = elem2d;
|
this._elem2d = elem2d;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 2D element
|
* @return 2D element
|
||||||
* @throws will throw an error if the element is null or undefined within node graph
|
* @throws will throw an error if the element is null or undefined within node graph
|
||||||
*/
|
*/
|
||||||
get2DElement: function () {
|
get2DElement: function () {
|
||||||
$assert(this._elem2d, 'NodeGraph has not been initialized properly');
|
$assert(this._elem2d, 'NodeGraph has not been initialized properly');
|
||||||
return this._elem2d;
|
return this._elem2d;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @abstract */
|
/** @abstract */
|
||||||
setPosition: function (point, fireEvent) {
|
setPosition: function (point, fireEvent) {
|
||||||
throw "Unsupported operation";
|
throw 'Unsupported operation';
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
addEvent: function (type, listener) {
|
addEvent: function (type, listener) {
|
||||||
var elem = this.get2DElement();
|
var elem = this.get2DElement();
|
||||||
elem.addEvent(type, listener);
|
elem.addEvent(type, listener);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
removeEvent: function (type, listener) {
|
removeEvent: function (type, listener) {
|
||||||
var elem = this.get2DElement();
|
var elem = this.get2DElement();
|
||||||
elem.removeEvent(type, listener);
|
elem.removeEvent(type, listener);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
fireEvent: function (type, event) {
|
fireEvent: function (type, event) {
|
||||||
var elem = this.get2DElement();
|
var elem = this.get2DElement();
|
||||||
elem.trigger(type, event);
|
elem.trigger(type, event);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
setMouseEventsEnabled: function (isEnabled) {
|
setMouseEventsEnabled: function (isEnabled) {
|
||||||
this._mouseEvents = isEnabled;
|
this._mouseEvents = isEnabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
isMouseEventsEnabled: function () {
|
isMouseEventsEnabled: function () {
|
||||||
return this._mouseEvents;
|
return this._mouseEvents;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @return {Object<Number>} size*/
|
/** @return {Object<Number>} size*/
|
||||||
getSize: function () {
|
getSize: function () {
|
||||||
return this._size;
|
return this._size;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @param {Object<Number>} size*/
|
/** @param {Object<Number>} size*/
|
||||||
setSize: function (size) {
|
setSize: function (size) {
|
||||||
this._size.width = parseInt(size.width);
|
this._size.width = parseInt(size.width);
|
||||||
this._size.height = parseInt(size.height);
|
this._size.height = parseInt(size.height);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {mindplot.model.NodeModel} the node model
|
* @return {mindplot.model.NodeModel} the node model
|
||||||
*/
|
*/
|
||||||
getModel: function () {
|
getModel: function () {
|
||||||
$assert(this._model, 'Model has not been initialized yet');
|
$assert(this._model, 'Model has not been initialized yet');
|
||||||
return this._model;
|
return this._model;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {mindplot.NodeModel} model the node model
|
* @param {mindplot.NodeModel} model the node model
|
||||||
* @throws will throw an error if model is null or undefined
|
* @throws will throw an error if model is null or undefined
|
||||||
*/
|
*/
|
||||||
setModel: function (model) {
|
setModel: function (model) {
|
||||||
$assert(model, 'Model can not be null');
|
$assert(model, 'Model can not be null');
|
||||||
this._model = model;
|
this._model = model;
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
getId: function () {
|
getId: function () {
|
||||||
return this._model.getId();
|
return this._model.getId();
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
setOnFocus: function (focus) {
|
setOnFocus: function (focus) {
|
||||||
if (this._onFocus != focus) {
|
if (this._onFocus != focus) {
|
||||||
|
this._onFocus = focus;
|
||||||
|
var outerShape = this.getOuterShape();
|
||||||
|
if (focus) {
|
||||||
|
outerShape.setFill(Topic.OUTER_SHAPE_ATTRIBUTES_FOCUS.fillColor);
|
||||||
|
outerShape.setOpacity(1);
|
||||||
|
} else {
|
||||||
|
outerShape.setFill(Topic.OUTER_SHAPE_ATTRIBUTES.fillColor);
|
||||||
|
outerShape.setOpacity(0);
|
||||||
|
}
|
||||||
|
this.setCursor('move');
|
||||||
|
|
||||||
this._onFocus = focus;
|
// In any case, always try to hide the editor ...
|
||||||
var outerShape = this.getOuterShape();
|
this.closeEditors();
|
||||||
if (focus) {
|
|
||||||
outerShape.setFill(Topic.OUTER_SHAPE_ATTRIBUTES_FOCUS.fillColor);
|
|
||||||
outerShape.setOpacity(1);
|
|
||||||
|
|
||||||
} else {
|
// Fire event ...
|
||||||
outerShape.setFill(Topic.OUTER_SHAPE_ATTRIBUTES.fillColor);
|
this.fireEvent(focus ? 'ontfocus' : 'ontblur', this);
|
||||||
outerShape.setOpacity(0);
|
|
||||||
}
|
}
|
||||||
this.setCursor('move');
|
},
|
||||||
|
|
||||||
// In any case, always try to hide the editor ...
|
/** @return {Boolean} true if the node graph is on focus */
|
||||||
this.closeEditors();
|
isOnFocus: function () {
|
||||||
|
return this._onFocus;
|
||||||
|
},
|
||||||
|
|
||||||
// Fire event ...
|
/** */
|
||||||
this.fireEvent(focus ? 'ontfocus' : 'ontblur', this);
|
dispose: function (workspace) {
|
||||||
|
this.setOnFocus(false);
|
||||||
|
workspace.removeChild(this);
|
||||||
|
},
|
||||||
|
|
||||||
}
|
/** */
|
||||||
},
|
createDragNode: function (layoutManager) {
|
||||||
|
var dragShape = this._buildDragShape();
|
||||||
|
return new DragTopic(dragShape, this, layoutManager);
|
||||||
|
},
|
||||||
|
|
||||||
/** @return {Boolean} true if the node graph is on focus */
|
_buildDragShape: function () {
|
||||||
isOnFocus: function () {
|
$assert(false, '_buildDragShape must be implemented by all nodes.');
|
||||||
return this._onFocus;
|
},
|
||||||
},
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
dispose: function (workspace) {
|
getPosition: function () {
|
||||||
this.setOnFocus(false);
|
var model = this.getModel();
|
||||||
workspace.removeChild(this);
|
return model.getPosition();
|
||||||
},
|
},
|
||||||
|
|
||||||
/** */
|
|
||||||
createDragNode: function (layoutManager) {
|
|
||||||
var dragShape = this._buildDragShape();
|
|
||||||
return new DragTopic(dragShape, this, layoutManager);
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildDragShape: function () {
|
|
||||||
$assert(false, '_buildDragShape must be implemented by all nodes.');
|
|
||||||
},
|
|
||||||
|
|
||||||
/** */
|
|
||||||
getPosition: function () {
|
|
||||||
var model = this.getModel();
|
|
||||||
return model.getPosition();
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a new topic from the given node model
|
* creates a new topic from the given node model
|
||||||
@ -202,6 +199,8 @@ const NodeGraph = new Class(/** @lends NodeGraph */{
|
|||||||
* @return {mindplot.CentralTopic|mindplot.MainTopic} the new topic
|
* @return {mindplot.CentralTopic|mindplot.MainTopic} the new topic
|
||||||
*/
|
*/
|
||||||
NodeGraph.create = function (nodeModel, options) {
|
NodeGraph.create = function (nodeModel, options) {
|
||||||
|
const CentralTopic = require('./CentralTopic').default;
|
||||||
|
const MainTopic = require('./MainTopic').default;
|
||||||
$assert(nodeModel, 'Model can not be null');
|
$assert(nodeModel, 'Model can not be null');
|
||||||
|
|
||||||
var type = nodeModel.getType();
|
var type = nodeModel.getType();
|
||||||
@ -213,7 +212,7 @@ NodeGraph.create = function (nodeModel, options) {
|
|||||||
} else if (type == INodeModel.MAIN_TOPIC_TYPE) {
|
} else if (type == INodeModel.MAIN_TOPIC_TYPE) {
|
||||||
result = new MainTopic(nodeModel, options);
|
result = new MainTopic(nodeModel, options);
|
||||||
} else {
|
} else {
|
||||||
$assert(false, "unsupported node type:" + type);
|
$assert(false, 'unsupported node type:' + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
21
packages/mindplot/lib/components/commands/index.js
Normal file
21
packages/mindplot/lib/components/commands/index.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const addFeatureToTopicCommand = require('./AddFeatureToTopicCommand').default;
|
||||||
|
const addRelationshipCommand = require('./AddRelationshipCommand').default;
|
||||||
|
const addTopicCommand = require('./AddTopicCommand').default;
|
||||||
|
const changeFeatureToTopicCommand = require('./ChangeFeatureToTopicCommand').default;
|
||||||
|
const deleteCommand = require('./DeleteCommand').default;
|
||||||
|
const dragTopicCommand = require('./DragTopicCommand').default;
|
||||||
|
const genericFunctionCommand = require('./GenericFunctionCommand').default;
|
||||||
|
const moveControlPointCommand = require('./MoveControlPointCommand').default;
|
||||||
|
const removeFeatureFromTopicCommand = require('./RemoveFeatureFromTopicCommand').default;
|
||||||
|
|
||||||
|
export const Commands = {
|
||||||
|
AddFeatureToTopicCommand: addFeatureToTopicCommand,
|
||||||
|
AddRelationshipCommand: addRelationshipCommand,
|
||||||
|
AddTopicCommand: addTopicCommand,
|
||||||
|
ChangeFeatureToTopicCommand: changeFeatureToTopicCommand,
|
||||||
|
DeleteCommand: deleteCommand,
|
||||||
|
DragTopicCommand: dragTopicCommand,
|
||||||
|
GenericFunctionCommand: genericFunctionCommand,
|
||||||
|
MoveControlPointCommand: moveControlPointCommand,
|
||||||
|
RemoveFeatureFromTopicCommand: removeFeatureFromTopicCommand,
|
||||||
|
};
|
108
packages/mindplot/lib/components/index.js
Normal file
108
packages/mindplot/lib/components/index.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
const acitonDispatcher = require('./ActionDispatcher').default;
|
||||||
|
const actionIcon = require('./ActionIcon').default;
|
||||||
|
const centralTopic = require('./CentralTopic').default;
|
||||||
|
const command = require('./Command').default;
|
||||||
|
const connectionLine = require('./ConnectionLine').default;
|
||||||
|
const controlPoint = require('./ControlPoint').default;
|
||||||
|
const designer = require('./Designer').default;
|
||||||
|
const designerAcitonRun = require('./DesignerActionRunner').default;
|
||||||
|
const designerKeyboard = require('./DesignerKeyboard').default;
|
||||||
|
const desginerModel = require('./DesignerModel').default;
|
||||||
|
const desginerUndoManager = require('./DesignerUndoManager').default;
|
||||||
|
const dragConnector = require('./DragConnector').default;
|
||||||
|
const dragManager = require('./DragManager').default;
|
||||||
|
const dragPivot = require('./DragPivot').default;
|
||||||
|
const dragTopic = require('./DragTopic').default;
|
||||||
|
const editorOptions = require('./EditorOptions').default;
|
||||||
|
const editorProperties = require('./EditorProperties').default;
|
||||||
|
const events = require('./Events').default;
|
||||||
|
const footer = require('./footer');
|
||||||
|
//const header =require('./header');
|
||||||
|
const icon = require('./Icon').default;
|
||||||
|
const iconGroup = require('./IconGroup').default;
|
||||||
|
const imageIcon = require('./ImageIcon').default;
|
||||||
|
const keyboard = require('./Keyboard').default;
|
||||||
|
const linkIcon = require('./LinkIcon').default;
|
||||||
|
const localStorageManager = require('./LocalStorageManager').default;
|
||||||
|
const mainTopic = require('./MainTopic').default;
|
||||||
|
const messages = require('./Messages').default;
|
||||||
|
const messageBundle_ca = require('./MessageBundle_ca').default;
|
||||||
|
const messageBundle_de = require('./MessageBundle_de').default;
|
||||||
|
const messageBundle_en = require('./MessageBundle_en').default;
|
||||||
|
const messageBundle_es = require('./MessageBundle_es').default;
|
||||||
|
const messageBundle_fr = require('./MessageBundle_fr').default;
|
||||||
|
const messageBundle_pt_BR = require('./MessageBundle_pt_BR').default;
|
||||||
|
const messageBundle_zh_CN = require('./MessageBundle_zh_CN').default;
|
||||||
|
const messageBundle_zh_TW = require('./MessageBundle_zh_TW').default;
|
||||||
|
const multilineTextEditor = require('./MultilineTextEditor').default;
|
||||||
|
const nodeGraph = require('./NodeGraph').default;
|
||||||
|
const noteIcon = require('./NoteIcon').default;
|
||||||
|
const options = require('./Options').default;
|
||||||
|
const persistenceManger = require('./PersistenceManager').default;
|
||||||
|
const relationship = require('./Relationship').default;
|
||||||
|
const relationshipPivot = require('./RelationshipPivot').default;
|
||||||
|
const restPersistenceManager = require('./RestPersistenceManager').default;
|
||||||
|
const screenManager = require('./ScreenManager').default;
|
||||||
|
const shrinkConnector = require('./ShrinkConnector').default;
|
||||||
|
const standaloneActionDispatcher = require('./StandaloneActionDispatcher').default;
|
||||||
|
const textEditor = require('./TextEditor').default;
|
||||||
|
//const textEditorFacotry = require('./TextEditorFactory').default;
|
||||||
|
const topic = require('./Topic').default;
|
||||||
|
const topicEventDispatcher = require('./TopicEventDispatcher').default;
|
||||||
|
const topicFeature = require('./TopicFeature').default;
|
||||||
|
const topicStyle = require('./TopicStyle').default;
|
||||||
|
const workspace = require('./Workspace').default;
|
||||||
|
|
||||||
|
export const Components = {
|
||||||
|
ActionDispatcher: acitonDispatcher,
|
||||||
|
ActionIcon: actionIcon,
|
||||||
|
CentralTopic: centralTopic,
|
||||||
|
Command: command,
|
||||||
|
ConnectionLine: connectionLine,
|
||||||
|
ControlPoint: controlPoint,
|
||||||
|
Designer: designer,
|
||||||
|
DesignerActionRunner: designerAcitonRun,
|
||||||
|
DesignerKeyboard: designerKeyboard,
|
||||||
|
DesignerModel: desginerModel,
|
||||||
|
DesignerUndoManager: desginerUndoManager,
|
||||||
|
DragConnector: dragConnector,
|
||||||
|
DragManager: dragManager,
|
||||||
|
DragPivot: dragPivot,
|
||||||
|
DragTopic: dragTopic,
|
||||||
|
EditorOptions: editorOptions,
|
||||||
|
EditorProperties: editorProperties,
|
||||||
|
Events: events,
|
||||||
|
Icon: icon,
|
||||||
|
IconGroup: iconGroup,
|
||||||
|
ImageIcon: imageIcon,
|
||||||
|
Keyboard: keyboard,
|
||||||
|
LinkIcon: linkIcon,
|
||||||
|
LocalStorageManager: localStorageManager,
|
||||||
|
MainTopic: mainTopic,
|
||||||
|
MessageBundle_ca: messageBundle_ca,
|
||||||
|
MessageBundle_de: messageBundle_de,
|
||||||
|
MessageBundle_en: messageBundle_en,
|
||||||
|
MessageBundle_es: messageBundle_es,
|
||||||
|
MesasgeBundle_fr: messageBundle_fr,
|
||||||
|
MessageBundle_pt_BR: messageBundle_pt_BR,
|
||||||
|
MessageBundle_zh_CN: messageBundle_zh_CN,
|
||||||
|
MessageBundle_zh_TW: messageBundle_zh_TW,
|
||||||
|
Messages: messages,
|
||||||
|
MultilineTextEditor: multilineTextEditor,
|
||||||
|
NodeGraph: nodeGraph,
|
||||||
|
NoteIcon: noteIcon,
|
||||||
|
Options: options,
|
||||||
|
PersistenceManager: persistenceManger,
|
||||||
|
Relationship: relationship,
|
||||||
|
RelationshipPivot: relationshipPivot,
|
||||||
|
RestPersistenceManager: restPersistenceManager,
|
||||||
|
ScreenManager: screenManager,
|
||||||
|
StandaloneActionDispatcher: standaloneActionDispatcher,
|
||||||
|
TextEditor: textEditor,
|
||||||
|
//TextEditorFactory: textEditorFacotry,
|
||||||
|
Topic: topic,
|
||||||
|
TopicEventDispatcher: topicEventDispatcher,
|
||||||
|
TopicFeature: topicFeature,
|
||||||
|
TopicStyle: topicStyle,
|
||||||
|
Workspace: workspace,
|
||||||
|
};
|
27
packages/mindplot/lib/components/layout/index.js
Normal file
27
packages/mindplot/lib/components/layout/index.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const abstractBasicSorter = require('./AbstractBasicSorter').default;
|
||||||
|
const balancedSorter = require('./BalancedSorter').default;
|
||||||
|
const changeEvent = require('./ChangeEvent').default;
|
||||||
|
const childrenSorterStrategy = require('./ChildrenSorterStrategy').default;
|
||||||
|
const eventBus = require('./EventBus').default;
|
||||||
|
const eventBusDispatcher = require('./EventBusDispatcher').default;
|
||||||
|
const gridSorter = require('./GridSorter').default;
|
||||||
|
const layoutManager = require('./LayoutManager').default;
|
||||||
|
const node = require('./Node').default;
|
||||||
|
const originalLayout = require('./OriginalLayout').default;
|
||||||
|
const rootedTreeSet = require('./RootedTreeSet').default;
|
||||||
|
const symmetricSorter = require('./SymmetricSorter').default;
|
||||||
|
|
||||||
|
export const Layout = {
|
||||||
|
AbstractBasicSorter: abstractBasicSorter,
|
||||||
|
BalancedSorter: balancedSorter,
|
||||||
|
ChangeEvent: changeEvent,
|
||||||
|
ChildrenSorterStrategy: childrenSorterStrategy,
|
||||||
|
EventBus: eventBus,
|
||||||
|
EventBusDispatcher: eventBusDispatcher,
|
||||||
|
GridSorter: gridSorter,
|
||||||
|
LayoutManager: layoutManager,
|
||||||
|
Node: node,
|
||||||
|
OriginalLayout: originalLayout,
|
||||||
|
RootedTreeSet: rootedTreeSet,
|
||||||
|
SymmetricSorter: symmetricSorter,
|
||||||
|
};
|
21
packages/mindplot/lib/components/model/index.js
Normal file
21
packages/mindplot/lib/components/model/index.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const featureModel = require('./FeatureModel').default;
|
||||||
|
const iconModel = require('./IconModel').default;
|
||||||
|
const imindmap = require('./IMindmap').default;
|
||||||
|
const inodeModel = require('./INodeModel').default;
|
||||||
|
const linkModel = require('./LinkModel').default;
|
||||||
|
const mindmap = require('./Mindmap').default;
|
||||||
|
const nodeModel = require('./NodeModel').default;
|
||||||
|
const noteModel = require('./NoteModel').default;
|
||||||
|
const relationshipModel = require('./RelationshipModel').default;
|
||||||
|
|
||||||
|
export const Models = {
|
||||||
|
FeatureModel: featureModel,
|
||||||
|
IconModel: iconModel,
|
||||||
|
IMindmap: imindmap,
|
||||||
|
INodeModel: inodeModel,
|
||||||
|
LinkModel: linkModel,
|
||||||
|
Mindmap: mindmap,
|
||||||
|
NodeModel: nodeModel,
|
||||||
|
NoteModel: noteModel,
|
||||||
|
RelationshipModel: relationshipModel,
|
||||||
|
};
|
17
packages/mindplot/lib/components/persistence/index.js
Normal file
17
packages/mindplot/lib/components/persistence/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const beta2PelaMigrator = require('./Beta2PelaMigrator').default;
|
||||||
|
const modelCodeName = require('./ModelCodeName').default;
|
||||||
|
const pela2TangoMigrator = require('./Pela2TangoMigrator').default;
|
||||||
|
const xmlSerializer_Beta = require('./XMLSerializer_Beta').default;
|
||||||
|
const xmlSerializer_Pela = require('./XMLSerializer_Pela').default;
|
||||||
|
const xmlSerializer_Tango = require('./XMLSerializer_Tango').default;
|
||||||
|
const xmlSerializerFactory = require('./XMLSerializerFactory').default;
|
||||||
|
|
||||||
|
export const Persistence = {
|
||||||
|
Beta2PelaMigrator: beta2PelaMigrator,
|
||||||
|
ModelCodeName: modelCodeName,
|
||||||
|
Pela2TangoMigrator: pela2TangoMigrator,
|
||||||
|
XMLSerializer_Beta: xmlSerializer_Beta,
|
||||||
|
XMLSerializer_Pela: xmlSerializer_Pela,
|
||||||
|
XMLSerializer_Tango: xmlSerializer_Tango,
|
||||||
|
XMLSerializerFactory: xmlSerializerFactory,
|
||||||
|
};
|
37
packages/mindplot/lib/components/widget/index.js
Normal file
37
packages/mindplot/lib/components/widget/index.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const colorPalettePanel = require('./ColorPalettePanel').default;
|
||||||
|
const floatingTip = require('./FloatingTip').default;
|
||||||
|
const fontFamilyPanel = require('./FontFamilyPanel').default;
|
||||||
|
const fontSizePanel = require('./FontSizePanel').default;
|
||||||
|
const iconPanel = require('./IconPanel').default;
|
||||||
|
const imenu = require('./IMenu').default;
|
||||||
|
const keyboardShortcutTooltip = require('./KeyboardShortcutTooltip').default;
|
||||||
|
const linkEditor = require('./LinkEditor').default;
|
||||||
|
const linkIconTooltip = require('./LinkIconTooltip').default;
|
||||||
|
const listToolbarPanel = require('./ListToolbarPanel').default;
|
||||||
|
const menu = require('./Menu').default;
|
||||||
|
const modalDialogNotifier = require('./ModalDialogNotifier');
|
||||||
|
const noteEditor = require('./NoteEditor');
|
||||||
|
const toolbarItem = require('./ToolbarItem');
|
||||||
|
const toolbarNotifier = require('./ToolbarNotifier');
|
||||||
|
const toolbarPanelItem = require('./ToolbarPaneItem');
|
||||||
|
const topicShapePanel = require('./TopicShapePanel');
|
||||||
|
|
||||||
|
export const Widgets = {
|
||||||
|
ColorPalettePanel: colorPalettePanel,
|
||||||
|
FloatingTip: floatingTip,
|
||||||
|
FontFamilyPanel: fontFamilyPanel,
|
||||||
|
FontSizePanel: fontSizePanel,
|
||||||
|
IconPanel: iconPanel,
|
||||||
|
Imenu: imenu,
|
||||||
|
KeyboardShortcutTooltip: keyboardShortcutTooltip,
|
||||||
|
LinkEditor: linkEditor,
|
||||||
|
LinkIconTooltip: linkIconTooltip,
|
||||||
|
ListToolbarPanel: listToolbarPanel,
|
||||||
|
Menu: menu,
|
||||||
|
ModalDialogNotifier: modalDialogNotifier,
|
||||||
|
NoteEditor: noteEditor,
|
||||||
|
ToolbarItem: toolbarItem,
|
||||||
|
ToolbarNotifier: toolbarNotifier,
|
||||||
|
ToolbarPaneItem: toolbarPanelItem,
|
||||||
|
TopicShapePanel: topicShapePanel,
|
||||||
|
};
|
@ -3,59 +3,29 @@ module.exports = mindplot; //eslint-disable-line
|
|||||||
|
|
||||||
function mindplot() {
|
function mindplot() {
|
||||||
// Commands
|
// Commands
|
||||||
const addFeatureToTopicCommand = require('./components/commands/AddFeatureToTopicCommand')
|
const { Commands } = require('./components/commands');
|
||||||
.default;
|
|
||||||
const addRelationshipCommand = require('./components/commands/AddRelationshipCommand').default;
|
|
||||||
const addTopicCommand = require('./components/commands/AddTopicCommand').default;
|
|
||||||
const changeFeatureToTopicCommand = require('./components/commands/ChangeFeatureToTopicCommand')
|
|
||||||
.default;
|
|
||||||
const deleteCommand = require('./components/commands/DeleteCommand').default;
|
|
||||||
const dragTopicCommand = require('./components/commands/DragTopicCommand').default;
|
|
||||||
const genericFunctionCommand = require('./components/commands/GenericFunctionCommand').default;
|
|
||||||
const moveControlPointCommand = require('./components/commands/MoveControlPointCommand')
|
|
||||||
.default;
|
|
||||||
const removeFeatureFromTopicCommand = require('./components/commands/RemoveFeatureFromTopicCommand')
|
|
||||||
.default;
|
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
const abstractBasicSorter = require('./components/layout/AbstractBasicSorter').default;
|
const { Layout } = require('./components/layout');
|
||||||
const balancedSorter = require('./components/layout/BalancedSorter').default;
|
|
||||||
const changeEvent = require('./components/layout/ChangeEvent').default;
|
// Model
|
||||||
const childrenSorterStrategy = require('./components/layout/ChildrenSorterStrategy').default;
|
const { Models } = require('./components/model');
|
||||||
const eventBus = require('./components/layout/EventBus').default;
|
|
||||||
const eventBusDispatcher = require('./components/layout/EventBusDispatcher').default;
|
// Persistence
|
||||||
const gridSorter = require('./components/layout/GridSorter').default;
|
const { Persistence } = require('./components/persistence');
|
||||||
const layoutManager = require('./components/layout/LayoutManager').default;
|
|
||||||
const node = require('./components/layout/Node').default;
|
// Widgets
|
||||||
const originalLayout = require('./components/layout/OriginalLayout').default;
|
const { Widgets } = require('./components/widget');
|
||||||
const rootedTreeSet = require('./components/layout/RootedTreeSet').default;
|
|
||||||
const symmetricSorter = require('./components/layout/SymmetricSorter').default;
|
// Commponents
|
||||||
|
const { Components } = require('./components');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Commands: {
|
Commands,
|
||||||
AddFeatureToTopicCommand: addFeatureToTopicCommand,
|
Layout,
|
||||||
AddRelationshipCommand: addRelationshipCommand,
|
Models,
|
||||||
AddTopicCommand: addTopicCommand,
|
Persistence,
|
||||||
ChangeFeatureToTopicCommand: changeFeatureToTopicCommand,
|
Widgets,
|
||||||
DeleteCommand: deleteCommand,
|
Components,
|
||||||
DragTopicCommand: dragTopicCommand,
|
|
||||||
GenericFunctionCommand: genericFunctionCommand,
|
|
||||||
MoveControlPointCommand: moveControlPointCommand,
|
|
||||||
RemoveFeatureFromTopicCommand: removeFeatureFromTopicCommand,
|
|
||||||
},
|
|
||||||
Layout: {
|
|
||||||
AbstractBasicSorter: abstractBasicSorter,
|
|
||||||
BalancedSorter: balancedSorter,
|
|
||||||
ChangeEvent: changeEvent,
|
|
||||||
ChildrenSorterStrategy: childrenSorterStrategy,
|
|
||||||
EventBus: eventBus,
|
|
||||||
EventBusDispatcher: eventBusDispatcher,
|
|
||||||
GridSorter: gridSorter,
|
|
||||||
LayoutManager: layoutManager,
|
|
||||||
Node: node,
|
|
||||||
OriginalLayout: originalLayout,
|
|
||||||
RootedTreeSet: rootedTreeSet,
|
|
||||||
SymmetricSorter: symmetricSorter,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wismapping/core-js": "^0.0.1",
|
"@wismapping/core-js": "^0.0.1",
|
||||||
"@wismapping/web2d": "^0.0.1",
|
"@wismapping/web2d": "^0.0.1"
|
||||||
"mootools": "^1.5.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.14.6",
|
||||||
|
16
packages/mindplot/test/javascript/static/test/testPalette.js
Normal file
16
packages/mindplot/test/javascript/static/test/testPalette.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const Mindplot = require('../../../../lib/mindplot');
|
||||||
|
const mindplot = Mindplot();
|
||||||
|
|
||||||
|
window.addEventListener('load', function (e) {
|
||||||
|
var model = {
|
||||||
|
getValue: function () {},
|
||||||
|
setValue: function (value) {
|
||||||
|
console.log('value:' + value);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var palette = new mindplot.widget.ColorPalettePanel(
|
||||||
|
'myButton',
|
||||||
|
model,
|
||||||
|
'/mindplot/src/main/javascript/widget'
|
||||||
|
);
|
||||||
|
});
|
29
packages/mindplot/webpack.test.js
Normal file
29
packages/mindplot/webpack.test.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
|
||||||
|
/** @type {import('webpack').Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
entry: './lib/mindplot',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist', 'test'),
|
||||||
|
filename: '[name].js',
|
||||||
|
publicPath: '',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
use: 'babel-loader',
|
||||||
|
test: /.(js|jsx)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'asset',
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.json'],
|
||||||
|
},
|
||||||
|
plugins: [new CleanWebpackPlugin()],
|
||||||
|
};
|
@ -53,6 +53,7 @@
|
|||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||||
"@reduxjs/toolkit": "^1.5.0",
|
"@reduxjs/toolkit": "^1.5.0",
|
||||||
|
"@wismapping/core-js": "^0.0.1",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
|
0
packages/webcomponent/.gitignore
vendored
Normal file
0
packages/webcomponent/.gitignore
vendored
Normal file
11
packages/webcomponent/README.md
Normal file
11
packages/webcomponent/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# `webcomponent`
|
||||||
|
|
||||||
|
> TODO: description
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
const webcomponent = require('webcomponent');
|
||||||
|
|
||||||
|
// TODO: DEMONSTRATE API
|
||||||
|
```
|
7
packages/webcomponent/__tests__/webcomponent.test.js
Normal file
7
packages/webcomponent/__tests__/webcomponent.test.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const webcomponent = require('..');
|
||||||
|
|
||||||
|
describe('webcomponent', () => {
|
||||||
|
it('needs tests');
|
||||||
|
});
|
50
packages/webcomponent/package.json
Normal file
50
packages/webcomponent/package.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "webcomponent",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "webcomponent Wisemapping",
|
||||||
|
"author": "Ezequiel-Vega <vegaezequiel51@gmail.com>",
|
||||||
|
"homepage": "https://www.wisemapping.com",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "dist/webcomponent.js",
|
||||||
|
"private": false,
|
||||||
|
"directories": {
|
||||||
|
"lib": "lib",
|
||||||
|
"test": "__tests__"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.yarnpkg.com"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://ezequielVega@bitbucket.org/lilabyus/wisemapping-frontend.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack serve --config webpack.dev.js",
|
||||||
|
"build": "webpack --config webpack.prod.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.31.0",
|
||||||
|
"@typescript-eslint/parser": "^4.31.0",
|
||||||
|
"babel-loader": "^8.2.2",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"html-webpack-plugin": "^5.3.2",
|
||||||
|
"prettier": "^2.3.2",
|
||||||
|
"ts-loader": "^9.2.5",
|
||||||
|
"typescript": "^4.4.2",
|
||||||
|
"webpack": "^5.52.0",
|
||||||
|
"webpack-cli": "^4.8.0",
|
||||||
|
"webpack-merge": "^5.8.0",
|
||||||
|
"webpack-server": "^0.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wisemapping/mindplot": "^0.0.1",
|
||||||
|
"@wismapping/core-js": "^0.0.1",
|
||||||
|
"@wismapping/web2d": "^0.0.1",
|
||||||
|
"mootools": "1.4.5",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2"
|
||||||
|
}
|
||||||
|
}
|
11
packages/webcomponent/public/index.html
Normal file
11
packages/webcomponent/public/index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
packages/webcomponent/src/App.tsx
Normal file
10
packages/webcomponent/src/App.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Mindplot from '@wismapping/web2d';
|
||||||
|
|
||||||
|
const App = (): React.ReactElement => {
|
||||||
|
const mindplot = Mindplot();
|
||||||
|
console.log(mindplot);
|
||||||
|
return <div>Webcomponent</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
6
packages/webcomponent/src/index.tsx
Normal file
6
packages/webcomponent/src/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
import 'mootools';
|
||||||
|
|
||||||
|
ReactDOM.render(<App />, document.getElementById('root'));
|
16
packages/webcomponent/tsconfig.json
Normal file
16
packages/webcomponent/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./lib/",
|
||||||
|
"sourceMap": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"types": ["node"],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"module": "es6",
|
||||||
|
"target": "es6",
|
||||||
|
"jsx": "react",
|
||||||
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
40
packages/webcomponent/webpack.common.js
Normal file
40
packages/webcomponent/webpack.common.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
|
|
||||||
|
/** @type {import('webpack').Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.tsx',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'lib'),
|
||||||
|
filename: 'webcomponent.js',
|
||||||
|
publicPath: '/',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
use: 'babel-loader',
|
||||||
|
test: /.(js|jsx)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
use: 'ts-loader',
|
||||||
|
test: /\.(ts|tsx)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'asset',
|
||||||
|
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './public/index.html',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
20
packages/webcomponent/webpack.dev.js
Normal file
20
packages/webcomponent/webpack.dev.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const { HotModuleReplacementPlugin } = require('webpack');
|
||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common');
|
||||||
|
|
||||||
|
/** @type {import('webpack').Configuration} */
|
||||||
|
const devConfig = {
|
||||||
|
mode: 'development',
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.join(__dirname, 'lib'),
|
||||||
|
compress: true,
|
||||||
|
port: 8080,
|
||||||
|
hot: true,
|
||||||
|
},
|
||||||
|
target: 'web',
|
||||||
|
plugins: [new HotModuleReplacementPlugin()],
|
||||||
|
devtool: 'eval-source-map',
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = merge(common, devConfig);
|
15
packages/webcomponent/webpack.prod.js
Normal file
15
packages/webcomponent/webpack.prod.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common');
|
||||||
|
|
||||||
|
/** @type {import('webpack').Configuration} */
|
||||||
|
const prodConfig = {
|
||||||
|
mode: 'production',
|
||||||
|
devtool: 'source-map',
|
||||||
|
optimization: {
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'all',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = merge(common, prodConfig);
|
Loading…
Reference in New Issue
Block a user