foxbpm 시리즈 의 - signavio 사건 원형, OOP 사상 깊이 분석
21382 단어 sign
이벤트 구동 원형
우선 전체 시스템 의 사건 원형 을 살 펴 보 자.다른 핵심 작업 과 마찬가지 로 이벤트 관련 인터페이스 도 ORYX. Editor 대상 에 봉 인 됩 니 다. 등록 취소, 실행 취소, 이벤트 일시 정지, 이벤트 활성화 등 인 터 페 이 스 를 포함 하고 JS 언어 자체 가 함수 식 프로 그래 밍 에 좋 은 지원 을 하기 때문에 시스템 이벤트 원형 이 쉽게 실 현 됩 니 다.
시스템 이벤트 응답 유형:
1. 동작 응답 이벤트, 예 를 들 어 마우스 클릭 이벤트, 키보드 조작 이벤트 등 은 주로 HTML DOCUMENT 에 의 해 이 루어 집 니 다. 디자이너 는 자신의 업무 동태 에 대해 사건 감청 을 추가 하면 됩 니 다.
2. 기능 응답 이벤트, 전체 디자이너 시스템 은 이 이벤트 모델 을 바탕 으로 이 루어 집 니 다. 예 를 들 어 도구 모음 명령 실행 이벤트, 노드 요소 드래그 이벤트, 메뉴 이벤트 등 입 니 다.
모든 이벤트 형식의 상수 정 의 는 다음 코드 와 같 습 니 다.
// 、 HTML DOCUMENT
ORYX.CONFIG.EVENT_MOUSEDOWN = "mousedown";
ORYX.CONFIG.EVENT_MOUSEUP = "mouseup";
ORYX.CONFIG.EVENT_MOUSEOVER = "mouseover";
ORYX.CONFIG.EVENT_MOUSEOUT = "mouseout";
ORYX.CONFIG.EVENT_MOUSEMOVE = "mousemove";
ORYX.CONFIG.EVENT_DBLCLICK = "dblclick";
ORYX.CONFIG.EVENT_KEYDOWN = "keydown";
ORYX.CONFIG.EVENT_KEYUP = "keyup";
ORYX.CONFIG.EVENT_LOADED = "editorloaded";
//
ORYX.CONFIG.EVENT_EXECUTE_COMMANDS = "executeCommands";
ORYX.CONFIG.EVENT_STENCIL_SET_LOADED = "stencilSetLoaded";
ORYX.CONFIG.EVENT_SELECTION_CHANGED = "selectionchanged";
ORYX.CONFIG.EVENT_SHAPEADDED = "shapeadded";
ORYX.CONFIG.EVENT_SHAPEREMOVED = "shaperemoved";
ORYX.CONFIG.EVENT_PROPERTY_CHANGED = "propertyChanged";
ORYX.CONFIG.EVENT_DRAGDROP_START = "dragdrop.start";
ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE = "shape.menu.close";
ORYX.CONFIG.EVENT_DRAGDROP_END = "dragdrop.end";
ORYX.CONFIG.EVENT_RESIZE_START = "resize.start";
ORYX.CONFIG.EVENT_RESIZE_END = "resize.end";
ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED = "dragDocker.docked";
ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW = "highlight.showHighlight";
ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE = "highlight.hideHighlight";
ORYX.CONFIG.EVENT_LOADING_ENABLE = "loading.enable";
ORYX.CONFIG.EVENT_LOADING_DISABLE = "loading.disable";
ORYX.CONFIG.EVENT_LOADING_STATUS = "loading.status";
ORYX.CONFIG.EVENT_OVERLAY_SHOW = "overlay.show";
ORYX.CONFIG.EVENT_OVERLAY_HIDE = "overlay.hide";
ORYX.CONFIG.EVENT_ARRANGEMENT_TOP = "arrangement.setToTop";
ORYX.CONFIG.EVENT_ARRANGEMENT_BACK = "arrangement.setToBack";
ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD = "arrangement.setForward";
ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD = "arrangement.setBackward";
ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED = "propertyWindow.propertyChanged";
ORYX.CONFIG.EVENT_LAYOUT_ROWS = "layout.rows";
ORYX.CONFIG.EVENT_LAYOUT_BPEL = "layout.BPEL";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL = "layout.BPEL.vertical";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL = "layout.BPEL.horizontal";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD = "layout.BPEL.singlechild";
ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE = "layout.BPEL.autoresize";
ORYX.CONFIG.EVENT_AUTOLAYOUT_LAYOUT = "autolayout.layout";
ORYX.CONFIG.EVENT_UNDO_EXECUTE = "undo.execute";
ORYX.CONFIG.EVENT_UNDO_ROLLBACK = "undo.rollback";
ORYX.CONFIG.EVENT_BUTTON_UPDATE = "toolbar.button.update";
ORYX.CONFIG.EVENT_LAYOUT = "layout.dolayout";
ORYX.CONFIG.EVENT_GLOSSARY_LINK_EDIT = "glossary.link.edit";
ORYX.CONFIG.EVENT_GLOSSARY_SHOW = "glossary.show.info";
ORYX.CONFIG.EVENT_GLOSSARY_NEW = "glossary.show.new";
ORYX.CONFIG.EVENT_DOCKERDRAG = "dragTheDocker";
이상 코드 는 oryx. debug. js 파일 에 있 습 니 다.
이벤트 조작 관련 코드 는 다음 과 같다.
disableEvent: function(eventType){
if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
this._keydownEnabled = false;
}
if(eventType == ORYX.CONFIG.EVENT_KEYUP) {
this._keyupEnabled = false;
}
if(this.DOMEventListeners.keys().member(eventType)) {
var value = this.DOMEventListeners.remove(eventType);
this.DOMEventListeners['disable_' + eventType] = value;
}
},
enableEvent: function(eventType){
if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
this._keydownEnabled = true;
}
if(eventType == ORYX.CONFIG.EVENT_KEYUP) {
this._keyupEnabled = true;
}
if(this.DOMEventListeners.keys().member("disable_" + eventType)) {
var value = this.DOMEventListeners.remove("disable_" + eventType);
this.DOMEventListeners[eventType] = value;
}
},
/**
* Methods for the PluginFacade
*/
registerOnEvent: function(eventType, callback) {
if(!(this.DOMEventListeners.keys().member(eventType))) {
this.DOMEventListeners[eventType] = [];
}
this.DOMEventListeners[eventType].push(callback);
},
unregisterOnEvent: function(eventType, callback) {
if(this.DOMEventListeners.keys().member(eventType)) {
this.DOMEventListeners[eventType] = this.DOMEventListeners[eventType].without(callback);
} else {
// Event is not supported
// TODO: Error Handling
}
},
이벤트 실행:
/**
* Helper method to execute an event immediately. The event is not
* scheduled in the _eventsQueue. Needed to handle Layout-Callbacks.
*/
_executeEventImmediately: function(eventObj) {
if(this.DOMEventListeners.keys().member(eventObj.event.type)) {
this.DOMEventListeners[eventObj.event.type].each((function(value) {
value(eventObj.event, eventObj.arg);
}).bind(this));
}
},
_executeEvents: function() {
this._queueRunning = true;
while(this._eventsQueue.length > 0) {
var val = this._eventsQueue.shift();
this._executeEventImmediately(val);
}
this._queueRunning = false;
},
/**
* Leitet die Events an die Editor-Spezifischen Event-Methoden weiter
* @param {Object} event Event , welches gefeuert wurde
* @param {Object} uiObj Target-UiObj
*/
handleEvents: function(event, uiObj) {
ORYX.Log.trace("Dispatching event type %0 on %1", event.type, uiObj);
switch(event.type) {
case ORYX.CONFIG.EVENT_MOUSEDOWN:
this._handleMouseDown(event, uiObj);
break;
case ORYX.CONFIG.EVENT_MOUSEMOVE:
this._handleMouseMove(event, uiObj);
break;
case ORYX.CONFIG.EVENT_MOUSEUP:
this._handleMouseUp(event, uiObj);
break;
case ORYX.CONFIG.EVENT_MOUSEOVER:
this._handleMouseHover(event, uiObj);
break;
case ORYX.CONFIG.EVENT_MOUSEOUT:
this._handleMouseOut(event, uiObj);
break;
}
/* Force execution if necessary. Used while handle Layout-Callbacks. */
if(event.forceExecution) {
this._executeEventImmediately({event: event, arg: uiObj});
} else {
this._eventsQueue.push({event: event, arg: uiObj});
}
if(!this._queueRunning) {
this._executeEvents();
}
// TODO: Make this return whether no listener returned false.
// So that, when one considers bubbling undesireable, it won't happen.
return false;
},
이벤트 초기 화:
_initEventListener: function(){
// Register on Events
document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYDOWN, this.catchKeyDownEvents.bind(this), false);
document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYUP, this.catchKeyUpEvents.bind(this), false);
// Enable Key up and down Event
this._keydownEnabled = true;
this._keyupEnabled = true;
this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEDOWN] = [];
this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEUP] = [];
this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOVER] = [];
this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOUT] = [];
this.DOMEventListeners[ORYX.CONFIG.EVENT_SELECTION_CHANGED] = [];
this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEMOVE] = [];
},
상기 사건 모델 을 바탕 으로 시스템 의 많은 복잡 한 기능 이 순조롭게 실 현 될 수 있다.
예 를 들 어 노드 요소 가 드래그 를 시작 할 때 노드 요소 가 지원 하 는 규칙 메뉴 항목 을 숨 겨 야 합 니 다. 노드 요소 가 드래그 를 종료 할 때 기본적으로 선택 하고 노드 요소 가 지원 하 는 규칙 메뉴 항목 을 보 여 줍 니 다.
이 시스템 을 잘 아 는 독자 들 은 이 기능 을 알 아야 한다.그 핵심 코드 는 다음 과 같다.
이벤트 등록 코드:
ORYX.Plugins.ShapeMenuPlugin = {
construct: function(facade) {
this.facade = facade;
this.alignGroups = new Hash();
var containerNode = this.facade.getCanvas().getHTMLContainer();
this.shapeMenu = new ORYX.Plugins.ShapeMenu(containerNode);
this.currentShapes = [];
// Register on dragging and resizing events for show/hide of ShapeMenu
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START, this.hideShapeMenu.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END, this.showShapeMenu.bind(this));
이벤트 방법 관련 코드:
hideShapeMenu: function(event) {
window.clearTimeout(this.timer);
this.timer = null;
this.shapeMenu.hide();
},
showShapeMenu: function( dontGenerateNew ) {
if( !dontGenerateNew || this.resetElements ){
window.clearTimeout(this.timer);
this.timer = window.setTimeout(function(){
// Close all Buttons
this.shapeMenu.closeAllButtons();
// Show the Morph Button
this.showMorphButton(this.currentShapes);
// Show the Stencil Buttons
this.showStencilButtons(this.currentShapes);
// Show the ShapeMenu
this.shapeMenu.show(this.currentShapes);
this.resetElements = false;
}.bind(this), 300)
} else {
window.clearTimeout(this.timer);
this.timer = null;
// Show the ShapeMenu
this.shapeMenu.show(this.currentShapes);
}
},
예 를 들 어 선 에 DragDocker 를 추가 할 때 선 에 Docker 가 존재 한다 면 마우스 가 가 는 줄 로 이동 할 때 추 가 된 Docker 를 동적 으로 표시 해 야 합 니 다. 핵심 코드 는 다음 과 같 습 니 다.
이벤트 등록 코드:
ORYX.Plugins.DragDocker = Clazz.extend({
/**
* Constructor
* @param {Object} Facade: The Facade of the Editor
*/
construct: function(facade) {
this.facade = facade;
// Set the valid and invalid color
this.VALIDCOLOR = ORYX.CONFIG.SELECTION_VALID_COLOR;
this.INVALIDCOLOR = ORYX.CONFIG.SELECTION_INVALID_COLOR;
// Define Variables
this.shapeSelection = undefined;
this.docker = undefined;
this.dockerParent = undefined;
this.dockerSource = undefined;
this.dockerTarget = undefined;
this.lastUIObj = undefined;
this.isStartDocker = undefined;
this.isEndDocker = undefined;
this.undockTreshold = 10;
this.initialDockerPosition = undefined;
this.outerDockerNotMoved = undefined;
this.isValid = false;
// For the Drag and Drop
// Register on MouseDown-Event on a Docker
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DOCKERDRAG, this.handleDockerDrag.bind(this));
// Register on over/out to show / hide a docker
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOVER, this.handleMouseOver.bind(this));
this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOUT, this.handleMouseOut.bind(this));
},
이벤트 방법 구현 코드:
/**
* MouseOver Handler
*
*/
handleMouseOver: function(event, uiObj) {
// If there is a Docker, show this
if(!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) {
uiObj.show()
} else if(!this.docker && uiObj instanceof ORYX.Core.Edge) {
uiObj.dockers.each(function(docker){
docker.show();
})
}
},
OOP 사상
시스템 을 더욱 유연성 있 고 확장 가능 하 게 하기 위해 SIGNAVIO 의 전체적인 구조 도 OOP 사상 으로 프로 그래 밍 을 한다. OOP 관련 지식 과 JS 관련 기초 지식 은 더 이상 군말 하지 않 는 다. (JAVA 언어 와 BS 구조 가 유행 하 는 오늘날 OOP 와 JS 를 모 르 는 프로그래머 는 상상 할 수 없다)클래스 의 계승 은 JS 의 prototype 을 바탕 으로 이 루어 집 니 다.
실 현 된 핵심 코드 는 다음 과 같다 (코드 의 영문 주석 포함).
/**
* The super class for all classes in ORYX. Adds some OOP feeling to javascript.
* See article "Object Oriented Super Class Method Calling with JavaScript" on
* http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html
* for a documentation on this. Fairly good article that points out errors in
* Douglas Crockford's inheritance and super method calling approach.
* Worth reading.
* @class Clazz
*/
var Clazz = function() {};
/**
* Empty constructor.
* @methodOf Clazz.prototype
*/
Clazz.prototype.construct = function() {};
/**
* Can be used to build up inheritances of classes.
* @example
* var MyClass = Clazz.extend({
* construct: function(myParam){
* // Do sth.
* }
* });
* var MySubClass = MyClass.extend({
* construct: function(myParam){
* // Use this to call constructor of super class
* arguments.callee.$.construct.apply(this, arguments);
* // Do sth.
* }
* });
* @param {Object} def The definition of the new class.
*/
Clazz.extend = function(def) {
var classDef = function() {
if (arguments[0] !== Clazz) { this.construct.apply(this, arguments); }
};
var proto = new this(Clazz);
var superClass = this.prototype;
for (var n in def) {
var item = def[n];
if (item instanceof Function) item.$ = superClass;
proto[n] = item;
}
classDef.prototype = proto;
//Give this new class the same static extend method
classDef.extend = this.extend;
return classDef;
};
상기 코드 는 계승 기능 을 실현 하 는 템 플 릿 을 제공 하 는 것 과 같 고 상기 템 플 릿 으로 정 의 된 대상 은 모두 계승 기능 을 가진다.
핵심 코드 설명:
1. classDef. extend = this. extend 기능: 이 템 플 릿 으로 대상 을 정의 할 때 이 계승 템 플 릿 도 이 대상 에 게 부여 하여 이 대상 이 하위 대상 을 정의 하 는 능력 을 가지 게 하여 진정한 의미 의 계승 을 실현 합 니 다.
2. this. construct. apply (this, arguments) 와 같은 코드 의 기능 은 이 템 플 릿 으로 대상 을 정의 할 때 해당 대상 의 구조 함수 construct 를 호출 하 는 것 입 니 다.
3、classDef.prototype = proto;속성 을 계승 하 다.
꽃 은 물 에서 흘러 내 리 며 템 플 릿 이 정의 되 어 호출 이 쉬 워 집 니 다!
시스템 의 이 줄 코드 를 보십시오.
ORYX.Core.UIObject = Clazz.extend(ORYX.Core.UIObject);
Clazz. extend 는 바로 우리 가 방금 정의 한 계승 템 플 릿 방법 입 니 다.저희 도 템 플 릿 방법 으로 정 의 된 대상 내부 에 construct 구조 함수 가 정의 되 어 있어 야 한다 고 말씀 드 렸 습 니 다. 그래서 검증 을 하고 ORYX. Core. UIObject 원형 정 의 를 추출 해 야 합 니 다.
ORYX. Core. UIObject 프로 토 타 입 이 정의 하 는 부분 코드:
ORYX.Core.UIObject = {
/**
* Constructor of the UIObject class.
*/
construct: function(options) {
this.isChanged = true; //Flag, if UIObject has been changed since last update.
this.isResized = true;
this.isVisible = true; //Flag, if UIObject's display attribute is set to 'inherit' or 'none'
this.isSelectable = false; //Flag, if UIObject is selectable.
this.isResizable = false; //Flag, if UIObject is resizable.
this.isMovable = false; //Flag, if UIObject is movable.
this.id = ORYX.Editor.provideId(); //get unique id
this.parent = undefined; //parent is defined, if this object is added to another uiObject.
this.node = undefined; //this is a reference to the SVG representation, either locally or in DOM.
this.children = []; //array for all add uiObjects
this.bounds = new ORYX.Core.Bounds(); //bounds with undefined values
this._changedCallback = this._changed.bind(this); //callback reference for calling _changed
this.bounds.registerCallback(this._changedCallback); //set callback in bounds
if(options && options.eventHandlerCallback) {
this.eventHandlerCallback = options.eventHandlerCallback;
}
},
봤 어? construct 나 왔 습 니 다!ORYX. Core. UIObject 는 시스템 이 정의 한 JS 대상 이지 만 마지막 으로 계승 템 플 릿 을 사용 하여 이 루어 집 니 다. 따라서 현재 ORYX. Core. UIObject 대상 은 extend 기능 을 가 진 부모 대상 이 어야 합 니 다. 하위 대상 을 확장 할 수 있 습 니 다.
그럼 과연 그 럴 까요?
우 리 는 시스템 에서 ORYX. Core. AbstractShape 라 는 종 류 를 찾 아 정 의 를 봅 니 다.
ORYX. Core. AbstractShape 부분 정의 코드:
ORYX.Core.AbstractShape = ORYX.Core.UIObject.extend(
/** @lends ORYX.Core.AbstractShape.prototype */
{
/**
* Constructor
*/
construct: function(options, stencil) {
arguments.callee.$.construct.apply(this, arguments);
this.resourceId = ORYX.Editor.provideId(); //Id of resource in DOM
// stencil reference
this._stencil = stencil;
// if the stencil defines a super stencil that should be used for its instances, set it.
if (this._stencil._jsonStencil.superId){
stencilId = this._stencil.id()
superStencilId = stencilId.substring(0, stencilId.indexOf("#") + 1) + stencil._jsonStencil.superId;
stencilSet = this._stencil.stencilSet();
this._stencil = stencilSet.stencil(superStencilId);
}
//Hash map for all properties. Only stores the values of the properties.
this.properties = new Hash();
this.propertiesChanged = new Hash();
// List of properties which are not included in the stencilset,
// but which gets (de)serialized
this.hiddenProperties = new Hash();
//Initialization of property map and initial value.
this._stencil.properties().each((function(property) {
var key = property.prefix() + "-" + property.id();
this.properties[key] = property.value();
this.propertiesChanged[key] = true;
}).bind(this));
// if super stencil was defined, also regard stencil's properties:
if (stencil._jsonStencil.superId) {
stencil.properties().each((function(property) {
var key = property.prefix() + "-" + property.id();
var value = property.value();
var oldValue = this.properties[key];
this.properties[key] = value;
this.propertiesChanged[key] = true;
// Raise an event, to show that the property has changed
// required for plugins like processLink.js
//window.setTimeout( function(){
this._delegateEvent({
type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
name : key,
value : value,
oldValue: oldValue
});
//}.bind(this), 10)
}).bind(this));
}
},
수수께끼 가 철저히 밝 혀 졌 으 니 우 리 는 발견 할 수 있다. ORYX. Core. AbstractShape 의 정 의 는 단순 한 JS 문법 '{}' 이 아니 라 ORYX. Core. UIObject 대상 의 extend 방법 을 통 해 알 수 있 습 니 다. ORYX. Core. AbstractShape 의 구조 함수 에 이러한 코드 가 추가 되 었 습 니 다. "arguments. callee. $. construct. apply (this, arguments)" ,똑똑 한 건 분명히 알 아 맞 혔 을 거 야.ORYX. Core. UIObject 는 최종 적 으로 계승 템 플 릿 을 사용 하여 실현 하 는 대상 이기 때문에 extend 기능, 동종 원리, ORYX. Core. AbstractShape 도 extend 기능 을 가지 게 되 었 다. 그러면 전체 시스템 계승 시스템 의 초기 형태 도 나 타 났 다. 바로 SIGNAVIO 가 현재 대상 을 대상 으로 하 는 시스템 구조 이다.이렇게 되면 시스템 의 개발 은 과정 식 함수 식 이 아니 라 시스템 도 더욱 유연성 을 가지 고 확장 성과 유지 가능성 을 가진다.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = [email protected])
=====================================================================
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
8.3 sign up successthis part, we will deal with the case that sign up success. 1. start from TDD!!!! b. should change(User, :count).by(1) c...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.