Skip to content

Instantly share code, notes, and snippets.

@chj1768
Last active December 11, 2018 17:05
Show Gist options
  • Save chj1768/d9f4bc26b20e82ef009dbf45ca202144 to your computer and use it in GitHub Desktop.
Save chj1768/d9f4bc26b20e82ef009dbf45ca202144 to your computer and use it in GitHub Desktop.
#5
<html>
<body>
<p id="base"></p>
</body>
<script>
const Task = class{
constructor(title, date){
this._title = title,
this._date = date,
this._isComplete = false;
this._list = [];
}
isComplete(){return this._isComplete;}
toggle(){
this._isComplete = !this._isComplete;
}
add(title, date = null){
this._list.push(new Task(title, date));
}
remove(task){
const list = this._list;
if(list.includes(task))
list.splice(list.indexOf(task), 1);
}
byTitle(stateGroup = true){return this.list('title', stateGroup);}
byDate(stateGroup = true){return this.list('date', stateGroup);}
list(sort, stateGroup = true){
const list = this._list,
f = (a, b)=>a[sort] > b[sort];
const map = task=>task.list(sort, stateGroup);
return {
task:this,
list:!stateGroup ? [...list].sort(f).map(map) : [...list.filter(v=>!v.isComplete()).sort(f).map(map),
...list.filter(v=>v.isComplete()).sort(f).map(map)]
};
}
};
const el = (tag, attr={})=>Object.entries(attr).reduce((el, v)=>{
typeof el[v[0]] == 'function' ? el[v[0]](v[1]) : (el[v[0]] = v[1]);return el;},
document.createElement(tag));
const Renderer = class{
constructor(processor){
this.p = processor;
processor.addObserver(this);
}
observe(type){
type=='rerender'&&this.rerender();
}
rerender(){
this.oldList && this.render(this.oldList);
}
render({task, list}){
this.oldList = {task, list};
this.p.folder(task);
this.p.parent(task);
this.subTask(list);
}
subTask(list){
list.forEach(({task, list})=>{
this.p.task(task);
if(list.length){
this.p.parent(task);
this.subTask(list);
}
});
}
};
Renderer.Processor = class{
constructor(){
this.prop = Object.create(null);
this._tv=TaskView.base;
}
observe(msg){
this.notify(msg);
}
addObserver(v){
this.observer = v;
}
notify(msg){
this.observer && this.observer.observe(msg);
}
taskView(...tv){
tv.forEach(tv=>this._tv = tv.set(this._tv));
}
folder(task){
throw 'override';
}
task(task){
throw 'override';
}
parent(task){
throw 'override';
}
remove(task){
throw 'override';
}
taskRender(task){
this._tv.addObserver(this);
return this._tv.task(this.prop.ptask, task);
}
};
const Dom = class extends Renderer.Processor{
constructor(parent){
super();
this._p = parent;
}
folder(task){
const parent = document.querySelector(this._p);
parent.innerHTML = '';
this.prop.parent = parent;
this.parent(task);
this.task(task);
}
task(task){
const li = this.taskRender(task);
this.prop.parent.appendChild(li);
if(task._list.length)
this.prop.parent = li;
}
parent(task){
const ul = el('ul');
this.prop.parent.appendChild(ul);
this.prop.parent = ul;
this.prop.ptask = task;
}
};
const TaskView = class{
addObserver(v){
this.observer = v;
}
notify(msg){
this.observer && this.observer.observe(msg);
}
set(tv){
this._tv = tv;
return this;
}
task(parent, task){
this.result = this._tv ? this._tv.task(parent, task) : el('li', {innerHTML : task._title});
return this._task(parent, task);
}
_task(parent, task){
throw "override!"
}
};
TaskView.base = new (class extends TaskView{
constructor() {
super();
}
_task(parent, task){
return this.result;
}
});
const Priority = class extends TaskView{
constructor() {
super();
this._reg = new RegExp(/\[(urgent|high|normal|low)\]/,'gi');
}
_task(parent, task){
const word = this.result.innerText.match(this._reg);
if(word) {
this.result.innerHTML = `<strong>${word[0]}</strong>${this.result.innerHTML.replace(this._reg, "")}`;
}
return this.result;
}
};
const Member = class extends TaskView{
constructor(...members){
super();
this._reg = new RegExp(`@(${members.join('|')})`, 'g');
}
_task(parent, task){
const word = this.result.innerText.match(this._reg);
if(word) {
this.result.innerHTML = `${this.result.innerHTML.replace(this._reg, "")}<a href=${word[0].replace("@", "")}>${word[0].replace("@", "")}</a>`;
}
return this.result;
}
};
const Remove = class extends TaskView{
constructor() {
super();
}
_task(parent, task){
const remove = e => {
parent.remove(task);
e.currentTarget.parentElement.remove();
};
const a = el('button', {innerHTML : 'X'});
a.onclick = remove;
this.result.appendChild(a);
return this.result;
}
};
const folder = new Task('[high]s3-4@aaa');
folder.add("2강교안작성");
folder.add("3강교안작성");
const {list} = folder.list('title');
list[1].task.add('ppt정리 @bbb');
list[1].task.add('코드정리 @aaa');
const {list:sublist} = list[1].task.list('title');
sublist[1].task.add('[high]슬라이드마스터정리');
sublist[1].task.add('디자인개선');
const dom = new Dom('#base');
dom.taskView(new Member('aaa', 'bbb'), new Priority(), new Remove());
const renderer = new Renderer(dom);
renderer.render(folder.list('title'));
</script>
</html>
@chj1768
Copy link
Author

chj1768 commented Dec 11, 2018

practice #1, #2 [심화] 포함.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment