Skip to content

Commit

Permalink
Observable changes to TS class from @ShaMan123 (#8330)
Browse files Browse the repository at this point in the history
Co-authored-by: ShaMan123 <shacharnen@gmail.com>
Co-authored-by: Shachar <34343793+ShaMan123@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 29, 2022
1 parent 2ea8540 commit 09d32e3
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 226 deletions.
168 changes: 84 additions & 84 deletions src/mixins/observable.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,145 +1,145 @@
//@ts-nocheck
(function (global) {
var fabric = global.fabric;

/**
* @private
* @param {String} eventName
* @param {Function} handler
*/
function _removeEventListener(eventName, handler) {
if (!this.__eventListeners[eventName]) {
return;
}
var eventListener = this.__eventListeners[eventName];
if (handler) {
eventListener[eventListener.indexOf(handler)] = false;
} else {
eventListener.fill(false);
}
}
import { fabric } from '../../HEADER';

type EventRegistryObject = Record<string, Function>;

/**
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}
* @see {@link http://fabricjs.com/events|Events demo}
*/
export class Observable {
private __eventListeners: Record<Function[]> = {};

/**
* Observes specified event
* @memberOf fabric.Observable
* @alias on
* @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {string} eventName Event name (eg. 'after:render')
* @param {EventRegistryObject} handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {Function} handler Function that receives a notification when an event of the specified type occurs
* @return {Function} disposer
*/
function on(eventName, handler) {
on(eventName: string, handler: Function): Function;
on(handlers: EventRegistryObject): Function;
on(arg0: string | EventRegistryObject, handler?: Function): Function {
if (!this.__eventListeners) {
this.__eventListeners = {};
}
// one object with key/value pairs was passed
if (arguments.length === 1) {
for (var prop in eventName) {
this.on(prop, eventName[prop]);
if (typeof arg0 === 'object') {
// one object with key/value pairs was passed
for (const eventName in arg0) {
this.on(eventName, arg0[eventName]);
}
} else {
return () => this.off(arg0);
} else if (handler) {
const eventName = arg0;
if (!this.__eventListeners[eventName]) {
this.__eventListeners[eventName] = [];
}
this.__eventListeners[eventName].push(handler);
return () => this.off(eventName, handler);
} else {
// noop
return () => false;
}
return off.bind(this, eventName, handler);
}

function _once(eventName, handler) {
var _handler = function () {
handler.apply(this, arguments);
this.off(eventName, _handler);
}.bind(this);
this.on(eventName, _handler);
return _handler;
}

/**
* Observes specified event **once**
* @memberOf fabric.Observable
* @alias once
* @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {string} eventName Event name (eg. 'after:render')
* @param {EventRegistryObject} handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {Function} handler Function that receives a notification when an event of the specified type occurs
* @return {Function} disposer
*/
function once(eventName, handler) {
// one object with key/value pairs was passed
if (arguments.length === 1) {
var handlers = {};
for (var prop in eventName) {
handlers[prop] = _once.call(this, prop, eventName[prop]);
once(eventName: string, handler: Function): Function;
once(handlers: EventRegistryObject): Function;
once(arg0: string | EventRegistryObject, handler?: Function): Function {
if (typeof arg0 === 'object') {
// one object with key/value pairs was passed
const disposers: Function[] = [];
for (const eventName in arg0) {
disposers.push(this.once(eventName, arg0[eventName]));
}
return off.bind(this, handlers);
return () => disposers.forEach((d) => d());
} else if (handler) {
const disposer = this.on(arg0, (...args: any[]) => {
handler(...args);
disposer();
});
return disposer;
} else {
var _handler = _once.call(this, eventName, handler);
return off.bind(this, eventName, _handler);
// noop
return () => false;
}
}

/**
* @private
* @param {string} eventName
* @param {Function} [handler]
*/
private _removeEventListener(eventName: string, handler?: Function) {
if (!this.__eventListeners[eventName]) {
return;
}

if (handler) {
const eventListener = this.__eventListeners[eventName];
const index = eventListener.indexOf(handler);
index > -1 && eventListener.splice(index, 1);
} else {
this.__eventListeners[eventName] = [];
}
}

/**
* Stops event observing for a particular event handler. Calling this method
* without arguments removes all handlers for all events
* @memberOf fabric.Observable
* @alias off
* @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {string} eventName Event name (eg. 'after:render')
* @param {EventRegistryObject} handlers key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})
* @param {Function} handler Function to be deleted from EventListeners
*/
function off(eventName, handler) {
off(eventName: string, handler: Function): void;
off(handlers: EventRegistryObject): void;
off(arg0?: string | EventRegistryObject, handler?: Function) {
if (!this.__eventListeners) {
return;
}

// remove all key/value pairs (event name -> event handler)
if (arguments.length === 0) {
for (eventName in this.__eventListeners) {
_removeEventListener.call(this, eventName);
if (typeof arg0 === 'undefined') {
for (const eventName in this.__eventListeners) {
this._removeEventListener(eventName);
}
}
// one object with key/value pairs was passed
else if (typeof eventName === 'object' && typeof handler === 'undefined') {
for (var prop in eventName) {
_removeEventListener.call(this, prop, eventName[prop]);
else if (typeof arg0 === 'object') {
for (const eventName in arg0) {
this._removeEventListener(eventName, arg0[eventName]);
}
} else {
_removeEventListener.call(this, eventName, handler);
this._removeEventListener(arg0, handler);
}
}

/**
* Fires event with an optional options object
* @memberOf fabric.Observable
* @param {String} eventName Event name to fire
* @param {Object} [options] Options object
*/
function fire(eventName, options) {
fire(eventName: string, options: object) {
if (!this.__eventListeners) {
return;
}

var listenersForEvent = this.__eventListeners[eventName];
if (!listenersForEvent) {
return;
}

for (var i = 0, len = listenersForEvent.length; i < len; i++) {
listenersForEvent[i] && listenersForEvent[i].call(this, options || {});
const listenersForEvent = this.__eventListeners[eventName]?.concat();
if (listenersForEvent) {
for (let i = 0; i < listenersForEvent.length; i++) {
listenersForEvent[i].call(this, options || {});
}
}
this.__eventListeners[eventName] = listenersForEvent.filter(function (
value
) {
return value !== false;
});
}
}

/**
* @namespace fabric.Observable
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}
* @see {@link http://fabricjs.com/events|Events demo}
*/
fabric.Observable = {
fire: fire,
on: on,
once: once,
off: off,
};
})(typeof exports !== 'undefined' ? exports : window);
fabric.Observable = Observable;
9 changes: 0 additions & 9 deletions src/shapes/itext.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { FabricObject } from './object.class';
* prefix when observing canvas.
* @class fabric.IText
* @extends fabric.Text
* @mixes fabric.Observable
*
* @fires changed
* @fires selection:changed
Expand Down Expand Up @@ -57,15 +56,7 @@ import { FabricObject } from './object.class';
*/
fabric.IText = fabric.util.createClass(
fabric.Text,
fabric.Observable,
/** @lends fabric.IText.prototype */ {
/**
* Type of an object
* @type String
* @default
*/
type: 'i-text',

/**
* Index where text selection starts (or where cursor is when there is no selection)
* @type Number
Expand Down
1 change: 1 addition & 0 deletions src/shapes/object.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fabric } from '../../HEADER';
import { cache } from '../cache';
import { config } from '../config';
import { VERSION } from '../constants';
import { Observable } from '../mixins/observable.mixin';
import { Point } from '../point.class';
import { capValue } from '../util/misc/capValue';
import { pick } from '../util/misc/pick';
Expand Down
2 changes: 0 additions & 2 deletions src/shapes/text.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,4 @@ import { DEFAULT_SVG_FONT_SIZE } from '../constants';
'fantasy',
'monospace',
];

fabric.util.createAccessors && fabric.util.createAccessors(fabric.Text);
})(typeof exports !== 'undefined' ? exports : window);
3 changes: 1 addition & 2 deletions src/shapes/textbox.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
* wrapping of lines.
* @class fabric.Textbox
* @extends fabric.IText
* @mixes fabric.Observable
* @return {fabric.Textbox} thisArg
* @see {@link fabric.Textbox#initialize} for constructor definition
*/
fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, {
fabric.Textbox = fabric.util.createClass(fabric.IText, {
/**
* Type of an object
* @type String
Expand Down
11 changes: 10 additions & 1 deletion src/static_canvas.class.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ts-nocheck
import { config } from './config';
import { VERSION } from './constants';
import { Observable } from './mixins/observable.mixin';
import { Point } from './point.class';
import { requestAnimFrame } from './util/animate';
import { removeFromArray } from './util/internals';
Expand Down Expand Up @@ -1853,7 +1854,15 @@ import { FabricObject } from './shapes/object.class';
}
);

extend(fabric.StaticCanvas.prototype, fabric.Observable);
// hack - class methods are not enumrable
// TODO remove when migrating to es6
Object.getOwnPropertyNames(Observable.prototype).forEach(key => {
if (key === 'constructor') return;
Object.defineProperty(fabric.StaticCanvas.prototype, key, {
value: Observable.prototype[key]
});
});

extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);

extend(
Expand Down
Loading

0 comments on commit 09d32e3

Please sign in to comment.