@brusalk/react-wow-addon
Version:
React-style UI Framework for World of Warcraft AddOns
208 lines (207 loc) • 7.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.pascalCase = exports.sentenceCase = exports.P = exports.updateFrameProperties = exports.cleanupFrame = exports.createFrame = void 0;
const frameCache = {};
function getCache(type) {
// if (frameCache[type]) {
// return frameCache[type].length ? frameCache[type].pop() : undefined;
// }
return undefined;
}
function setCache(frame) {
const type = frame.GetObjectType();
print('store cache', type);
if (frameCache[type] && frameCache[type].length) {
frameCache[type].push(frame);
}
else {
frameCache[type] = [frame];
}
}
function createFrame(jsxType, parentFrame, props) {
const frameType = pascalCase(jsxType);
let frame = getCache(frameType);
if (frame) {
print('got frame from cache', frameType, frame, 'parent:', parentFrame);
frame.SetParent(parentFrame);
frame.Show();
return frame;
}
if (frameType === 'FontString') {
frame = parentFrame
.CreateFontString(props.name, props.DrawLayer || 'ARTWORK', props.inheritsFrom);
}
else if (frameType === 'Texture') {
frame = parentFrame
.CreateTexture(props.name, props.DrawLayer || 'ARTWORK', props.inheritsFrom);
}
else {
frame =
CreateFrame(frameType, props.name, parentFrame, props.inheritsFrom || "BackdropTemplate");
}
// frame.SetParent(parentFrame);
print('created frame:', frameType);
return frame;
}
exports.createFrame = createFrame;
function cleanupFrame(frame) {
print('cleaning up frame', frame.GetObjectType(), frame);
frame.Hide();
frame.ClearAllPoints();
if (frame.GetObjectType() === 'Texture' ||
frame.GetObjectType() === 'FontString') {
frame.SetParent(UIParent);
}
else {
frame.SetParent(null);
}
setCache(frame);
}
exports.cleanupFrame = cleanupFrame;
const isEvent = (name) => name.startsWith('On');
const isStandardProperty = (name) => !isEvent(name) &&
!isOrderedProperty(name) && name !== 'children' && name !== 'Points' && name !== 'Point' &&
name !== 'name' && name !== 'DrawLayer' && name !== 'inheritsFrom' && name !== 'Clickable' &&
name !== 'Draggable';
/**
* These properties must be set _before_ their other properties e.g. Background
* must be set before BackgroundColor
*/
const isOrderedProperty = (name) => name === 'Font' ||
name === 'Background' || name === 'Texture' || name === 'Backdrop';
/**
* These properties take table values, which should be set verbatim. Array
* values will apply each item as an argument to SetX. These values should not
* be interpreted as arrays.
*/
const isTableValue = (name) => name === 'Backdrop';
function updateFrameProperties(frame, prevProps, nextProps) {
updateFramePoints(frame, nextProps);
updateFrameLayer(frame, nextProps);
updateFrameEvents(frame, prevProps, nextProps);
updateOrderSpecificProperties(frame, prevProps, nextProps);
updateRemainingProperties(frame, prevProps, nextProps);
}
exports.updateFrameProperties = updateFrameProperties;
function updateOrderSpecificProperties(frame, prevProps, nextProps) {
// Remove properties that are no longer specified
Object.keys(prevProps)
.filter(key => isOrderedProperty(key) && !nextProps[key])
.forEach(key => {
attemptSetProperty(frame, key, null);
});
// Set properties
Object.keys(nextProps).filter(isOrderedProperty).forEach(key => {
attemptSetProperty(frame, key, nextProps[key]);
});
}
function updateRemainingProperties(frame, prevProps, nextProps) {
// Remove properties that are no longer specified
Object.keys(prevProps)
.filter(key => isStandardProperty(key) && !nextProps[key])
.forEach(key => {
attemptSetProperty(frame, key, null);
});
// Set properties
Object.keys(nextProps).filter(isStandardProperty).forEach(key => {
attemptSetProperty(frame, key, nextProps[key]);
});
}
function updateFrameEvents(frame, prevProps, nextProps) {
// Detach removed event listeners
Object.keys(prevProps)
.filter(key => isEvent(key) && !nextProps[key])
.forEach(event => {
frame.SetScript(event, undefined);
});
if (nextProps['Clickable']) {
frame.RegisterForClicks('RightButton');
}
if (nextProps['Draggable']) {
frame.RegisterForDrag(...nextProps['Draggable']);
}
// Add new event listeners
Object.keys(nextProps)
.filter(key => isEvent(key) && prevProps[key] !== nextProps[key])
.forEach(event => {
// print('attaching event', event);
frame.SetScript(event, nextProps[event]);
});
}
/** Handle frame points, size to parent unless specified. */
function updateFramePoints(frame, nextProps) {
frame.ClearAllPoints();
if (nextProps.Point) {
setPoint(frame, nextProps.Point);
return;
}
if (nextProps.Points) {
const points = nextProps.Points;
points.forEach(pointDef => setPoint(frame, pointDef));
}
else {
// Fill to parent
frame.SetAllPoints();
}
}
/** Handle frame points, size to parent unless specified. */
function updateFrameLayer(frame, nextProps) {
const region = frame;
const layer = nextProps.DrawLayer;
if (!layer || typeof region.SetDrawLayer !== 'function') {
return;
}
if (typeof layer === 'string') {
region.SetDrawLayer(layer, 0);
return;
}
region.SetDrawLayer(layer[0], layer[1]);
}
/** Create a point declaration */
function P(point, x, y, relativePoint, relativeFrame) {
// TODO: memoize for perf
return { point, relativePoint, relativeFrame, x, y };
}
exports.P = P;
function setPoint(frame, pointDef) {
if (typeof pointDef === 'string') {
frame.SetPoint(pointDef);
}
else {
const { point, relativePoint, relativeFrame, x, y } = pointDef;
const relativeTo = relativePoint || point;
// print('setPoint', Object.keys(pointDef).join(', '));
if (relativeFrame) {
frame.SetPoint(point, relativeFrame, relativeTo, x || 0, y || 0);
}
else {
const parent = frame.GetParent();
frame.SetPoint(point, parent, relativeTo, x || 0, y || 0);
}
}
}
function attemptSetProperty(frame, key, value) {
const region = frame;
const setter = `Set${key}`;
const setterFn = region[setter];
assert(setterFn, `Tried to use ${setter} and it did not exist on ${region}`);
if (setterFn && typeof setterFn == 'function') {
if (typeof value === 'string' || typeof value === 'number' ||
typeof value === 'boolean' || isTableValue(key)) {
region[setter](value);
}
else {
// print( `calling ${setter} with array elements as args:`,
// (value as any[]).join(', '));
setterFn.apply(region, value);
}
}
}
function sentenceCase(str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase();
}
exports.sentenceCase = sentenceCase;
function pascalCase(kebabCase) {
return kebabCase.split('-').map(sentenceCase).join('');
}
exports.pascalCase = pascalCase;