Last active
November 14, 2016 04:54
-
-
Save bowbowbow/bec0961944aa1bd02b30ceab5121039a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by clsrn1581 on 2016. 09. 22... | |
*/ | |
// Common Modules... | |
// 예전 버전에서 사용하던 태그 | |
import React from 'react'; | |
import { Additory } from 'additor-elements'; | |
// Own Modules... | |
import Panel from '../../../../basic/components/Panel.jsx'; | |
/** | |
* string에서 substring의 모든 시작 인덱스를 배열형태로 반환 | |
* @param substring | |
* @param string | |
* @returns {Array} | |
*/ | |
function locations(substring, string) { | |
const a = []; | |
let i = -1; | |
while ((i = string.indexOf(substring, i + 1)) >= 0) { | |
a.push(i); | |
} | |
return a; | |
} | |
export default class TagPanel extends Panel { | |
constructor(props) { | |
super(props); | |
this.state = { | |
tagInput: '', | |
tags: [], | |
suggestions: ['Banana', 'Apple', 'Melon'], // 자동완성 아직 미 구현 | |
}; | |
this.handleChangeTag = this._handleChangeTag.bind(this); | |
this.handleKeyPressTag = this._handleKeyPressTag.bind(this); | |
this.handleKeyDownTag = this._handleKeyDownTag.bind(this); | |
this.handleFocus = this._handleFocus.bind(this); | |
this.moveCursorEnd = this._moveCursorEnd.bind(this); | |
} | |
_handleChangeTag(e) { | |
this.setState({ | |
tagInput: e.target.value, | |
}); | |
} | |
_handleKeyPressTag(e) { | |
const { tagInput } = this.state; | |
if (e.key === 'Enter') { | |
// 엔터가 입력됐을 때 진입 | |
this.setState({ | |
tagInput: `${tagInput}∙`, | |
}, () => { | |
// 태그 입력들의 일관성을 유지시키는 과정 | |
const tagRaws = tagInput.split('∙'); | |
const tags = []; | |
// 입력에 존재하는 태그에서 중복과 스페이스를 제거 함 | |
tagRaws.forEach((tag) => { | |
const tagS = tag.replace(/ /g, '_'); | |
const index = tags.indexOf(tagS); | |
if (tagS !== '') { | |
if (index === -1) { | |
tags.push(tagS); | |
} else { | |
tags.splice(index, 1); | |
tags.push(tagS); | |
} | |
} | |
}); | |
this.setState({ | |
tags, | |
tagInput: `${tags.join('∙')}∙`, | |
}, () => { | |
// 상위 컴포넌트에서 태그 값 설정 | |
this.props.setTags(tags); | |
// ∙이 추가되서 커서 포커스가 가장 오른쪽으로 안 옮겨지는 상황이 있어서 | |
this.moveCursorEnd(); | |
}); | |
}); | |
} | |
} | |
/** | |
* backspace 입력 발생 시 구분자 바깥에 있는 태그는 한 글자식 지우고 | |
* 구분 자 안에 있는 태그는 태그 단위로 지운다. | |
* @param e | |
*/ | |
_handleKeyDownTag(e) { | |
if (e.keyCode === 8) { | |
const { tags } = this.state; | |
const input = this.refs['addit-widget-card-tag']; | |
let cursorPos = input.selectionEnd; | |
if (cursorPos !== 0) { | |
/** | |
* 커서는 단어 사이마다 인덱스가 부여되기 때문에 단어와 인덱스를 맞춰주기 위함 | |
*/ | |
cursorPos -= 1; | |
} | |
// 어떤 태그 단락을 삭제할 지 탐색하는 과정 | |
const indexes = locations('∙', input.value); | |
indexes.unshift(-1); | |
let posIndex = -1; | |
for (let i = 0; i < indexes.length - 1; i++) { | |
if (indexes[i] < cursorPos && cursorPos <= indexes[i + 1]) { | |
posIndex = i; | |
break; | |
} | |
} | |
if (posIndex !== -1) { | |
// 삭제 할 단락이 존재할 때 진입 | |
_.pullAt(tags, posIndex); | |
let tagInput = tags.join('∙'); | |
if (tagInput !== '') { | |
tagInput += '∙'; | |
} | |
this.setState({ | |
tags, | |
tagInput, | |
}, () => { | |
// 상위 컴포넌트에서 태그 값 설정 | |
this.props.setTags(tags); | |
// 삭제 된 이후에도 커서가 가장 오른쪽으로 옮겨지지 않고 원래 위치를 유지하기 위해서 | |
input.selectionStart = input.selectionEnd = cursorPos; | |
input.scrollLeft = cursorPos; | |
}); | |
// backspace 입력을 차단 함 | |
e.preventDefault(); | |
e.stopPropagation(); | |
} | |
} | |
} | |
/** | |
* 포커스 시 커서를 인풋 가장 뒤로 옮긴다. | |
* @param e | |
* @private | |
*/ | |
_handleFocus(e) { | |
this.moveCursorEnd(); | |
} | |
/** | |
* 인풋창의 커서를 가장 오른쪽으로 옮긴다. | |
* @private | |
*/ | |
_moveCursorEnd() { | |
const { tagInput } = this.state; | |
/** | |
* 포커스 시 커서를 오른쪽으로 당겨야 하는데 포커스 시 마우스가 놓인 자리에 | |
* 커서가 생기기 때문에 setTimeout으로 약간 딜레이를 줌 | |
*/ | |
setTimeout(() => { | |
const input = this.refs['addit-widget-card-tag']; | |
input.selectionStart = input.selectionEnd = tagInput.length; | |
input.scrollLeft = input.scrollWidth; | |
}, 10); | |
} | |
render() { | |
const { tagInput } = this.state; | |
return ( | |
<div id="addit-widget-card-tag-wrapper"> | |
<input | |
ref="addit-widget-card-tag" | |
id="addit-widget-card-tag" | |
value={tagInput} | |
onChange={this.handleChangeTag} | |
onKeyPress={this.handleKeyPressTag} | |
onKeyDown={this.handleKeyDownTag} | |
onFocus={this.handleFocus} | |
placeholder="Add a tag" | |
style={{ color: (tagInput.length > 0 ? '#3A434C' : '#B8BDC2') }} | |
/> | |
</div> | |
); | |
} | |
} | |
TagPanel.propTypes = { | |
setTags: React.PropTypes.func, | |
}; | |
TagPanel.defaultProps = {}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment