Как выделить имя друга в окне обновления статуса Facebook (textarea)? - PullRequest
7 голосов
/ 21 сентября 2011

В окне обновления статуса Facebook, когда я набираю @, начинаю печатать и выбираю имя, скажем, Стивена Джеррарда, из списка друзей, предложенного fb, имя моего друга выделяется в текстовой области следующим образом

textbox with name highlighted

Я проверил с Firebug, и есть только

  • div.highlighter, который содержит отформатированный текст (Стивен Джеррард в тегах b)
  • текстовая область внутри div.uiTypeahead. Ничего интересного я не смог бы найти
  • и скрытый ввод, который содержит фактический текст, который будет опубликован: @ [100001915747xxx: Стивен Джеррард] потрясающий

В чем секрет этого трюка? Обычные редакторы форматированного текста, такие как ckeditor, обычно имеют iframe для отображения текста и фактическую текстовую область для сохранения исходного содержимого. Но в этом случае я ничего не вижу. Кто-нибудь, пожалуйста, пролить немного света?

Я бы хотел сделать что-то подобное, но понятия не имею, с чего начать. Кроме того, если я хотел бы показать маленький палец рядом с именем моего друга, это вообще возможно?

Ответы [ 3 ]

17 голосов
/ 29 сентября 2011

Вот как это работает:

  • Вы накладываете текстовую область (впереди) и div (сзади), которые будут иметь одинаковый размер и одинаковый размер шрифта..
  • Текстовое поле должно иметь прозрачный фон, чтобы мы могли видеть его текст, а также видеть div за ним.
  • Div за ним будет иметь белый текст и белый фон, поэтомусодержащийся в нем текст будет прозрачным.
  • Вы устанавливаете ловушку на клавиатуре текстовой области и обрабатываете содержащийся в ней текст как HTML: замените разрывы строк на , замените двойные пробелы на , а также замените все слова, которые вы хотите выделить, версией, окруженной .
  • Поскольку выВы можете видеть div подсветки позади текстовой области, и что текст, который содержит div подсветки, идеально выровнен с текстом в текстовой области, и что видим, у вас будет иллюзия, что текст в текстовой области выделен.

Я написал небольшой пример, основанный на jquery, чтобы вы могли попробовать его самостоятельно, без лишнего кода для анализа.


Вот пример кодаВы можете просто скопировать-вставить-сохранить и попробовать:

В этом примере кода будет выделен определенный набор слов, здесь: "привет" и "мир".

Я будуПозвольте вам адаптировать его так, как вы хотите.

