See this demo (dependent on selectionchange event which works in Chrome only at this moment): http://jsfiddle.net/fyG3H/
Select some lorem ipsum text and then focus the text input. In the console log you will see that there is a DOMSelection object.
It has an anchorNode value of HTMLBodyElement while it should have one of Text.
I didn't know why this was happening until I tried stringfying the selection object: http://jsfiddle.net/fyG3H/1/
This gives the following error:
Uncaught TypeError: Converting circular structure to JSON
Do you know how I can prevent this circular reference caused by window.getSelection() ?
EDIT
New demo which works in other browsers too but still gives the wrong anchorNode: http://jsfiddle.net/fyG3H/5/
And with JSON.stringify: http://jsfiddle.net/fyG3H/6/
Firefox seem to return an empty {} instead of throwing an error.
You need to invoke toString() on getSelection(). I've updated your fiddle to behave as you'd expect.
var selection;
$('p').bind('mouseup', function() {
selection = window.getSelection().toString();
});
$('input').bind('focus', function() {
this.value = selection;
console.log(selection);
});
See demo
EDIT:
The reason that you're not getting the correct anchor node is that the DOMSelection object is passed by reference and when you focus on the input, the selection gets cleared, thus returning the selection defaults corresponding to no selection. One way you can get around this is to clone the DOMSelection properties to an object and reference that. You won't have the prototypal DOMSelection methods any more, but depending on what you want to do this may be sufficient.
var selection, clone;
$('p').bind('mouseup', function() {
selection = window.getSelection();
clone = {};
for (var p in selection) {
if (selection.hasOwnProperty(p)) {
clone[p] = selection[p];
}
}
});
$('input').bind('focus', function() {
console.dir(clone);
});
See demo
Related
I am trying to add an extension that replaces the existing link functionality in medium editor to allow me to have a filelist and other custom bits. The problem is that once I show modal and you make some change in it the original selection is lost. The example for inserting code, which looked to be the same thing the main script uses is this which I editing only so far as allowing a selection object to be passed in as a second param.
What I do is on button click show the modal, set some inputs, grab the selection from the base (same as window.getSelection()) save that to extension object. Then on clicking the save button in the modal I use the function from the code insert example, passing the selection. However the selection has changed, so I am guessing it's a reference or calculated everytime maybe, so I'm not sure how to make it work.
Here's code, I trimmed out the unrelated bits:
function MediumLink() {
var self = this;
this.parent = true;
//...button init
this.modalSubmit.addEventListener('click', function () {
//the linkSel is no longer what I set it to here
console.log(self.linkSel);
self.insertHtmlAtCaret('' + self.modalName.value + '', self.linkSel);
//... hide and reset modal
}, false);
//https://github.com/jillix/medium-editor-custom-html
this.insertHtmlAtCaret = function (html, sel) {
if (sel === undefined) {
sel = window.getSelection();
}
//..rest of this function is unchanged from example
};
}
MediumLink.prototype.onClick = function () {
var sel = this.base.selection;
if (sel.type === 'Range') { //trying to keep sel from changing since an empty selection would have a different type
//... set inputs in modal based on the selection
// sel is what I want at this point, what should be passed
console.log(sel);
this.linkSel = sel;
}
};
medium-editor does have support for this built in:
MediumEditor.saveSelection() // Stores the selection internally
MediumEditor.restoreSelection() // Re-applies the stored selection
From within your extension, since you're setting this.parent = true you can access this.base to call these methods:
this.base.saveSelection()
this.base.restoreSelection()
These built-in helpers should work fine as long as you don't make large alterations to the html (or more specifically the text value itself) between when the selection is saved and when the selection is restored.
Ok I think the problem boils down to this :
How do we save the selection and reproduce it if it is lost while we perform some other operation.
I dont know if there is an inbuilt medium editor function for it but I have encountered same problem and the short answer is to use Ranges and X-path to save selection.
Ranges are required to highlight the selection and X path to have selection accurately across all node and text.
Refer this :
How to calculate the XPath position of an element using Javascript?
I've got some JS code here. Basically, I am trying to change the ID of an element to some value from a previous variable.
Here's what I got so far;
function() {
var colorarray = [ "RANDOMCOLOR_0", "RANDOMCOLOR_1", "RANDOMCOLOR_2" ];
var RANcolorarray = colorarray[Math.rsound(Math.random() * (colorarray.length - 1))];
document.getElementsByClassName('RANDOMCOLOR').setAttribute('id', RANcolorarray);
}
This code throws an error in Chrome for line 4: Uncaught TypeError: undefined is not a function which is weird because JsLint finds no errors.
I also tried using the other way to setting id's;
document.getElementsByClassName('RANDOMCOLOR').id = RANcolorarray;
However, although this method does not throw an error on chrome or jslint - it does not work at all after inspecting the element.. :/
Any ideas?
document.getElementsByClassName('RANDOMCOLOR') returns a list of DOM nodes (even if there's only one match) so you can't just call .setAttribute() on the list as the list doesn't have that method.
You can either get the first item out of the list and call .setAttribute() on that one or use a for loop to iterate through the list and call it on all of them. Of course, since you're setting the id, you should not be setting multiple elements to the same id, so I'll assume you just want one element:
document.getElementsByClassName('RANDOMCOLOR')[0].id = RANcolorarray;
Or, a little more safe:
var elems = document.getElementsByClassName('RANDOMCOLOR');
if (elems && elems.length) {
elems[0].id = RANcolorarray;
}
I was playing with Object.observe in the latest version of Chrome and was wondering why it does not work for the 'value' property of a text input. The code below will log a change for adding/changing the 'foo' property, but not for changing the value property. Anybody know why?
var myTextInput = document.getElementById('myTextInput');
Object.observe(myTextInput, function(changes){
changes.forEach(function(change) {
console.log(change);
});
});
myTextInput.value = 'test123';
myTextInput.foo = 'bar';
I'm not sure why this is, but since you're observing a DOM element's attributes, the mutation observer api may be more appropriate.
I have a piece of code that is working on all browsers except safari.
Basically I have an object called record.
record has properties, UserPhone, UserFax ...etc.
I also have a form with the same field names.
I update the object on the text field blur
$(this).on('blur', function() {
console.log($(this).val()); // shows the new value correctly
console.log($(this).attr('name')); // shows the right name correctly
record[$(this).attr('name')] = $(this).val();
console.log(record); // shows the record with the old value, should show the new value
updateDB();
});
The comments in the code to show what I'm getting in the console.
This code is working in other browsers.
Any idea?
This should work:
$(this).on('blur', function() {
console.log($(this).val()); // shows the new value correctly
console.log($(this).attr('name')); // shows the right name correctly
var key = $(this).attr('name'),
val = $(this).val();
record[key] = val;
console.log(record); // shows the record with the old value, should show the new value
updateDB();
});
There is an ambiguity in your scope, I assume.
Also, this fiddle resembles your code and I don't have any problems whatsoever.
EDIT: And the fiddle that addresses your problems. The takeaways from this should be to always avoid inline javascript and bind elements later.
Storage.prototype.setObj = function(key, obj) {
return this.setItem(key, JSON.stringify(obj))
^-----Error in this line: Uncaught TypeError: Accessing selectionDirection on an input element that cannot have a selection
}
var selected = jQuery('input:checkbox.mychkbox:checked').each(function() {
return this.id;
});
sessionStorage.setObj("savedCollSearch",selected);
I am using jQuery 1.7.2 and Chrome 22.
This error shows up as Uncaught Exception in Firefox 16. Search in SO and Google does not help and I have no clue how to resolve this.
I am 100% sure jQuery is loaded properly.
This expression...
var selected = jQuery('input:checkbox.mychkbox:checked').each(function() {
return this.id;
});
... seems to be misused here: it'll return you a jQuery-wrapped collection of checked checkbox elements, which is probably not quite easy to stringify (because of circular references).
(as a sidenote, .each will stop the iteration at the first element which doesn't have an id, or have it set to an empty string, but that doesn't matter much here)
You probably wanted to use this instead:
var selected = jQuery('input:checkbox.mychkbox:checked').map(function() {
return this.id;
}).get();