dol-match-bracket
Version:
- Javascript Library to make tree structured tournament brackets. - using Recursion to generate tournament bracket based on match JSON not team JSON(example below)
161 lines (136 loc) • 5.2 kB
text/typescript
//@ts-nocheck
const messageMap = new Map();
messageMap.set('container', 'Container not found. check your selector');
messageMap.set('noFinal', 'Final game not found. The data needs one element with a null value of "next".');
messageMap.set('overFinal', 'Only one element is allowed to have a null value of "next".');
messageMap.set('overId', 'There are more than two items with the same "next" value. -');
/**
* @param defaultConfig 기본옵션
* @param defaultConfig.con 기본옵션
* @param defaultConfig.containerClass 컨테이너의 기본 클래스
* @param defaultConfig.matchClass 각 매치별 래퍼
* @param defaultConfig.matchType 매치의 타입 - match-type-right || match-type-left || match-type-top
* @param defaultConfig.mainGameClass 매치의 래퍼
* @param defaultConfig.subGameClass 매치의 서브 매치그루핑용
* @param defaultConfig.hasByeClass 부전승 경기가 있을경우 사용할 클래스
* @param defaultConfig.itemTemplate 각 매치의 기본템플릿 {{ }} 를 사용하여 데이터의 변수 사용
* @param defaultConfig.leftClass 서브 매치의 왼쪽 구분
* @param defaultConfig.rightClass 서브 매치의 오른쪽 구분
* */
const defaultConfig = {
containerClass: 'dol-bracket',
matchClass: 'dol-bracket-match',
// matchType: 'match-type-right',
// matchType: 'match-type-left',
// matchType: 'match-type-top',
mainGameClass: 'dol-bracket-main',
subGameClass: 'dol-bracket-sub',
hasByeClass: 'dol-bracket-bye',
itemTemplate: '<div class="dol-bracket-item">{{school1}} : {{school2}}</div>',
leftClass: 'dol-bracket-left',
rightClass: 'dol-bracket-right',
};
/**
* @param {object} match current match data
* @param {gameObject[]} data all match data
* @param {object} options
* @param {-1|1} [pos] direction, -1: left, 1:right
* */
function makeMatchFragment(match, data, options, pos) {
const groupEle = document.createElement('div');
const gameTpl = options.itemTemplate.replace(/{{\s*([^}]*)\s*}}/g, (_, key) => `${match[key]}`);
const subGames = data.filter((item) => item.next === match.id);
if (subGames.length > 2) {
console.warn(`${messageMap.get('overId')} ${match.id}`);
}
groupEle.classList.add(options.matchClass);
// 매치의 왼쪽 오른쪽 구분(옵션)
if (pos) {
groupEle.classList.add(pos < 0 ? options.leftClass : options.rightClass);
}
groupEle.innerHTML = `<div class="${options.mainGameClass}">${gameTpl}</div>`;
if (subGames.length) {
const subGroupEle = document.createElement('div');
subGroupEle.classList.add(options.subGameClass);
if (subGames.length === 1) {
subGroupEle.classList.add(options.hasByeClass);
} else {
// 왼쪽 오른쪽 구분을 위해 정렬(옵션), pos값이 없으면 그대로
subGames.sort(function (a, b) {
if (a.pos === 'left' || b.pos === 'right') {
return -1;
}
if (a.pos === 'right' || b.pos === 'left') {
return 1;
}
return 0;
});
}
if (options.matchType === "match-type-top" || options.matchType === "match-type-left"){
if (subGames[0]) {
subGroupEle.prepend(makeMatchFragment(subGames[0], data, options, -1));
}
if (subGames[1]) {
subGroupEle.prepend(makeMatchFragment(subGames[1], data, options, 1));
}
groupEle.prepend(subGroupEle);
}else{
if (subGames[0]) {
subGroupEle.append(makeMatchFragment(subGames[0], data, options, -1));
}
if (subGames[1]) {
subGroupEle.append(makeMatchFragment(subGames[1], data, options, 1));
}
groupEle.append(subGroupEle);
}
}
return groupEle;
}
/**
* @param {string|node element} selector
* @param {gameObject[]} data all match data
* @param {object} confit user defined options
*
* @description Given date, with year, get Days and insert into DOM on [Schedule page #result]
* */
function makeBracket(selector, data, config) {
const finalGame = data.filter((item) => !item.next);
let container;
let options;
let fragment = document.createElement('div');
if (typeof selector === 'string') {
container = document.querySelector(selector);
} else if (selector.nodeName) {
container = selector;
}
if (!container) {
throw messageMap.get('container');
}
// 최종 경기가 하나만 있어야 함
if (!finalGame.length) {
throw messageMap.get('noFinal');
} else if (finalGame.length > 1) {
throw messageMap.get('overFinal');
}
options = Object.assign(defaultConfig, config);
fragment = makeMatchFragment(finalGame[0], data, options);
container.classList.add(options.containerClass);
if(options.matchType){
container.classList.add(options.matchType);
}
container.append(fragment);
}
// 모듈화
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS
module.exports = factory;
} else {
// browser
root.MakeDolBracket = factory;
}
})(this, makeBracket);