- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
/**
* Collection of valid extension types.
* @memberof PIXI
* @property {string} Application - Application plugins
* @property {string} RendererPlugin - Plugins for Renderer
* @property {string} CanvasRendererPlugin - Plugins for CanvasRenderer
* @property {string} Loader - Plugins to use with Loader
* @property {string} LoadParser - Parsers for Assets loader.
* @property {string} ResolveParser - Parsers for Assets resolvers.
* @property {string} CacheParser - Parsers for Assets cache.
*/
enum ExtensionType
// eslint-disable-next-line @typescript-eslint/indent
{
Application = 'application',
RendererPlugin = 'renderer-webgl-plugin',
CanvasRendererPlugin = 'renderer-canvas-plugin',
Loader = 'loader',
LoadParser = 'load-parser',
ResolveParser = 'resolve-parser',
CacheParser = 'cache-parser',
DetectionParser = 'detection-parser',
}
interface ExtensionMetadataDetails
{
type: ExtensionType | ExtensionType[];
name?: string;
}
type ExtensionMetadata = ExtensionType | ExtensionMetadataDetails;
/**
* Format when registering an extension. Generally, the extension
* should have these values as `extension` static property,
* but you can override name or type by providing an object.
* @memberof PIXI
*/
interface ExtensionFormatLoose
{
/** The extension type, can be multiple types */
type: ExtensionType | ExtensionType[];
/** Optional. Some plugins provide an API name/property, such as Renderer plugins */
name?: string;
/** Reference to the plugin object/class */
ref: any;
}
/**
* Strict extension format that is used internally for registrations.
* @memberof PIXI
*/
interface ExtensionFormat extends ExtensionFormatLoose
{
/** The extension type, always expressed as multiple, even if a single */
type: ExtensionType[];
}
type ExtensionHandler = (extension: ExtensionFormat) => void;
/**
* Convert input into extension format data.
* @ignore
*/
const normalizeExtension = (ext: ExtensionFormatLoose | any): ExtensionFormat =>
{
// Class/Object submission, use extension object
if (typeof ext === 'function' || (typeof ext === 'object' && ext.extension))
{
// #if _DEBUG
if (!ext.extension)
{
throw new Error('Extension class must have an extension object');
}
// #endif
const metadata: ExtensionMetadataDetails = (typeof ext.extension !== 'object')
? { type: ext.extension }
: ext.extension;
ext = { ...metadata, ref: ext };
}
if (typeof ext === 'object')
{
ext = { ...ext };
}
else
{
throw new Error('Invalid extension type');
}
if (typeof ext.type === 'string')
{
ext.type = [ext.type];
}
return ext;
};
/**
* Global registration of all PixiJS extensions. One-stop-shop for extensibility.
* @memberof PIXI
* @namespace extensions
*/
const extensions = {
/** @ignore */
_addHandlers: null as Record<ExtensionType, ExtensionHandler>,
/** @ignore */
_removeHandlers: null as Record<ExtensionType, ExtensionHandler>,
/** @ignore */
_queue: {} as Record<ExtensionType, ExtensionFormat[]>,
/**
* Remove extensions from PixiJS.
* @param extensions - Extensions to be removed.
* @returns {PIXI.extensions} For chaining.
*/
remove(...extensions: Array<ExtensionFormatLoose | any>)
{
extensions.map(normalizeExtension).forEach((ext) =>
{
ext.type.forEach((type) => this._removeHandlers[type]?.(ext));
});
return this;
},
/**
* Register new extensions with PixiJS.
* @param extensions - The spread of extensions to add to PixiJS.
* @returns {PIXI.extensions} For chaining.
*/
add(...extensions: Array<ExtensionFormatLoose | any>)
{
// Handle any extensions either passed as class w/ data or as data
extensions.map(normalizeExtension).forEach((ext) =>
{
ext.type.forEach((type) =>
{
const handlers = this._addHandlers;
const queue = this._queue;
if (!handlers[type])
{
queue[type] = queue[type] || [];
queue[type].push(ext);
}
else
{
handlers[type](ext);
}
});
});
return this;
},
/**
* Internal method to handle extensions by name.
* @param type - The extension type.
* @param onAdd - Function for handling when extensions are added/registered passes {@link PIXI.ExtensionFormat}.
* @param onRemove - Function for handling when extensions are removed/unregistered passes {@link PIXI.ExtensionFormat}.
* @returns {PIXI.extensions} For chaining.
*/
handle(type: ExtensionType, onAdd: ExtensionHandler, onRemove: ExtensionHandler)
{
const addHandlers = this._addHandlers = this._addHandlers || {} as Record<ExtensionType, ExtensionHandler>;
const removeHandlers = this._removeHandlers = this._removeHandlers || {} as Record<ExtensionType, ExtensionHandler>;
// #if _DEBUG
if (addHandlers[type] || removeHandlers[type])
{
throw new Error(`Extension type ${type} already has a handler`);
}
// #endif
addHandlers[type] = onAdd;
removeHandlers[type] = onRemove;
// Process the queue
const queue = this._queue;
// Process any plugins that have been registered before the handler
if (queue[type])
{
queue[type].forEach((ext) => onAdd(ext));
delete queue[type];
}
return this;
},
/**
* Handle a type, but using a map by `name` property.
* @param type - Type of extension to handle.
* @param map - The object map of named extensions.
* @returns {PIXI.extensions} For chaining.
*/
handleByMap(type: ExtensionType, map: Record<string, any>)
{
return this.handle(type,
(extension) =>
{
map[extension.name] = extension.ref;
},
(extension) =>
{
delete map[extension.name];
}
);
},
/**
* Handle a type, but using a list of extensions.
* @param type - Type of extension to handle.
* @param list - The list of extensions.
* @returns {PIXI.extensions} For chaining.
*/
handleByList(type: ExtensionType, list: any[])
{
return this.handle(
type,
(extension) =>
{
list.push(extension.ref);
// TODO: remove me later, only added for @pixi/loaders
if (type === ExtensionType.Loader)
{
extension.ref.add?.();
}
},
(extension) =>
{
const index = list.indexOf(extension.ref);
if (index !== -1)
{
list.splice(index, 1);
}
}
);
},
};
export {
extensions,
ExtensionType,
};
export type {
ExtensionHandler,
ExtensionMetadata,
ExtensionFormatLoose,
ExtensionFormat,
};