mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 15:26:39 +00:00
[Code Style] Use prototypes in representation bundle
WTD-1482
This commit is contained in:
parent
07a2065c11
commit
365134b085
@ -238,6 +238,25 @@ define(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A representer participates in the process of instantiating a
|
||||||
|
* representation of a domain object.
|
||||||
|
*
|
||||||
|
* @interface Representer
|
||||||
|
* @augments {Destroyable}
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Set the current representation in use, and the domain
|
||||||
|
* object being represented.
|
||||||
|
*
|
||||||
|
* @method Representer#represent
|
||||||
|
* @param {RepresentationDefinition} representation the
|
||||||
|
* definition of the representation in use
|
||||||
|
* @param {DomainObject} domainObject the domain object
|
||||||
|
* being represented
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
return MCTRepresentation;
|
return MCTRepresentation;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -47,71 +47,78 @@ define(
|
|||||||
* @param $rootScope Angular's root scope
|
* @param $rootScope Angular's root scope
|
||||||
* @param actionContexr the context in which the action
|
* @param actionContexr the context in which the action
|
||||||
* should be performed
|
* should be performed
|
||||||
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function ContextMenuAction($compile, $document, $window, $rootScope, actionContext) {
|
function ContextMenuAction($compile, $document, $window, $rootScope, actionContext) {
|
||||||
|
this.$compile = $compile;
|
||||||
function perform() {
|
this.actionContext = actionContext;
|
||||||
var winDim = [$window.innerWidth, $window.innerHeight],
|
this.getDocument = function () { return $document; };
|
||||||
eventCoors = [actionContext.event.pageX, actionContext.event.pageY],
|
this.getWindow = function () { return $window; };
|
||||||
menuDim = GestureConstants.MCT_MENU_DIMENSIONS,
|
this.getRootScope = function () { return $rootScope; };
|
||||||
body = $document.find('body'),
|
|
||||||
scope = $rootScope.$new(),
|
|
||||||
goLeft = eventCoors[0] + menuDim[0] > winDim[0],
|
|
||||||
goUp = eventCoors[1] + menuDim[1] > winDim[1],
|
|
||||||
menu;
|
|
||||||
|
|
||||||
// Remove the context menu
|
|
||||||
function dismiss() {
|
|
||||||
menu.remove();
|
|
||||||
body.off("click", dismiss);
|
|
||||||
dismissExistingMenu = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dismiss any menu which was already showing
|
|
||||||
if (dismissExistingMenu) {
|
|
||||||
dismissExistingMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and record the presence of this menu.
|
|
||||||
dismissExistingMenu = dismiss;
|
|
||||||
|
|
||||||
// Set up the scope, including menu positioning
|
|
||||||
scope.domainObject = actionContext.domainObject;
|
|
||||||
scope.menuStyle = {};
|
|
||||||
scope.menuStyle[goLeft ? "right" : "left"] =
|
|
||||||
(goLeft ? (winDim[0] - eventCoors[0]) : eventCoors[0]) + 'px';
|
|
||||||
scope.menuStyle[goUp ? "bottom" : "top"] =
|
|
||||||
(goUp ? (winDim[1] - eventCoors[1]) : eventCoors[1]) + 'px';
|
|
||||||
scope.menuClass = {
|
|
||||||
"go-left": goLeft,
|
|
||||||
"go-up": goUp,
|
|
||||||
"context-menu-holder": true
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the context menu
|
|
||||||
menu = $compile(MENU_TEMPLATE)(scope);
|
|
||||||
|
|
||||||
// Add the menu to the body
|
|
||||||
body.append(menu);
|
|
||||||
|
|
||||||
// Stop propagation so that clicks on the menu do not close the menu
|
|
||||||
menu.on('mousedown', function (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dismiss the menu when body is clicked elsewhere
|
|
||||||
// ('mousedown' because 'click' breaks left-click context menus)
|
|
||||||
body.on('mousedown', dismiss);
|
|
||||||
|
|
||||||
// Don't launch browser's context menu
|
|
||||||
actionContext.event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
perform: perform
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContextMenuAction.prototype.perform = function () {
|
||||||
|
var $compile = this.$compile,
|
||||||
|
$document = this.getDocument(),
|
||||||
|
$window = this.getWindow(),
|
||||||
|
$rootScope = this.getRootScope(),
|
||||||
|
actionContext = this.actionContext,
|
||||||
|
winDim = [$window.innerWidth, $window.innerHeight],
|
||||||
|
eventCoors = [actionContext.event.pageX, actionContext.event.pageY],
|
||||||
|
menuDim = GestureConstants.MCT_MENU_DIMENSIONS,
|
||||||
|
body = $document.find('body'),
|
||||||
|
scope = $rootScope.$new(),
|
||||||
|
goLeft = eventCoors[0] + menuDim[0] > winDim[0],
|
||||||
|
goUp = eventCoors[1] + menuDim[1] > winDim[1],
|
||||||
|
menu;
|
||||||
|
|
||||||
|
// Remove the context menu
|
||||||
|
function dismiss() {
|
||||||
|
menu.remove();
|
||||||
|
body.off("click", dismiss);
|
||||||
|
dismissExistingMenu = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismiss any menu which was already showing
|
||||||
|
if (dismissExistingMenu) {
|
||||||
|
dismissExistingMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and record the presence of this menu.
|
||||||
|
dismissExistingMenu = dismiss;
|
||||||
|
|
||||||
|
// Set up the scope, including menu positioning
|
||||||
|
scope.domainObject = actionContext.domainObject;
|
||||||
|
scope.menuStyle = {};
|
||||||
|
scope.menuStyle[goLeft ? "right" : "left"] =
|
||||||
|
(goLeft ? (winDim[0] - eventCoors[0]) : eventCoors[0]) + 'px';
|
||||||
|
scope.menuStyle[goUp ? "bottom" : "top"] =
|
||||||
|
(goUp ? (winDim[1] - eventCoors[1]) : eventCoors[1]) + 'px';
|
||||||
|
scope.menuClass = {
|
||||||
|
"go-left": goLeft,
|
||||||
|
"go-up": goUp,
|
||||||
|
"context-menu-holder": true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the context menu
|
||||||
|
menu = $compile(MENU_TEMPLATE)(scope);
|
||||||
|
|
||||||
|
// Add the menu to the body
|
||||||
|
body.append(menu);
|
||||||
|
|
||||||
|
// Stop propagation so that clicks on the menu do not close the menu
|
||||||
|
menu.on('mousedown', function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dismiss the menu when body is clicked elsewhere
|
||||||
|
// ('mousedown' because 'click' breaks left-click context menus)
|
||||||
|
body.on('mousedown', dismiss);
|
||||||
|
|
||||||
|
// Don't launch browser's context menu
|
||||||
|
actionContext.event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
return ContextMenuAction;
|
return ContextMenuAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -36,33 +36,31 @@ define(
|
|||||||
* @memberof platform/representation
|
* @memberof platform/representation
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param element the jqLite-wrapped element which should exhibit
|
* @param element the jqLite-wrapped element which should exhibit
|
||||||
* the context mennu
|
* the context menu
|
||||||
* @param {DomainObject} domainObject the object on which actions
|
* @param {DomainObject} domainObject the object on which actions
|
||||||
* in the context menu will be performed
|
* in the context menu will be performed
|
||||||
|
* @implements {Gesture}
|
||||||
*/
|
*/
|
||||||
function ContextMenuGesture(element, domainObject) {
|
function ContextMenuGesture(element, domainObject) {
|
||||||
var actionContext,
|
function showMenu(event) {
|
||||||
stop;
|
domainObject.getCapability('action').perform({
|
||||||
|
key: 'menu',
|
||||||
|
domainObject: domainObject,
|
||||||
|
event: event
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// When context menu event occurs, show object actions instead
|
// When context menu event occurs, show object actions instead
|
||||||
element.on('contextmenu', function (event) {
|
element.on('contextmenu', showMenu);
|
||||||
actionContext = {key: 'menu', domainObject: domainObject, event: event};
|
|
||||||
stop = domainObject.getCapability('action').perform(actionContext);
|
this.showMenuCallback = showMenu;
|
||||||
});
|
this.element = element;
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Detach any event handlers associated with this gesture.
|
|
||||||
* @method
|
|
||||||
* @memberof ContextMenuGesture
|
|
||||||
* @memberof platform/representation.ContextMenuGesture#
|
|
||||||
*/
|
|
||||||
destroy: function () {
|
|
||||||
element.off('contextmenu', stop);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContextMenuGesture.prototype.destroy = function () {
|
||||||
|
this.element.off('contextmenu', this.showMenu);
|
||||||
|
};
|
||||||
|
|
||||||
return ContextMenuGesture;
|
return ContextMenuGesture;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,7 @@ define(
|
|||||||
*
|
*
|
||||||
* @memberof platform/representation
|
* @memberof platform/representation
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Gesture}
|
||||||
* @param $log Angular's logging service
|
* @param $log Angular's logging service
|
||||||
* @param element the jqLite-wrapped element which should become
|
* @param element the jqLite-wrapped element which should become
|
||||||
* draggable
|
* draggable
|
||||||
@ -104,22 +105,19 @@ define(
|
|||||||
element.on('dragstart', startDrag);
|
element.on('dragstart', startDrag);
|
||||||
element.on('dragend', endDrag);
|
element.on('dragend', endDrag);
|
||||||
|
|
||||||
return {
|
this.element = element;
|
||||||
/**
|
this.startDragCallback = startDrag;
|
||||||
* Detach any event handlers associated with this gesture.
|
this.endDragCallback = endDrag;
|
||||||
* @memberof DragGesture
|
|
||||||
* @method
|
|
||||||
* @memberof platform/representation.DragGesture#
|
|
||||||
*/
|
|
||||||
destroy: function () {
|
|
||||||
// Detach listener
|
|
||||||
element.removeAttr('draggable');
|
|
||||||
element.off('dragstart', startDrag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DragGesture.prototype.destroy = function () {
|
||||||
|
// Detach listener
|
||||||
|
this.element.removeAttr('draggable');
|
||||||
|
this.element.off('dragstart', this.startDragCallback);
|
||||||
|
this.element.off('dragend', this.endDragCallback);
|
||||||
|
};
|
||||||
|
|
||||||
return DragGesture;
|
return DragGesture;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* A DropGesture adds and maintains event handlers upon an element
|
* A DropGesture adds and maintains event handlers upon an element
|
||||||
* such that it may act as a drop target for drag-drop composition.
|
* such that it may act as a drop target for drag-drop composition.
|
||||||
|
*
|
||||||
* @memberof platform/representation
|
* @memberof platform/representation
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param $q Angular's $q, for promise handling
|
* @param $q Angular's $q, for promise handling
|
||||||
@ -40,7 +40,6 @@ define(
|
|||||||
* @param {DomainObject} domainObject the domain object whose
|
* @param {DomainObject} domainObject the domain object whose
|
||||||
* composition should be modified as a result of the drop.
|
* composition should be modified as a result of the drop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function DropGesture(dndService, $q, element, domainObject) {
|
function DropGesture(dndService, $q, element, domainObject) {
|
||||||
var actionCapability = domainObject.getCapability('action'),
|
var actionCapability = domainObject.getCapability('action'),
|
||||||
action; // Action for the drop, when it occurs
|
action; // Action for the drop, when it occurs
|
||||||
@ -122,19 +121,16 @@ define(
|
|||||||
element.on('drop', drop);
|
element.on('drop', drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
this.element = element;
|
||||||
/**
|
this.dragOverCallback = dragOver;
|
||||||
* Detach any event handlers associated with this gesture.
|
this.dropCallback = drop;
|
||||||
* @memberof platform/representation.DropGesture#
|
|
||||||
*/
|
|
||||||
destroy: function () {
|
|
||||||
element.off('dragover', dragOver);
|
|
||||||
element.off('drop', drop);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropGesture.prototype.destroy = function () {
|
||||||
|
this.element.off('dragover', this.dragOverCallback);
|
||||||
|
this.element.off('drop', this.dropCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return DropGesture;
|
return DropGesture;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,29 @@ define(
|
|||||||
function () {
|
function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the attachment of gestures (responses to DOM events,
|
||||||
|
* generally) to DOM elements which represent domain objects.
|
||||||
|
*
|
||||||
|
* @interface GestureService
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Attach a set of gestures (indicated by key) to a
|
||||||
|
* DOM element which represents a specific domain object.
|
||||||
|
* @method GestureService#attachGestures
|
||||||
|
* @param element the jqLite-wrapped DOM element which the
|
||||||
|
* user will interact with
|
||||||
|
* @param {DomainObject} domainObject the domain object which
|
||||||
|
* is represented by that element
|
||||||
|
* @param {string[]} gestureKeys an array of keys identifying
|
||||||
|
* which gestures should apply; these will be matched
|
||||||
|
* against the keys defined in the gestures' extension
|
||||||
|
* definitions
|
||||||
|
* @return {Destroyable} an object with a `destroy`
|
||||||
|
* method which can (and should) be used when
|
||||||
|
* gestures should no longer be applied to an element.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GestureProvider exposes defined gestures. Gestures are used
|
* The GestureProvider exposes defined gestures. Gestures are used
|
||||||
* do describe and handle general-purpose interactions with the DOM
|
* do describe and handle general-purpose interactions with the DOM
|
||||||
@ -41,6 +64,7 @@ define(
|
|||||||
* where they are used.
|
* where they are used.
|
||||||
*
|
*
|
||||||
* @memberof platform/representation
|
* @memberof platform/representation
|
||||||
|
* @implements {GestureService}
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Gesture[]} gestures an array of all gestures which are
|
* @param {Gesture[]} gestures an array of all gestures which are
|
||||||
* available as extensions
|
* available as extensions
|
||||||
@ -48,19 +72,28 @@ define(
|
|||||||
function GestureProvider(gestures) {
|
function GestureProvider(gestures) {
|
||||||
var gestureMap = {};
|
var gestureMap = {};
|
||||||
|
|
||||||
function releaseGesture(gesture) {
|
// Assemble all gestures into a map, for easy look up
|
||||||
// Invoke the gesture's "destroy" method (if there is one)
|
gestures.forEach(function (gesture) {
|
||||||
// to release any held resources and detach event handlers.
|
gestureMap[gesture.key] = gesture;
|
||||||
if (gesture && gesture.destroy) {
|
});
|
||||||
gesture.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function attachGestures(element, domainObject, gestureKeys) {
|
this.gestureMap = gestureMap;
|
||||||
// Look up the desired gestures, filter for applicability,
|
}
|
||||||
// and instantiate them. Maintain a reference to allow them
|
|
||||||
// to be destroyed as a group later.
|
function releaseGesture(gesture) {
|
||||||
var attachedGestures = gestureKeys.map(function (key) {
|
// Invoke the gesture's "destroy" method (if there is one)
|
||||||
|
// to release any held resources and detach event handlers.
|
||||||
|
if (gesture && gesture.destroy) {
|
||||||
|
gesture.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GestureProvider.prototype.attachGestures = function attachGestures(element, domainObject, gestureKeys) {
|
||||||
|
// Look up the desired gestures, filter for applicability,
|
||||||
|
// and instantiate them. Maintain a reference to allow them
|
||||||
|
// to be destroyed as a group later.
|
||||||
|
var gestureMap = this.gestureMap,
|
||||||
|
attachedGestures = gestureKeys.map(function (key) {
|
||||||
return gestureMap[key];
|
return gestureMap[key];
|
||||||
}).filter(function (Gesture) {
|
}).filter(function (Gesture) {
|
||||||
return Gesture !== undefined && (Gesture.appliesTo ?
|
return Gesture !== undefined && (Gesture.appliesTo ?
|
||||||
@ -70,42 +103,32 @@ define(
|
|||||||
return new Gesture(element, domainObject);
|
return new Gesture(element, domainObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
destroy: function () {
|
|
||||||
// Just call all the individual "destroy" methods
|
|
||||||
attachedGestures.forEach(releaseGesture);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble all gestures into a map, for easy look up
|
|
||||||
gestures.forEach(function (gesture) {
|
|
||||||
gestureMap[gesture.key] = gesture;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
destroy: function () {
|
||||||
* Attach a set of gestures (indicated by key) to a
|
// Just call all the individual "destroy" methods
|
||||||
* DOM element which represents a specific domain object.
|
attachedGestures.forEach(releaseGesture);
|
||||||
* @method
|
}
|
||||||
* @memberof GestureProvider
|
|
||||||
* @param element the jqLite-wrapped DOM element which the
|
|
||||||
* user will interact with
|
|
||||||
* @param {DomainObject} domainObject the domain object which
|
|
||||||
* is represented by that element
|
|
||||||
* @param {string[]} gestureKeys an array of keys identifying
|
|
||||||
* which gestures should apply; these will be matched
|
|
||||||
* against the keys defined in the gestures' extension
|
|
||||||
* definitions
|
|
||||||
* @return {{ destroy: function }} an object with a `destroy`
|
|
||||||
* method which can (and should) be used when a
|
|
||||||
* gesture should no longer be applied to an element.
|
|
||||||
* @memberof platform/representation.GestureProvider#
|
|
||||||
*/
|
|
||||||
attachGestures: attachGestures
|
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A destroyable object may have resources allocated which require
|
||||||
|
* explicit release.
|
||||||
|
*
|
||||||
|
* @interface Destroyable
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Release any resources associated with this object.
|
||||||
|
*
|
||||||
|
* @method Destroyable#destroy
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A gesture describes manners in which certain representations of
|
||||||
|
* domain objects may respond to DOM events upon those representations.
|
||||||
|
* @interface Gesture
|
||||||
|
* @augments Destroyable
|
||||||
|
*/
|
||||||
|
|
||||||
return GestureProvider;
|
return GestureProvider;
|
||||||
}
|
}
|
||||||
|
@ -38,50 +38,33 @@ define(
|
|||||||
* @param {Scope} scope the Angular scope for this representation
|
* @param {Scope} scope the Angular scope for this representation
|
||||||
* @param element the JQLite-wrapped mct-representation element
|
* @param element the JQLite-wrapped mct-representation element
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @implements {Representer}
|
||||||
* @memberof platform/representation
|
* @memberof platform/representation
|
||||||
*/
|
*/
|
||||||
function GestureRepresenter(gestureService, scope, element) {
|
function GestureRepresenter(gestureService, scope, element) {
|
||||||
var gestureHandle;
|
this.gestureService = gestureService;
|
||||||
|
this.element = element;
|
||||||
function destroy() {
|
|
||||||
// Release any resources associated with these gestures
|
|
||||||
if (gestureHandle) {
|
|
||||||
gestureHandle.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function represent(representation, domainObject) {
|
|
||||||
// Clear out any existing gestures
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
// Attach gestures - by way of the service.
|
|
||||||
gestureHandle = gestureService.attachGestures(
|
|
||||||
element,
|
|
||||||
domainObject,
|
|
||||||
(representation || {}).gestures || []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Set the current representation in use, and the domain
|
|
||||||
* object being represented.
|
|
||||||
*
|
|
||||||
* @param {RepresentationDefinition} representation the
|
|
||||||
* definition of the representation in use
|
|
||||||
* @param {DomainObject} domainObject the domain object
|
|
||||||
* being represented
|
|
||||||
* @memberof platform/representation.GestureRepresenter#
|
|
||||||
*/
|
|
||||||
represent: represent,
|
|
||||||
/**
|
|
||||||
* Release any resources associated with this representer.
|
|
||||||
* @memberof platform/representation.GestureRepresenter#
|
|
||||||
*/
|
|
||||||
destroy: destroy
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GestureRepresenter.prototype.represent = function represent(representation, domainObject) {
|
||||||
|
// Clear out any existing gestures
|
||||||
|
this.destroy();
|
||||||
|
|
||||||
|
// Attach gestures - by way of the service.
|
||||||
|
this.gestureHandle = this.gestureService.attachGestures(
|
||||||
|
this.element,
|
||||||
|
domainObject,
|
||||||
|
(representation || {}).gestures || []
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
GestureRepresenter.prototype.destroy = function () {
|
||||||
|
// Release any resources associated with these gestures
|
||||||
|
if (this.gestureHandle) {
|
||||||
|
this.gestureHandle.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return GestureRepresenter;
|
return GestureRepresenter;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user