<html>
    <head>
        <title></title>
        <!-- Load jQuery -->
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
        <!-- The javascript xontaining the plugin and the code to init the plugin -->
        <script type="text/javascript">
            $(function() {
                // let's init the plugin, that we called "highlight".
                // We will highlight the words "hello" and "world", 
                // and set the input area to a widht and height of 500 and 250 respectively.
                $("#container").highlight({
                    words:  ["hello","world"],
                    width:  500,
                    height: 250
                });
            });

            // the plugin that would do the trick
            (function($){
                $.fn.extend({
                    highlight: function() {
                        // the main class
                        var pluginClass = function() {};
                        // init the class
                        // Bootloader
                        pluginClass.prototype.__init = function (element) {
                            try {
                                this.element = element;
                            } catch (err) {
                                this.error(err);
                            }
                        };
                        // centralized error handler
                        pluginClass.prototype.error = function (e) {
                            // manage error and exceptions here
                            //console.info("error!",e);
                        };
                        // Centralized routing function
                        pluginClass.prototype.execute = function (fn, options) {
                            try {
                                options = $.extend({},options);
                                if (typeof(this[fn]) == "function") {
                                    var output = this[fn].apply(this, [options]);
                                } else {
                                    this.error("undefined_function");
                                }
                            } catch (err) {
                                this.error(err);
                            }
                        };
                        // **********************
                        // Plugin Class starts here
                        // **********************
                        // init the component
                        pluginClass.prototype.init = function (options) {
                            try {
                                // the element's reference ( $("#container") ) is stored into "this.element"
                                var scope                   = this;
                                this.options                = options;

                                // just find the different elements we'll need
                                this.highlighterContainer   = this.element.find('#highlighterContainer');
                                this.inputContainer         = this.element.find('#inputContainer');
                                this.textarea               = this.inputContainer.find('textarea');
                                this.highlighter            = this.highlighterContainer.find('#highlighter');

                                // apply the css
                                this.element.css('position','relative');

                                // place both the highlight container and the textarea container
                                // on the same coordonate to superpose them.
                                this.highlighterContainer.css({
                                    'position':         'absolute',
                                    'left':             '0',
                                    'top':              '0',
                                    'border':           '1px dashed #ff0000',
                                    'width':            this.options.width,
                                    'height':           this.options.height,
                                    'cursor':           'text'
                                });
                                this.inputContainer.css({
                                    'position':         'absolute',
                                    'left':             '0',
                                    'top':              '0',
                                    'border':           '1px solid #000000'
                                });
                                // now let's make sure the highlit div and the textarea will superpose,
                                // by applying the same font size and stuffs.
                                // the highlighter must have a white text so it will be invisible
                                this.highlighter.css({

                                    'padding':          '7px',
                                    'color':            '#eeeeee',
                                    'background-color': '#ffffff',
                                    'margin':           '0px',
                                    'font-size':        '11px',
                                    'font-family':      '"lucida grande",tahoma,verdana,arial,sans-serif'
                                });
                                // the textarea must have a transparent background so we can see the highlight div behind it
                                this.textarea.css({
                                    'background-color': 'transparent',
                                    'padding':          '5px',
                                    'margin':           '0px',
                                    'font-size':        '11px',
                                    'width':            this.options.width,
                                    'height':           this.options.height,
                                    'font-family':      '"lucida grande",tahoma,verdana,arial,sans-serif'
                                });

                                // apply the hooks
                                this.highlighterContainer.bind('click', function() {
                                    scope.textarea.focus();
                                });
                                this.textarea.bind('keyup', function() {
                                    // when we type in the textarea, 
                                    // we want the text to be processed and re-injected into the div behind it.
                                    scope.applyText($(this).val());
                                });
                            } catch (err) {
                                this.error(err);
                            }
                            return true;
                        };
                        pluginClass.prototype.applyText = function (text) {
                            try {
                                var scope                   = this;

                                // parse the text:
                                // replace all the line braks by <br/>, and all the double spaces by the html version &nbsp;
                                text = this.replaceAll(text,'\n','<br/>');
                                text = this.replaceAll(text,'  ','&nbsp;&nbsp;');

                                // replace the words by a highlighted version of the words
                                for (var i=0;i<this.options.words.length;i++) {
                                    text = this.replaceAll(text,this.options.words[i],'<span style="background-color: #D8DFEA;">'+this.options.words[i]+'</span>');
                                }

                                // re-inject the processed text into the div
                                this.highlighter.html(text);

                            } catch (err) {
                                this.error(err);
                            }
                            return true;
                        };
                        // "replace all" function
                        pluginClass.prototype.replaceAll = function(txt, replace, with_this) {
                            return txt.replace(new RegExp(replace, 'g'),with_this);
                        }

                        // don't worry about this part, it's just the required code for the plugin to hadle the methods and stuffs. Not relevant here.
                        //**********************
                        // process
                        var fn;
                        var options;
                        if (arguments.length == 0) {
                            fn = "init";
                            options = {};
                        } else if (arguments.length == 1 && typeof(arguments[0]) == 'object') {
                            fn = "init";
                            options = $.extend({},arguments[0]);
                        } else {
                            fn = arguments[0];
                            options = $.extend({},arguments[1]);
                        }

                        $.each(this, function(idx, item) {
                            // if the component is not yet existing, create it.
                            if ($(item).data('highlightPlugin') == null) {
                                $(item).data('highlightPlugin', new pluginClass());
                                $(item).data('highlightPlugin').__init($(item));
                            }
                            $(item).data('highlightPlugin').execute(fn, options);
                        });
                        return this;
                    }
                });

            })(jQuery);


        </script>
    </head>
    <body>

        <div id="container">
            <div id="highlighterContainer">
                <div id="highlighter">

                </div>
            </div>
            <div id="inputContainer">
                <textarea cols="30" rows="10">

                </textarea>
            </div>
        </div>

    </body>
</html>

Дайте мне знать, если у вас есть какие-либо вопросы или вам нужна помощь с этим кодом.

2 голосов
/ 26 сентября 2011

Изучив способ, которым Facebook это делает, я вижу, что текст, показанный на экране:

<span class="highlighterContent"><b>Ws Dev</b> is good</span>

Этот промежуток помещается в таблицу (с большим количеством контейнера div), что соответственно соответствует стилю.

Так что я думаю, что это процесс:

  1. Когда вы вводите текст в поле, у Facebook есть текстовая область, в которой записывается то, что вы печатаете, но для отображения набранного HTML-содержимого в таблице используется javascript.

  2. Когда вы отправляете, отформатированный контент в скрытом вводе (который вы уже заметили в вопросе) отправляется. Это как "@ [100001915747xxx: Стивен Джеррард] потрясающий".

  3. Когда отформатированное сообщение отправляется, оно сохраняется в базе данных. Каждый раз, когда страница загружается, из сохраненного сообщения составляется и возвращается HTML.

Чтобы получить подобный эффект, вы можете использовать любой плагин jQuery для автозаполнения .

1 голос
/ 08 апреля 2012

Пример кода с использованием техники, описанной Жюльеном по адресу: http://jsfiddle.net/SBBZm/

Слова, начинающиеся с заглавной буквы, выделены в примере.

...