1 |
|
2 | var Emoji = function Emoji(params) {
|
3 | |
4 |
|
5 |
|
6 | var defaults = {
|
7 | data: null,
|
8 |
|
9 | mask: null,
|
10 | maskClass: 'emoji-mask',
|
11 | maskActiveClass: 'active',
|
12 | isClickMaskHide: true,
|
13 |
|
14 | containerClass: 'emoji',
|
15 | containerActiveClass: 'active',
|
16 |
|
17 | submitClass: 'emoji-edit-submit',
|
18 |
|
19 | textareaClass: 'emoji-edit-input',
|
20 |
|
21 | iconClass: 'emoji-edit-icon',
|
22 |
|
23 | faceClass: 'emoji-face',
|
24 | faceNameAttr: 'title',
|
25 | faceIdAttr: 'data-emoji',
|
26 | deleteClass: 'emoji-face-delete',
|
27 |
|
28 | carrouselClass: 'emoji-carrousel'
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | };
|
36 | params = params || {};
|
37 | for (var def in defaults) {
|
38 | if (params[def] === undefined) {
|
39 | params[def] = defaults[def];
|
40 | }
|
41 | }
|
42 |
|
43 |
|
44 | var s = this;
|
45 |
|
46 |
|
47 | s.params = params;
|
48 |
|
49 |
|
50 | s.mask = typeof s.params.mask === 'string' ? document.querySelector(s.params.mask) : s.params.mask;
|
51 | if (!s.mask) {
|
52 | console.log('SeedsUI Error:未找到Emoji的mask元素,请检查传入参数是否正确');
|
53 | return;
|
54 | }
|
55 |
|
56 |
|
57 | s.container = s.mask.querySelector('.' + s.params.containerClass);
|
58 | if (!s.container) {
|
59 | console.log('SeedsUI Error:未找到Emoji的container元素,请检查传入参数是否正确');
|
60 | return;
|
61 | }
|
62 |
|
63 |
|
64 | s.textarea = s.mask.querySelector('.' + s.params.textareaClass + ' textarea');
|
65 | if (!s.textarea) {
|
66 | console.log('SeedsUI Error:未找到Emoji的textarea元素,请检查传入参数是否正确');
|
67 | return;
|
68 | }
|
69 | if (s.textarea.tagName !== 'TEXTAREA') {
|
70 | console.log('SeedsUI Error:Emoji的textarea元素必须为一个textarea');
|
71 | return;
|
72 | }
|
73 |
|
74 |
|
75 | s.icon = s.mask.querySelector('.' + s.params.iconClass);
|
76 | if (!s.textarea) {
|
77 | console.log('SeedsUI Error:未找到Emoji的icon元素,请检查传入参数是否正确');
|
78 | return;
|
79 | }
|
80 |
|
81 |
|
82 | s.carrousel = s.mask.querySelector('.' + s.params.carrouselClass);
|
83 | if (!s.textarea) {
|
84 | console.log('SeedsUI Error:未找到Emoji的carrousel元素,请检查传入参数是否正确');
|
85 | return;
|
86 | }
|
87 | |
88 |
|
89 |
|
90 |
|
91 | s.setData = function (data) {
|
92 | s.params.data = data;
|
93 | };
|
94 |
|
95 | s.showMask = function () {
|
96 | s.mask.classList.add(s.params.maskActiveClass);
|
97 | };
|
98 | s.hideMask = function () {
|
99 | s.mask.classList.remove(s.params.maskActiveClass);
|
100 | };
|
101 | s.destroyMask = function () {
|
102 | s.mask.parentNode.removeChild(s.mask);
|
103 | };
|
104 | s.showContainer = function () {
|
105 | s.container.classList.add(s.params.containerActiveClass);
|
106 | };
|
107 | s.hideContainer = function () {
|
108 | s.container.classList.remove(s.params.containerActiveClass);
|
109 | };
|
110 | s.show = function () {
|
111 | s.showMask();
|
112 | s.showContainer();
|
113 | };
|
114 | s.hide = function () {
|
115 | s.hideMask();
|
116 | s.hideContainer();
|
117 | };
|
118 |
|
119 | s.parse = function (str) {
|
120 | var emojiExpr = /(\[[\u4E00-\u9FA5]*\])/gm;
|
121 | var parseStr = str;
|
122 | while (emojiExpr.exec(str)) {
|
123 | if (s.params.data[RegExp.$1]) {
|
124 | parseStr = parseStr.replace(RegExp.$1, '<span ' + s.params.faceIdAttr + '=' + s.params.data[RegExp.$1] + '></span>');
|
125 | }
|
126 | }
|
127 | return parseStr;
|
128 | };
|
129 |
|
130 | s.cursorOffset = 0;
|
131 |
|
132 |
|
133 | s.insertFace = function (emojiName) {
|
134 |
|
135 | var value = s.textarea.value;
|
136 | var valueBefore = value.substr(0, s.cursorOffset);
|
137 | var valueAfter = value.substr(s.cursorOffset, value.length);
|
138 | var valueInsert = emojiName;
|
139 | s.cursorOffset = s.cursorOffset + emojiName.length;
|
140 | s.textarea.value = valueBefore + valueInsert + valueAfter;
|
141 |
|
142 |
|
143 |
|
144 | return s.textarea.value;
|
145 | };
|
146 |
|
147 | s.deleteFace = function () {
|
148 |
|
149 | var value = s.textarea.value;
|
150 | var valueBefore = value.substr(0, s.cursorOffset);
|
151 | var valueAfter = value.substr(s.cursorOffset, value.length);
|
152 | var isDeleted = false;
|
153 | if (!valueBefore) return value;
|
154 |
|
155 | for (var face in s.params.data) {
|
156 | if (valueBefore.lastIndexOf(face) !== -1 && valueBefore.lastIndexOf(face) === valueBefore.length - face.length) {
|
157 | valueBefore = valueBefore.substring(0, valueBefore.lastIndexOf(face));
|
158 | isDeleted = true;
|
159 | break;
|
160 | }
|
161 | }
|
162 |
|
163 | if (!isDeleted) {
|
164 | valueBefore = valueBefore.substring(0, valueBefore.length - 1);
|
165 | }
|
166 | s.cursorOffset = valueBefore.length;
|
167 | s.textarea.value = valueBefore + valueAfter;
|
168 |
|
169 |
|
170 |
|
171 | return s.textarea.value;
|
172 | };
|
173 |
|
174 | s.setCaretPosition = function (input, pos) {
|
175 | if (!input) return;
|
176 | if (input.createTextRange) {
|
177 | var range = input.createTextRange();
|
178 | range.move('character', pos);
|
179 | range.select();
|
180 | } else {
|
181 | if (input.selectionStart) {
|
182 | input.focus();
|
183 | input.setSelectionRange(pos, pos);
|
184 | } else {
|
185 | input.focus();
|
186 | }
|
187 | }
|
188 | };
|
189 | |
190 |
|
191 |
|
192 | s.preventDefault = function (e) {
|
193 | e.preventDefault();
|
194 | };
|
195 | s.events = function (detach) {
|
196 | var action = detach ? 'removeEventListener' : 'addEventListener';
|
197 | s.mask[action]('click', s.onClick, false);
|
198 |
|
199 | if (navigator.userAgent.toLowerCase().match(/cpu iphone os (.*?) like mac os/)) {
|
200 |
|
201 | s.textarea[action]('focus', s.onFocus, false);
|
202 |
|
203 | s.mask[action]('touchmove', s.preventDefault, false);
|
204 |
|
205 | s.textarea[action]('blur', s.onBlur, false);
|
206 | }
|
207 |
|
208 | document[action]('selectionchange', s.onSelectionChange, false);
|
209 | s.textarea[action]('input', s.onInput, false);
|
210 | };
|
211 | s.attach = function () {
|
212 | s.events();
|
213 | };
|
214 | s.detach = function () {
|
215 | s.events(false);
|
216 | };
|
217 | s.onClick = function (e) {
|
218 | var target = e.target;
|
219 | if (target.classList.contains(s.params.faceClass)) {
|
220 |
|
221 | var value = s.insertFace(target.getAttribute(s.params.faceNameAttr));
|
222 | if (s.params.onChange) s.params.onChange(value, s);
|
223 | } else if (target.classList.contains(s.params.iconClass)) {
|
224 |
|
225 | if (s.carrousel.style.display === 'none') {
|
226 | setTimeout(function () {
|
227 | s.carrousel.style.display = 'block';
|
228 | s.icon.classList.add('active');
|
229 | }, 100);
|
230 |
|
231 | s.textarea.disabled = true;
|
232 | } else {
|
233 | s.carrousel.style.display = 'none';
|
234 | s.icon.classList.remove('active');
|
235 | }
|
236 | } else if (target.classList.contains(s.params.maskClass)) {
|
237 |
|
238 | if (s.params.onClickMask) s.params.onClickMask(s, e);
|
239 | if (s.params.isClickMaskHide) s.hide();
|
240 | } else if (target.classList.contains(s.params.submitClass)) {
|
241 |
|
242 | if (s.params.onClickSubmit) s.params.onClickSubmit(s.textarea.value, s, e);
|
243 | if (s.params.isClickMaskHide) s.hide();
|
244 | } else if (target.classList.contains(s.params.deleteClass)) {
|
245 |
|
246 | s.deleteFace();
|
247 | } else if (target.tagName === 'TEXTAREA') {
|
248 |
|
249 | s.icon.classList.remove('active');
|
250 | s.carrousel.style.display = 'none';
|
251 | s.textarea.disabled = false;
|
252 | s.textarea.focus();
|
253 | }
|
254 | e.stopPropagation();
|
255 | };
|
256 |
|
257 | s.onFocus = function () {
|
258 | setTimeout(function () {
|
259 | document.body.scrollTop = document.body.scrollHeight;
|
260 | }, 300);
|
261 | };
|
262 |
|
263 | s.onBlur = function () {
|
264 | setTimeout(function () {
|
265 | document.body.scrollTop = 0;
|
266 | }, 10);
|
267 | };
|
268 |
|
269 | s.onSelectionChange = function (e) {
|
270 | if (Object.prototype.toString.call(e.target.activeElement) === '[object HTMLTextAreaElement]') {
|
271 | s.cursorOffset = s.textarea.selectionStart;
|
272 | }
|
273 | };
|
274 | s.onInput = function (e) {
|
275 | s.cursorOffset = e.target.selectionStart;
|
276 | };
|
277 | |
278 |
|
279 |
|
280 | s.init = function () {
|
281 | s.attach();
|
282 | };
|
283 | s.init();
|
284 | };
|
285 |
|
286 | export default Emoji; |
\ | No newline at end of file |