This is driving me nuts, a simple script to swap two nodes in a two node ul:
// Html
<input type="button" onclick="swapItems()" value="Swap Items" />
//JavaScript
function swapItems() {
var ul2 = document.getElementById("ul2");
var first = ul2.firstChild;
var last = ul2.lastChild;
ul2.insertBefore(last, first);
}
It works but I have to either double click or triple click the button to see the changed list.
If you look at the childNodes of ul2 it will become apparent. The first child of ul2 is a blank text node, so is the last child. The reason you have to click a few times is that you are moving blank text nodes around. You can't see it on the web page, but if you use a web inspector you should be able to pick it up.
You could change the code to:
function swapItems() {
var ul2 = document.getElementById("ul2");
var liChildren = ul2.getElementsByTagName('li');
var first = ul2.liChildren[0];
var last = ul2.liChildren[liChildren.length - 1];
ul2.insertBefore(last, first);
}
That should work as you wanted.
Remove the whitespaces in #ul2. Whitespaces are also considered as children nodes.
Related
I am adding a bunch of spans to a div layer with appendchild like so:
var newSent = document.createElement("SPAN");
var current = document.createTextNode(sentInput.value);
newSent.style.backgroundColor = sentColor;
newSent.className = "sentSpan";
newSent.id = count - 1;
newSent.appendChild(current);
outputBox.appendChild(newSent);
Where outputBox is the name of the div layer and sentInput is the current value of an input text box. I need each of these spans to be click-able, and then delete their value from an array. Currently I have an event listener for this:
delCount = 0;
newSent.addEventListener("click", function(){
var x = parseInt(newSent.id);
sentCount.splice(x - delCount, 1);
sentNum.splice(x - delCount, 1);
delCount = delCount + 1;
newSent.remove(x);
});
The idea is that every time I delete a span, the delCount goes up to compensate for the now smaller array.
This doesn't work very well after a couple of deletions... I don't seem to be able to figure out the math or the proper method for handling the changing array. After clicking two or three spans I end up deleting the value in the array that was associated with the span next to it, but successfully removing the span itself. This array is displayed on a graph, so it's vital that it's displayed properly.
I temporarily had the arrays replace the deleted values with "0" which worked very well, but I need them to not show up in the array at all. Any help is greatly appreciated!
EDIT: added a jsfiddle http://jsfiddle.net/eL11o6mu/ though the display looks terrible in a window that small...
I want to be able to click on a specific element, and have it send a value to a textarea. However, I want it to append to a specific row/line of the textarea.
What I am trying to build is very similar to what happens when you click the notes of the fret board on this site: http://www.guitartabcreator.com/version2/ In fact, i want it almost exactly the same as this.
But right now I am really just trying to see how I can target the specific row, as it seems doable based on this website.
Currently I am using javascript to send a value based on clicking a specific element.
Here is the js:
<script type="text/javascript">
function addNote0(text,element_id) {
document.getElementById(element_id).value += text;
}
</script>
This is the HTML that represents the clickable element:
<td> x </td>
This is the textarea:
<textarea rows="6" cols="24" id="tabText" name="text">-
-
-
-
-
-</textarea>
This works fine for sending the value. But it obviously just goes to the next available space. I am a total newb when it comes to javascript, so I am just not sure where to begin with trying to target a specific line.
What I have currently can be viewed here: http://aldentec.com/tab/
Working code:
After some help, here is the final code that made this work:
<script>
function addNote0(text,element_id) {
document.getElementById(element_id).value += text;
var tabTextRows = ['','','','','',''];
$('td').click(function(){
var fret = $(this).index() - 1;
var line = $(this).parent().index() -1;
updateNote(fret, line);
});
function updateNote(fret, line){
var i;
for(i=0;i<tabTextRows.length;i++){
if(i == line) tabTextRows[i]+='-'+fret+'-';
else tabTextRows[i]+='---';
$('#tabText').val(tabTextRows.join('\n'));
}
}}
window.onload = function() {
addNote0('', 'tabText');
};
</script>
Tried to solve this only in JS.
What I did here is use an array to model each row of the textfield (note the array length is 6).
Then I used a jQuery selector to trigger any time a <td> element is clicked which calculates the fret and string that was clicked relative to the HTML tree then calls the updateNote function. (If you change the table, the solution will probably break).
In the update note function, I iterate through the tabTextRows array, adding the appropriate note. Finally, I set the value of the <textarea> to the array joined by '\n' (newline char).
Works for me on the site you linked.
This solution is dependant on jQuery however, so make sure that's included.
Also you should consider using a monospaced font so the spacing doesn't get messed up.
var tabTextRows = ['','','','','',''];
$('td').click(function(){
var fret = $(this).index() - 1;
var line = $(this).parent().index() -1;
updateNote(fret, line);
});
function updateNote(fret, line){
var i;
for(i=0;i<tabTextRows.length;i++){
if(i == line) tabTextRows[i]+='-'+fret+'-';
else tabTextRows[i]+='---';
$('#tabText').val(tabTextRows.join('\n'));
}
}
I wrote the guitartabcreator website. Jacob Mattison is correct - I am using the text area for display purposes. Managing the data occurs in the backend. After seeing your site, it looks like you've got the basics of my idea down.
I am currently using a html5 text editor (bootstrap-wysihtml5). I'm trying to use a "keypress" event (on tab) to select specific words within the text editor.
Here is an example of my text:
<div>
My name is {{name}} and I enjoy {{programming in Rails}}.
</div>
<div>
{{Friend Name}} suggested that we get in touch to {{catch up}}.
He spoke {{highly}} about you and said that we should {{get together sometime}}.
</div>
Goal: on 'keypress' tab event, highlight each word within {{ }}.
i.e.
1. Press tab once, will highlight {{name}}.
2. Press tab on the 2nd time, will highlight {{programming in Rails}}, & so on.
Here is what I have implemented so far:
$('#wysihtml5').each(function(i, elem) {
$(elem).wysihtml5({
"font-styles": true,
"events": {
"focus": function() {
$('.wysihtml5-sandbox').contents().find('body').on("keydown",function(event) {
event.preventDefault();
var numLoops = _.size($(this).children());
var keyCode = event.keyCode || event.which;
if (keyCode == 9){
// loop thru all children divs
for (var i = 0; i < numLoops; i++) {
// get array of all matched items {{}}
var sentence = $($(this).children()[i]).html();
var toSwap = sentence.match(/\{{(.*?)\}}/g);
var numSwap = _.size(toSwap);
// NEED TO FIGURE OUT: How to select matched item..and move to the next one on tab
}
}
});
}
}
});
});
Any thoughts? I've been spending 2 days on finding how to make this work. The following are the references for what I have looked at:
jQuery Set Cursor Position in Text Area
Selecting text in an element (akin to highlighting with your mouse)
javascript regex replace html chars
What Is A Text Node, Its Uses? //document.createTextNode()
What you want is the index of the Regex matches.
If you perform the Regex as follows:
var reg = /\{{(.*?)\}}/g; // The Regex selector
while(match=reg.exec(sentence)) { // Iterate all the matched strings
// match.index gives the starting position of the matched string
// match.length gives the length of the matched string, number of characters
}
You will get the position and length of all the matches which can be used for selection. The while loop iterates all the matches.
Save the matches and user their index and length values to select them one by one.
Edit
Back again. As you probably have experienced, selecting text in javascript is not the easiest task but it is completely doable.
I put together a small JSFiddle to demonstrate the technique I used to get the correct result. You can find it here.
I hope it's kind of clear and I tried to comment it well.
Of course, if you have any question, just ask!
Cheers!
Here is an example. Check the console for the result. The first two divs (not appended; above the <script> in the console) have the proper spacing and indention. However, the second two divs do not show the same formatting or white space as the original even though they are completely the same, but appended.
For example the input
var newElem = document.createElement('div');
document.body.appendChild(newElem);
var another = document.createElement('div');
newElem.appendChild(another);
console.log(document.body.innerHTML);
Gives the output
<div><div></div></div>
When I want it to look like
<div>
<div></div>
</div>
Is there any way to generate the proper white space between appended elements and retain that spacing when obtaining it using innerHTML (or a possible similar means)? I need to be able to visually display the hierarchy and structure of the page I'm working on.
I have tried appending it within an element that is in the actual HTML but it has the same behavior
I'd be okay with doing it using text nodes and line breaks as lincolnk suggested, but it needs to affect dynamic results, meaning I cannot use the same .createTextNode(' </br>') because different elements are in different levels of the hierarchy
No jQuery please
I think you're asking to be able to append elements to the DOM, such that the string returned from document.body.innerHTML will be formatted with indentation etc. as if you'd typed it into a text editor, right?
If so, something like this might work:
function indentedAppend(parent,child) {
var indent = "",
elem = parent;
while (elem && elem !== document.body) {
indent += " ";
elem = elem.parentNode;
}
if (parent.hasChildNodes() && parent.lastChild.nodeType === 3 && /^\s*[\r\n]\s*$/.test(parent.lastChild.textContent)) {
parent.insertBefore(document.createTextNode("\n" + indent), parent.lastChild);
parent.insertBefore(child, parent.lastChild);
} else {
parent.appendChild(document.createTextNode("\n" + indent));
parent.appendChild(child);
parent.appendChild(document.createTextNode("\n" + indent.slice(0,-2)));
}
}
demo: http://jsbin.com/ilAsAki/28/edit
I've not put too much thought into it, so you might need to play with it, but it's a starting point at least.
Also, i've assumed an indentation of 2 spaces as that's what you seemed to be using.
Oh, and you'll obviously need to be careful when using this with a <pre> tag or anywhere the CSS is set to maintain the whitespace of the HTML.
You can use document.createTextNode() to add a string directly.
var ft = document.createElement('div');
document.body.appendChild(ft);
document.body.appendChild(document.createTextNode(' '));
var another = document.createElement('div');
document.body.appendChild(another);
console.log(document.body.innerHTML);
I have dynamically created span elements that listen to an onkeyup action.
For example: When a user types into a textbox, it should replace the text inside the <span> too.
lets say I create N elements of span.
N-1 of then works perfectly, but the last one does not.
When I use Inspect Element (Chrome browser) and make the call
document.getElementById("span...").innerHTML
I see the new text, but on screen I still see the old one.
My code:
1. This is the part when i dynamically create the text inputs
titleInput.onkeyup = (function ()
{
var inputObject = titleInput;
var chartIndex = numberOfTds; return function () {
UpdateTitleInMagnifiedView(inputObject, chartIndex);
} })();
UpdateTitleInMagnifiedView - function that updates the span elemnts
document.getElementById("title_magnified_" + chartIndex).innerHTML = inputObject.value;