Mentioning system that mimics Facebook's - javascript

I've had a horrible problem that I've been wracking my brain for the past two days for, and have yet to come up with a solution. As such, I think this needs someone smarter than I to accomplish.
What I'm trying to build is a textbox that simulates that of Facebook's; essentially, the tagging function.
Now if you've used Facebook, you'll have noticed that Facebook allows you to tag people in a comment/post, simply by typing in their name and selecting from a dropdown list. The name of the person you've selected then appears in highlighted text in that very textarea. I've successfully managed to create and populate the dropdown list a combination of JQuery and AJAX, but the tagging process itself is the stumper.
Once a dropdown item has been selected (by Enter or clicking), the query text will be replaced with the tagged name. Now, it's difficult to see how one can give text in a textarea any kind of a highlight, so I've discovered (by inspecting elements in Google Chrome and deleting the textarea node) that the textarea itself is transparent, and there is a white div below "simulating" the text. Highlighted words are placed in a tag with custom CSS, which gives it that blue background. All of this I've found out myself, and I have successfully simulated this - but I can only do one tag.
Now I've investigated further and found an input type="hidden" element, of class "mentionsHidden". This input element has a value attribute, which dynamically populates itself based on the content of the textarea. So if I typed "ABC", the value of the element becomes "ABC". If I included a tag, say "hi [Rei]!" (where the name in [] is the tag), the value of the element becomes "hi #[member_id:Rei]!".
So I HAVE done my homework. But here comes the part I can't figure out.
I can't figure out how exactly to dynamically populate the hidden input element with the value of the textbox. It's obvious that the underlying div giving the blue tag background is populated from the input element. But the input element is giving me a headache.
You see, I can't do the following:
-I can't simply "copy" the entire value of the current textarea and "paste" it into the input element's value, because that would override any previously tagged people in the input element (after all, the textarea can only possess plaintext).
-Even though I CAN locate the current index of the caret (the flashing black line in the textarea that tells you where you're going to be typing into), that's only for the textarea. Index position 10 in the textarea and in the input element's value might be different things, because this way of "tagging" people will result in adding additional characters to the value String.
-I can't simply do a "replace" of the text I am intending to replace, because there might be other instances of that same text in other parts of the value String.
I know it's a very long and confusing post, but I do hope you get what I mean. I really need a solution and I don't want to use contenteditable, because it's only for HTML5 and some older browsers might not support it.
Yours,
Rei

I hope you were able to come up with, or find, a solution to your problem. Since there doesn't seem to be one here, i'd like to offer one for and anyone who might stumble upon this (as well as you if my assumption was incorrect).
You are going to need to maintain explicit locational data of each existing mention in the textarea in the order in which they appear. If, after a modification of the content in textarea, the position of a mention in it is changed, you will need to determine which appearance of its value, if any, will be used to represent it, and appropriately update the locational data of the mention.
With such a collection of data, it becomes trivial to construct the value of mentionsHidden, though the existence of such data makes the element unnecessary.
Mentionator is an existing, robust solution which takes this approach in providing the functionality you are trying to recreate. Considering it is well-structured, easy to follow, and copiously commented, it should be of use to you as either out-of-the box solution or reference material to cite as you roll out your own. It is maintained by yours truly :) .

Related

Change the value of a <textarea> and allow the user to undo

In the past, when you set the value of a textarea using javascript, Firefox allowed the user to undo this change (by pressing ctrl+Z, for example). However, this no longer works, and there doesn't appear to be any decent alternatives.
I've tried using document.execCommand to modify the textarea, but this requires you to select the text that you want to modify, and it doesn't appear to be possible to automatically select text in a textarea.
I've also heard about document.createEvent("TextEvent") but I can't find much information about this. It appears that you can only insert text at the cursor, and I need to delete text as well.
Creating my own undo/redo system and capturing ctrl+Z/Y presses is not an acceptable solution.
Similar questions have already been asked here, but they involve only inserting text at the cursor, not changing the value of the textarea entirely.
You can use the setSelectionRange API to manually manipulate the textarea's selection. Get the original values from textarea.selectionStart and textarea.selectionEnd.

Problems with custom divs within WYSIWYG, cross-browser

I am working on a WYSIWYG editor (customising someone else's code) and have encountered a few problems that I just can't seem to overcome.
So far I have been able to get most custom divs working, but I am having some trouble with a few things:
Problem 1: If the cursor is before a div element, I am able to press delete and begin to remove the contents of the div without removing the actual div itself. This is how the element should look within the WYSIWYG for example:
But after pressing delete when the cursor is before the element, I get the following:
How can I check if the next element is this custom div and cancel a delete key press?
Problem 2: I am also able to press backspace after an element, which causes any text after the element to appear inside it, like so:
How can I check if the previous element is my custom div and cancel a backspace key press?
Problem 3: When inside a section (where the 'put content here' text is), I am using a div with the attribute contenteditable="true". Every time I press 'enter' within this div, a new <div> tag is created, rather than a line break tag (<br>). How can I force a line break tag to be created instead of a div element?
I have looked far and wide on stackoverflow and have yet to find a proper solution to the problem that is cross-browser.
Disclaimer: I am a CKEditor core developer.
If you want to customise this there are three ways:
You can spend few months (or more) on learning about contenteditable, ranges, selection and all that stuff and trying to implement your custom handlers. You could of course spend only one week or month on that, but the result won't be great, believe me.
You can choose good, existing WYSIWYG editor.
You can lower your expectations regarding the expected behaviour ;).
Now, if you would decide to use CKEditor there's one new feature called Widgets which was introduced in recently released CKEditor 4.3 beta (4.3 stable is going to be released in max. 2-3 weeks). As far as I can see it may be very helpful in your case. Check out the Introduction to Widgets guide. In very short - it is possible to configure how enter key behaves in so called "nested editables" as well as to secure integrity of your custom markup.

