How to get current cursor position when editing fabric.Textbox - javascript

How to get current cursor position on text in fabric.Textbox
for example, the following should return = 6

I sort of figured it out. selectionStart and selectionEnd did the trick:
var activeObj = canvas.getActiveObject();
var caretPositionStart = activeObj.selectionStart;
var caretPositionEnd = activeObj.selectionEnd;
activeObj.enterEditing();
activeObj.insertChars("HI", null, caretPositionStart, caretPositionEnd);

Related

How to insert a node after a selection?

I need to wrap a selection in comment nodes so that it can be parsed later on.
This script is executing within a CK-Editor plugin, but I believe the way selection and range works is native to JavaScript.
I'm able to insert the comment node at the beginning of the range just fine, but I can't figure out how to add a comment node to the end of the selection.
My current code is:
var selection = editor.getSelection();
var ranges = selection.getRanges();
var start_node = 'parsing_start';
var end_node = 'parsing_end';
var start_comment = new CKEDITOR.dom.comment(start_node);
var end_comment = new CKEDITOR.dom.comment(end_node);
ranges[0].insertNode(start_comment);
ranges[0].nextSibling().insertNode(end_comment); // how to do this???
Try this to select a new empty range after the original selection. The only disadvantage is that you lose the original selection.
var selection = editor.getSelection();
var range = selection.getRanges()[0];
var start_node = 'parsing_start';
var end_node = 'parsing_end';
var start_comment = new CKEDITOR.dom.comment(start_node);
var end_comment = new CKEDITOR.dom.comment(end_node);
range.insertNode(start_comment);
var endNode = range.endContainer;
var endOffset = range.endOffset;
range.setStart(endNode, endOffset);
range.setEnd(endNode, endOffset);
selection.selectRanges([range]);
range.insertNode(end_comment);
editor.focus();

Inserting an HTML element after text selection

I am trying to insert some HTML after the user has selected some text on the page. I have it working but not optimally and there is one problem in particular:
It relies on the element being on the page, but I don't want it to be. I want to do it all in the code, I am sure it's something relatively simple but need some help :)
I also welcome any other tips/suggestions/feedback!
The code canbe seen working here: http://jsfiddle.net/shE58/ (The selectionchange library is to make this work in FF).
document.addEventListener('selectionchange', function (event) {
var sel = this.getSelection();
// If text is being selected by drag, to wait for them to finish selecting.
jQuery("body").mouseup(function() {
// Ensure there is some text selected and that it is more than one character.
if (sel.toString().length > 1) {
// We only want one #element on the page at a time.
$("#element").remove();
// #TODO: Remove dependency on this:
var el = document.getElementById('selection');
el.innerHTML = '<div id="element"></div>';
var frag = document.createDocumentFragment(), node;
frag.appendChild(el.firstChild);
var range = sel.getRangeAt(0)
var startNode = range.startContainer, startOffset = range.startOffset;
var boundaryRange = range.cloneRange();
boundaryRange.collapse(false);
boundaryRange.insertNode(frag);
boundaryRange.setStart(startNode, startOffset);
boundaryRange.collapse(true);
// Clean up
sel = '';
}
});
});
Solution 1
Remove frag variable and directly add value in insertNode function like this :
boundaryRange.insertNode($('<div id="element"></div>')[0]);
http://jsfiddle.net/N6zz8/
Fix issue when to select right to left :
With a condition check if endOffset is smaller than startOffset.
var startNode = range.startContainer, startOffset = range.startOffset;
if (range.endOffset < range.startOffset) {
startNode = range.endContainer;
startOffset = range.endOffset;
}
http://jsfiddle.net/2c4qw/
Solution 2
Remove unnecessary code, remove 'el' variable like this :
// #TODO: Remove dependency on this:
var frag = document.createDocumentFragment(), node;
$(frag).append($('<div id="element"></div>'));
http://jsfiddle.net/zYSH4/
Solution 3
Declare your variable like this var el = $("<div></div>")[0];. To get this :
// #TODO: Remove dependency on this:
var el = $("<div></div>")[0];
el.innerHTML = '<div id="element"></div>';
var frag = document.createDocumentFragment(), node;
frag.appendChild(el.firstChild);
http://jsfiddle.net/7L3Kf/

