PageSourceSearch

https://bgsocial.com/application/modules/Yncomment/externals/scripts/composer_tag.js?c=21838

js bgsocial.com collected 2026-10-07 20:35:28 UTC 15,266 bytes, 382 lines download raw bytes

1ComposerYnComment.Plugin.Nctag = new Class({
2    Extends: ComposerYnComment.Plugin.Interface,
3    name: 'tag',
4    options: {
5        'enabled': false,
6        requestOptions: {},
7        'suggestOptions': {
8            'minLength': 1,
9            'maxChoices': 100,
10            'delay': 250,
11            'selectMode': 'pick',
12            'multiple': false,
13            'filterSubset': true,
14            'tokenFormat': 'object',
15            'tokenValueKey': 'label',
16            'injectChoice': $empty,
17            'onPush': $empty,
18            'prefetchOnInit': true,
19            'alwaysOpen': false,
20            'ignoreKeys': true,
21            'stopKeysEvent': false
22        }
23    },
24    initialize: function(options) {
25        this.params = new Hash(this.params);
26        this.parent(options);
27    },
28    suggest: false,
29    attach: function() {
30        this.parent();
31        // Key Events
32        var self = this;
33
34        this.getComposer().addEvent((1) ? 'editorKeyDown' : 'editorKeyPress',
35                function(event) {
36                    if (self.suggest && self.suggest.visible && event) {
37                        self.suggest.onCommand(event);
38                        if (self.suggest.stopKeysEvent) {
39                            event.stop();
40                            return;
41                        }
42                    }
43                    self.monitor.bind(self)(event);
44                }
45        );
46        this.getComposer().addEvent('editorClick', this.monitor.bind(this));
47
48        // Submit
49        this.getComposer().addEvent('editorSubmit', this.submit.bind(this));
50        return this;
51    },
52    detach: function() {
53        if (!this.options.enabled)
54            return;
55        this.parent();
56        this.getComposer().removeEvent('editorKeyPress', this.monitor.bind(this));
57        this.getComposer().removeEvent('editorClick', this.monitor.bind(this));
58        this.getComposer().removeEvent('editorSubmit', this.submit.bind(this));
59        if (this.interval)
60            $clear(this.interval);
61        return this;
62    },
63    activate: $empty,
64    deactivate: $empty,
65    poll: function() {
66
67    },
68    monitor: function(e) {
69        // seems like we have to do this stupid delay or otherwise the last key
70        // doesn't get in the content
71        (function() {
72            var selection = this.getComposer().selection;
73            var range = selection.getRange();
74            if (!range)
75                return;
76            var start = 0;
77            if (window.getSelection) {
78                start = range.startOffset;
79            } else if (document.selection) {
80                var range_t = document.selection.createRange();
81                if (range_t == null || range_t['text'] == null) {
82                } else {
83                    var textlength = selection.win.innerText.length;
84                    range.moveStart("character", -textlength);
85                    start = range.text.length;
86                }
87            }
88
89            var content = null;
90            if (range.startContainer) {
91                content = range.startContainer.data;
92            } else if (selection.win) {
93                content = selection.win.innerText;
94            }
95            if (!content)
96                return;
97
98            this.filterYnCommentTagsFromComposer();
99
100            var currentIndex = false;
101            content = content.substring(0, start);
102            currentIndex = content.lastIndexOf('@');
103            if (currentIndex == -1 || currentIndex >= start) {
104                this.endSuggest();
105                return;
106            }
107            // Get the current at segment
108            var segment = content.substring(currentIndex + 1, start);
109            if (segment.length < 1) {
110				this.endSuggest();
111                return;
112			}
113
114            this.doSuggest(segment);
115
116        }).delay(250, this);
117    },
118    doSuggest: function(text) 
119    {
120        this.currentText = text;
121        var tagged = '';
122        this.getComposer().elements.body.getElements('.yncomment_composer_tag').each(function(tag) 
123        {
124           tagged += tag.get('rel') + ',';
125        });
126        this.tagged = tagged;
127        var suggest = this.getSuggest();
128        var input = this.getHiddenInput();
129        input.set('value', text);
130        input.value = text;
131        suggest.prefetch();
132    },
133    endSuggest: function() {
134        this.currentText = '';
135        this.tagged = '';
136        this.positions = {};
137        if (this.suggest) {
138            this.getSuggest().destroy();
139            delete this.suggest;
140        }
141    },
142    getHiddenInput: function() {
143        if (!this.hiddenInput) {
144            this.hiddenInput = new Element('input', {
145                'type': 'text',
146                'styles': {
147                    'display': 'none'
148                }
149            }).inject(document.body);
150        }
151        return this.hiddenInput;
152    },
153    getSuggest: function() {
154        if (!this.suggest) {
155            var width = this.getComposer().elements.body.getSize().x;
156            
157            this.choices = new Element('ul', {
158                'class': 'tag-autosuggest yncomment-autosuggest',
159                'styles': {
160                    'width': (width - 2) + 'px'
161                }
162            }).inject(this.getComposer().elements.body, 'after');
163
164			// Check offset
165			var global_content = this.choices.getParent('#global_content');
166			var y_position = this.choices.getPosition(global_content).y;
167			var p_height = global_content.getHeight();
168			var c_height = 375;
169			if(p_height - y_position < c_height)
170			{
171				this.choices.addClass('users_suggest_reverse');
172			}
173
174            var self = this;
175            var options = $merge(this.options.suggestOptions, {
176                'customChoices': this.choices,
177                'injectChoice': function(token) {
178                    var choice = new Element('li', {
179                        'class': 'autocompleter-choices',
180                        'html': token.photo || '',
181                        'id': token.guid
182                    });
183                    var divEl = new Element('div', {
184                        'html': this.markQueryValue(token.label) + '<span class = "yc_tag_' + token.type + '"></span>',
185                        'class': 'autocompleter-choice'
186                    });
187                    if (token.type != 'user') 
188                    {
189                        new Element('div', {
190                            'html': token.type
191                        }).inject(divEl);
192                    }
193                    divEl.inject(choice);
194                    new Element('input', {
195                        'type': 'hidden',
196                        'value': JSON.encode(token)
197                    }).inject(choice);
198                    this.addChoiceEvents(choice).inject(this.choices);
199                    choice.store('autocompleteChoice', token);
200                },
201                'onChoiceSelect': function(choice) {
202                    var data = JSON.decode(choice.getElement('input').value);
203                    var composer = self.getComposer();
204                    var body = composer.elements.body;
205
206                    var content = null;
207                    if (composer._supportsContentEditable()) {
208                        content = composer.elements.body.get('html');
209                    } else {
210                        content = composer.elements.body.get('value');
211                    }
212
213                    var replaceString = '@' + self.currentText;
214                    var newString = '<span class="yncomment_composer_tag" rel="' + data.guid + '" rev="' + data.label + '" >' + data.label + '</span>&nbsp;';
215
216                    content = content.replace(/\<span\>\<\/span\>/ig, '');
217                    content = content.replace(new RegExp(replaceString, 'i'), newString);
218                    composer.setContent(content);
219					
220                    var tagElement = self.getYnCommentTagElementFromComposer(data.label);
221
222                    if (window.getSelection) {  // all browsers, except IE before version 9         
223                        composer.selection.getSelection().collapse(tagElement.nextSibling, 1);
224                    } else if (document.selection) {  // Internet Explorer before version 9            
225                        composer.selection.getRange().moveToElementText(tagElement);
226                    }
227
228                },
229                'emptyChoices': function() {
230                    this.fireEvent('onHide', [this.element, this.choices]);
231                },
232                'onCommand': function(e) {
233                    // This code is copy to Autocompleter JS amd hack minor for check that stop the key event
234                    if (e && e.key && !e.shift) {
235                        switch (e.key) {
236                            case 'enter':
237                                e.stop();
238                                if (!this.selected) {
239                                    if (!this.options.customChoices) {
240                                        // @todo support multiple
241                                        this.element.value = '';
242                                    }
243                                    return true;
244                                }
245                                if (this.selected && this.visible) {
246                                    this.stopKeysEvent = true;
247                                    this.choiceSelect(this.selected);
248                                    return !!(this.options.autoSubmit);
249                                }
250                                break;
251                            case 'up':
252                            case 'down':
253                                var value = this.element.value;
254                                if (!this.prefetch() && this.queryValue !== null) {
255                                    this.stopKeysEvent = true;
256                                    var up = (e.key == 'up');
257                                    if (this.selected)
258                                        this.selected.removeClass('autocompleter-selected');
259                                    if (!(this.selected)[
260                                            ((up) ? 'getPrevious' : 'getNext')
261                                    ](this.options.choicesMatch)) {
262                                        this.selected = null;
263                                    }
264
265                                    this.choiceOver(
266                                            (this.selected || this.choices)[
267                                            (this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
268                                    ](this.options.choicesMatch), true);
269                                    this.element.value = value;
270                                }
271                                return false;
272                            case 'esc':
273                                this.stopKeysEvent = true;
274                                this.hideChoices(true);
275                                if (!this.options.customChoices)
276                                    this.element.value = '';
277                                break;
278                            case 'tab':
279                                this.stopKeysEvent = true;
280                                if (this.selected && this.visible) {
281                                    this.choiceSelect(this.selected);
282                                    return !!(this.options.autoSubmit);
283                                } else {
284                                    this.hideChoices(true);
285                                    if (!this.options.customChoices)
286                                        this.element.value = '';
287                                    break;
288                                }
289                            default :
290                                this.stopKeysEvent = false;
291                        }
292                    }
293
294                }
295            });
296
297            if (this.options.suggestProto == 'local') {
298                this.suggest = new Autocompleter.Local(this.getHiddenInput(), this.options.suggestParam, options);
299            } else if (this.options.suggestProto == 'request.json') 
300            {
301            	var suggestUrl = this.options.suggestOptions.url;
302            	if(this.tagged)
303            	{
304            		suggestUrl = suggestUrl + '/tagged/' + this.tagged;
305            	}
306                this.suggest = new Autocompleter.Request.JSON(this.getHiddenInput(), suggestUrl, options);
307            }
308            if (this.suggest && !this.suggest.options.alwaysOpen) {
309                this.getComposer().elements.body
310                        .addEvent('blur', this.suggestHideChoices.create({
311                    bind: this
312                }));
313            }
314        }
315
316        return this.suggest;
317    },
318    suggestHideChoices: function() {
319        var suggest = this.suggest;
320        if (suggest) {
321            suggest.hideChoices(true);
322            if (!suggest.options.customChoices)
323                suggest.element.value = '';
324        }
325    },
326    filterYnCommentTagsFromComposer: function()
327    {
328        var body = this.getComposer().elements.body;
329        body.getElements('.yncomment_composer_tag').each(function(tag) {
330            if (tag.get('text') != tag.get('rev')) {
331                tag.removeClass('yncomment_composer_tag');
332            }
333        });
334    },
335    getYnCommentTagElementFromComposer: function(text) {
336        var body = this.getComposer().elements.body;
337        var element = null;
338        body.getElements('.yncomment_composer_tag').each(function(tag) 
339        {
340            if (tag.get('text') == tag.get('rev') && tag.get('text') == text.replace(/&shy;/ig, '­').replace(/&#039;/ig, '\'')) {
341                element = tag;
342            }
343        });
344        return element;
345    },
346    submit: function() {
347        this.makeFormInputs({
348            tag: this.getYnCommentTagsFromComposer().toQueryString()
349        });
350    },
351    // get the tags which are in composer
352    getYnCommentTagsFromComposer: function()
353    {
354        // filter the tags which are uncorrect formate or lable 
355        this.filterYnCommentTagsFromComposer();
356
357        var composerTags = new Hash();
358        var body = this.getComposer().elements.body;
359        body.getElements('.yncomment_composer_tag').each(function(tag) {
360            composerTags[tag.get('rel')] = tag.get('text');
361        });
362        return composerTags;
363    },
364    makeFormInputs: function(data) {
365        $H(data).each(function(value, key) {
366            this.setFormInputValue(key, value);
367        }.bind(this));
368    },
369    // make tag hidden input and set value into composer form
370    setFormInputValue: function(key, value) {
371        var elName = 'yncommentComposerForm' + key.capitalize();
372        var composerObj = this.getComposer();
373        if (composerObj.elements.has(elName))
374            composerObj.elements.get(elName).destroy();
375        composerObj.elements.set(elName, new Element('input', {
376            'type': 'hidden',
377            'name': 'composer[' + key + ']',
378            'value': value || ''
379        }).inject(composerObj.getInputArea()));
380        composerObj.elements.get(elName).value = value;
381    }
382});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.