Grabbing the sentence that a selected word appears in

Using Javascript, I need to allow a user to double click a word on a page and retrieve the sentence that it appears in. Not just any sentence, but that specific one. I've toyed with retrieving all sentences that that word appears in and somehow choosing the correct sentence, so maybe that's an option.
I've scoured the web looking for this beast, and I've thought a lot about it. Some have recommended using Rangy but I haven't been able to find the functionality I'm looking for, or even functionality that would help me get where I need to be.
Any ideas?
You could turn your page into one or multiple read-only textareas, use clever CSS styling to mask it, then use the onselect event as described here: Detect selected text in a text area with javascript
Depends of course, how your page looks like and where it's used.

Javascript, Text Annotations and Ideas

I am very curious to hear input from others on a problem I've been contemplating for some time now.
Essentially I would like to present a user with a text document and allow him/her to make selections of text and annotate it. Specific to the annotations I aim to achieve the following:
Allow users to make a text selection, annotate it, then save the selection and annotation for reference later
(UI) Support representing overlapped annotations. For example if the string where: "This is the test sentence for my example test sentence", user1 might have an annotation on "is the test sentence for my example" and user2 might have an annotation on "for my example".
Account for a situations where the document's text changes. The annotations would to be updated, if possible.
How would you tackle this from a technical perspective?
Some ideas I've had are:
Use javascript ranges and store an annotation as a pair of integers something like: (document_start_char, document_end_char). Save this pair in the db.
Alternatively, using JS get the text selected and actually save the full text in the db. (not sure how i would then do overlapping annotations)
Represent overlapped annotations by applying a css style to highlight the text then darken the "stack" of annotations where they overlap. Smallest annotation would always have to be on the top of the "stack".
What are your thoughts or areas of improvement? How the heck could i support a document's text being updated without breaking all the annotations?
I'm researching this same question and personally I favor staying away from rolling my own, in favor of an existing open source library like Annotator.
http://mark.koli.ch/2009/09/use-javascript-and-jquery-to-get-user-selected-text.html (404 response)
http://mark.koli.ch/2009/09/05/get-selected-text-javascript.html- (404 response)
Getting the selected text is really easy. Storing it (or its starting/ending points) is also a joke. But what about your point number 3? What if the text changes?
If the text changes, both the original text and the original selection coordinates you stored won't equal the current modified text. You should be aware of the annotations present in the text document, so that everytime it changes, the annotations referencing to that particular piece of changed text should be updated, or deleted (maybe after a quick comparison between the before and after text: are some words missing? or just some words have been corrected?), but this seems really a struggling task.
I think storing the entire text annotation in a db is essential, to avoid it being changed and the annotation lost. This way you will still have the complete text you annotated. Then you should also use a sort of flag to indicate the start character of the annotation, and if the text changes, you could calculate the difference in characters from the document text before the change, and the one after it, and find this way the new starting point of the original annotation (assuming the annotation part of the document text has't changed).
Dividing the text document in as many paragraphs as possible should also help, this way you could separate different pieces of the document and work on one by one.
Now I would really like to see it done! :)

How to detect struckthrough text using JavaScript

I have a form which presents the user a list of checkboxes, some of which have the text label struckthrough some don't depending on initial conditions. This is functioning fine. During the form validation however, I would like to be able to detect which are struckthrough. I can figure out how to check if they're enabled, but whether the label is struckthrough is eluding me. Any ideas?
You'll have to use the DOM methods (or jQuery) to look at the parent element of the text to see if its a <del> tag.
Can you provide some sample source so I might be able to elaborate with an example.
Doing this with jQuery just makes so much more sense then trying to mess around with plain Javascript. Here is what you need, basically:
striked = $("strike"); // As mentioned, you should use `del` .. strike is depreciated
$.each(striked, function(i, el) {
alert($(el).html() + " is striked through. What do you want to do with it?");
});
Not sure what you want, but that would detect all elements with strike/del on your page. You can also change the search a bit, to restrict it to only within a certain form/div/whatever like so:
striked = $("strike", $("#myform_id"));
Hope that's what you were looking for.
If the strikeout (your struckthrough) is assigned via a CSS class, you can simple detect the class (since you can already detect enabled/disabled). Else like Darrell mentioned, jQuery will be a great method.
You basically have two categories of checkboxes which you are defining by their display qualities (struckthrough and not). This kind of "what does it look like" detection creates an artificial code-dependency which could cause a lot of trouble later:
The strikethrough effect can be accomplished in several ways (the del tag, the strike tag, CSS text-decoration: line-through, and possibly others in future versions of HTML/CSS). If you later change which way you do the effect, you'll have to update your js code to match
If you ever choose to reformat the list and stop using the strikethrough effect (e.g. you decide to make it invisible, or faded out, or have a red x over it), you will lose your ability to distinguish between the two types of checkboxes.
Instead, you should either assign a CSS class (like "nonUsableCheckboxes") to all strikethrough checkboxes, or generate a hidden field indicating if it is strikethrough or not. That way your javascript stays independent of your display code, and less prone to fail.

Categories

Resources