Occurrences and Arrays positions

Lets say I have this arrays:
likes = [4,6,42,72,7,4,42,56,6,24];
time = [1,2,3,4,5,6,7,8,9,10];
And when clicking in one of the bar charts I have, I'm forwarded to the current time, according to the array likes position.
this.click(function () {
var pos = result_likes.indexOf(this.bar.value);
var pos2 = result_time[pos];
setCurTime(pos2);
});
However when I have the same likes values, for instance number 4, there will be two positions of it, and the SetCurTime, will only forward me to the first time when "like=4 appears (timecode[0];)
How can I solve this and be forward to the right time position?
You need to embed meta data in the bar elements to solve this problem. For instance, you can use custom data attributes like such:
<div class="bar" data-index"5">4</div>
You would dynamically generate this of course, to create each bar with the proper index and value.
Then in your click handler would be:
this.click(function () {
var pos = this.bar.dataset.index;
var pos2 = result_time[pos];
setCurTime(pos2);
});
In light of you using the gRaphael library, perhaps you could crawl the bar elements to see which element it is within the chart, like this:
this.click(function(evt) {
var pos = 0;
var child = evt.currentTarget;
var type = child.nodeName;
while( (child = child.previousSibling) != null && type === child.nodeName)
pos++;
var pos2 = result_time[pos];
setCurTime(pos2);
});
Reposting comment here for any others who need a simliar solution:
var pos2 = result_time[this.bar.id];

Nested object with square bracket notation in JavaScript

I'm trying to achieve the following:
this.inputs[options.el.find('form').attr('class')] = {};
this.inputs[options.el.find('form').attr('class')][options.elements[x].selector] = false;
However, I'm unable to do the above without a syntax error!
Any ideas how I could achieve this Object structure?
That syntax looks legal, but these long one liners aren't doing anyone any favors. Break it apart a bit so you can find where it's failing.
var className = options.el.find('form').attr('class');
var selector = options.elements[x].selector;
this.inputs[className] = {};
this.inputs[className][selector] = false;
The index to an object should always be a string:
var obj = {
a: 2;
}
obj.a = 3; //a is 3 now
obj['a'] = 4;//a is 4 now
You said options.elements[x].selector is input[name="username"] so I guess in this line:
this.inputs[options.el.find('form').attr('class')][options.elements[x].selector] = false;
What you are really trying to do is:
this.inputs[options.el.find('form').attr('class')]['username'] = false;
So you can do like this:
var sel = options.elements[x].selector;
console.log( 'sel is ' + sel );
this.inputs[options.el.find('form').attr('class')][sel] = false;
Make sure that sel is a string. You may want to try
var sel = options.elements[x].selector.value;
The .value bit retrieves the text from inside an input element.

How to get the coordinates of the end of selected text with javascript?

My problem is similar to this, but I need a way to get the coordinates of the right side of the selection with Javascript in Firefox. I made a small example to show what I mean:
The code I got from the other post is the following:
var range = window.getSelection().getRangeAt(0);
var dummy = document.createElement("span");
range.insertNode(dummy);
var box = document.getBoxObjectFor(dummy);
var x = box.x, y = box.y;
dummy.parentNode.removeChild(dummy);
This gives me the coordinates of the beginning of the selection. Is there any way to retrieve the coordinates of the end of the selection?
Yes. That bit's quite simple: you just need to call collapse(false) on the Range obtained from the selection. Be aware that document.getBoxObjectFor() has now been removed from Mozilla, so you need the dummy element's getBoundingClientRect() method instead:
var range = window.getSelection().getRangeAt(0);
range.collapse(false);
var dummy = document.createElement("span");
range.insertNode(dummy);
var rect = dummy.getBoundingClientRect();
var x = rect.left, y = rect.top;
dummy.parentNode.removeChild(dummy);
var r = range.cloneRange();
r.collapse(false); // collapses range clone to end of original range
r.insertNode(dummy);
// document.getBoxObjectFor(dummy), etc.

Categories

Resources