I have the following html code.
<!DOCTYPE html>
<html>
<body>
<div>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
</div>
<div id="1">
<p id="2">Paragraph First
<ol id="3">
<li id="4">alice
<ul id="31">
<li id="41">bob</li>
<li id="51">foo</li>
<li id="61">grow</li>
</ul>
</li>
<li id="5">coding</li>
<li id="6">fun</li>
</ol>
</p>
</div>
<div>
<p>Paragraph Second</p>
</div>
</body>
</html>
I want to get the text of all the elements to an array(pre order transverse preffered).
So for the following example array consists of,
[My First Heading, first paragraph, Paragraph First, alice, bob, foo, grow, coding, fun]
I can use jQuery if it needsHow. can I achieve this ?
My own non-working attempt
var root = document.documentElement;
recursivePreorder(root); // Recusively find and handle all text nodes
function recursivePreorder(node) {
// If node is a text node
if (node.type == 3) {
//add to the array
} // else recurse for each child node
else {
for(var i=0; i<node.childNodes.length; i++)
recursivePreorder(node.childNodes[i]);
}
}
UPDATE
when my tag is <li id="41">boblink textalice</li> it gives me as [bob, link text, alice] . But I want the output as [boblink textalice] means links are working correctly. This is my current solution,
var arr=$('body').find('*').contents().filter(function () { return this.nodeType === 3&&this.textContent.trim()!=""; });
how to solve this problem ?
Try this:
var arr = [];
$(document).find('li,p,h1').each(function(e){
arr.push(($(this).clone().children().remove().end().text()).trim());
})
Demo
You can use map() for that.
$(document).ready(function() {
var arr = $("#container *").contents().map(function() {
if (this.nodeType === 3 && this.textContent.trim() != "") {
return this.textContent.trim();
}
});
console.log(arr);
});
nodeType will be 3 for text contents
Demo
Related
I am being able to provide option's in the menu bar but when I click on any of the option it's working absolutely fine,but if I tried to select twice it is changing at all places.
For Ex.
I want to make a ordered list such as:
1.Some Text here
a.option 1 b.option 2
c.option 3 d.option 4.
When I am trying to select some text its also converting 1 to A.
Please help.Thanks in advance
document.execCommand('insertUnorderedList',true,null);
let selectedStyle = event.target.parentNode.classList.value;
$('li').attr('id', function(i) {
return 'unorder'+(counter+1);
});
$('ol > li').css({'list-style-type':selectedStyle});
You can ignore the counter part its not required.I was trying to put id at every element and use jquery to update only that part.
let counter = 0;
document.querySelectorAll (".unorder-list-select .unorder-list-main .unorder-container ul").forEach((elem)=>{
elem.addEventListener("click",(event)=>{
counter++;
$('li').attr('id', function(i) {
return 'unorder'+(counter+1);
});
$('ul > li').css({'list-style-type':selectedStyle});
}
HTML
<div class="order-list-select" id="orderList" draggable="true">
<div>
<span class="jodit_popup_triangle"></span>
<div class="math-toolbar-top" id="orderlistHeader"></div>
<div class="order-list-main">
<div class="order-list-container"></div>
<div class="order-container">
<ol class="upper-roman">
<li><hr></li>
</ol>
<ol class="decimal">
<li><hr></li>
</ol>
</div>
</div>
</div>
</div>
Actual
1.text
2.text
Some text here
1.Txt
2.Txt
Expected
1.text
2.text
Some text here
a.Txt
b.Txt
I did it by Jquery don't know if its right approach but it has made me achieve my task.
Below is the code for my this.
document.querySelectorAll(".unorder-list-select .unorder-list-main .unorder-container ul").forEach((elem)=>{
elem.addEventListener("click",(event)=>{
counter++;
document.execCommand('insertUnorderedList',true,null);
let selectedStyle = event.target.parentNode.classList.value;
let select = window.getSelection().focusNode.parentElement.parentElement;
let ul_id = ""
$(select).attr('id', function(i) {
ul_id = "unorder"+(counter);
return ul_id;
});
if(selectedStyle == "right-arrow"){
$('#'+ul_id).css({'list-style-image':`url('icons/list-right-editor.svg')`});
}else if(selectedStyle == "open-square"){
$('#'+ul_id).css({'list-style-image':`url('icons/square-open-editor.svg')`});
}else{
$('ul').attr('type',function(){
return selectedStyle;
})
$('#'+ul_id).css({'list-style-type':selectedStyle});
}
document.querySelector(".unorder-list-select").remove();
})
});
Please change the classess accordingly to get the tag and click.
I'm looking to find a way to check if classes in an element matches those in another element. I have tried using code below:
Using dataset seems to work, however, I'm looking to explore the possibility of doing this through pure Javascript. The line that works is commented out (var matches = first.dataset.name === second.dataset.name;) and the line that I'm having difficulty getting to work is (var matches = first.classList === second.classList;)
javascript:
//check for 2 matching squares
function checkIfMatches() {
//var matches = first.dataset.name === second.dataset.name;
var matches = first.classList === second.classList;
matches ? disable() : unflip();
}
html:
<li class="card">
<i class="pa pa-test"></i>
</li>
<li class="card">
<i class="pa pa-test"></i>
</li>
Thanks for any help. If more details are needed you can comment.
Use Array spread [...classList] to make the classList an Array, then check if every member is contained in the classList of the other using Array.prototype.every().
function sameClassList({classList: x},{classList: y}) {
return [...x].every(z=>y.contains(z))
&& [...y].every(z=>x.contains(z));
}
console.log(sameClassList(a,b)); // true
console.log(sameClassList(a,c)); // false
console.log(sameClassList(b,c)); // false
<div class="foo bar" id="a"></div>
<div class="bar foo" id="b"></div>
<div class="foo bar baz" id="c"></div>
Taking the comments into account, this solves it independently of the order.
Changed the example a bit, so it could be executed.
//check for 2 matching squares
function checkIfMatches() {
var elements = document.getElementsByClassName('card')
var first = elements[0].getElementsByTagName('i')[0]
var second = elements[1].getElementsByTagName('i')[0]
var matches = first.classList.length === second.classList.length
first.classList.forEach(entry => matches = matches && second.classList.contains(entry))
console.log(matches)
// matches ? disable() : unflip();
}
checkIfMatches()
<li class="card">
<i class="pa pa-test"></i>
</li>
<li class="card">
<i class="pa pa-test"></i>
</li>
I have a list that I'm trying to filter, and then remove the filtered results. I found a ready made solution for the filtering in w3schools, but I'm having trouble with removing lines.
My html is here:
<body>
<ul id="project-list">
<li>Please please me</li>
<li>With the Beatles</li>
<li>A Hard Day's Night</li>
<li>Beatles for Sale</li>
<li>Help!</li>
<li>Rubber Soul</li>
<li>Revolver</li>
<li>Sgt. Pepper's Lonely Hearts Club Band</li>
<li>The Beatles (The White Album)</li>
<li>Yellow Submarine</li>
<li>Abbey Road</li>
<li>Let It Be</li>
</ul>
<div data-role="footer" class="ui-grid-a" data-position="fixed">
<div id="myNavbar" data-role="navbar" class="navbar">
<div class="ui-block-a" style="width:auto">
<button id="remove" onclick="listDelete">Remove</button>
</div>
<script>
$("button").click(function () {
$("li").remove(":contains('Beatles')");
});
</script>
<div class="ui-block-b" style="width:70%">
<input type="text" id="search-input" onkeyup="listFilter()" placeholder="Filter list...">
</div>
</div>
</div><!--/footer-->
The filtering function is this
function listFilter() {
// Declare variables
var input, filter, ul, li, a, i;
input = document.getElementById('search-input');
filter = input.value.toUpperCase();
ul = document.getElementById("project-list");
li = ul.getElementsByTagName('li');
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
The above code makes the button delete every line containing the word "Beatles". I'm trying to remove the lines that contain whatever goes into search-input, preferably non-case sensitive (just like the filtering). Ideally, I want this to not work when the filter textbox is empty, so that an accidental click on the remove button won't delete the whole list.
I'm using jquery-2.1.1 and jqm-1.4.4
hope this will work for you. Change click event to this. It is still case sensitive:
$("button").click(function () {
var fltr = $("#search-input").val();
if (fltr)
$("li").remove(":contains('" + fltr+ "')");
});
Based on diabolic's answer and Highway Of Life's icontains expression, the non case sensitive way to do this is the following:
Load the following two in your header, in one or two separate files:
function listDelete(){
$("button").click(function () {
var input = $("#search-input").val();
if (input) $("li").remove(":icontains('" +input+ "')");
});
}
// non-case sensitive contains expression
jQuery.expr[':'].icontains = function(a, i, m) {
return jQuery(a).text().toUpperCase()
.indexOf(m[3].toUpperCase()) >= 0;
};
Then your button should be like this:
<button id="remove" onclick="listDelete()">Remove</button>
this is probably an easy question for you guys but I'm very new to coding and can't figure out this. I have a code that I want to randomize the given choices in the questions, and I've found a script online that does that but it's not working. I don't know what the
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function() {
means so I tried to put all id that I don't need to randomize in it but it's still not working.
Can someone help me this please? Also is there anyway I can add choice "A", choice "B", choice "C", and choice "D" in front of each given options so even after the options(answers) are randomized, the A,B,C,D options will still be in order? Thank you. Here's the code:
HTML:
<!DOCTYPE html>
<html>
<body>
<script src="JQ.js"></script>
<script src="function.js"></script>
<link href="style.css" rel="stylesheet" />
<div id="quiz_container">
<ul class="quiz_container">
<li class="single_question" data-question-id="1" data-correct-answer="1">
<div class="question">
<h1 class="title">P.1 Grammar Review</h1>
<p class="text">1. "What is your name__"</p>
</div>
<ul class="options">
<li value="1">?</li>
<li value="2">.</li>
<li value="3">,</li>
</ul>
<div class="result"></div>
</li>
<li class="single_question" data-question-id="2" data-correct-answer="b">
<div class="question">
<p class="text">2. "Do you like the banana__"</p>
</div>
<ul class="options">
<li value="a">.</li>
<li value="b">?</li>
<li value="c">,</li>
</ul>
<div class="result"></div>
</li>
</div>
</body>
</html>
JS:
$(document).ready(function () {
/*
* shuffles the array
* #param {Array} myArray array to shuffle
*/
function shuffleArray(myArray) {
for (var i = myArray.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = temp;
}
return myArray;
}
var $ul, $li, li_content, li_list;
// find all lists to shuffle
$("#quiz_container > ul").each(function () {
$ul = $(this);
li_list = [];
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function () {
// add content to the array and remove item from the DOM
li_list.push($(this).html());
$(this).remove();
});
// shuffle the list
li_list = shuffleArray(li_list);
while (li_content = li_list.pop()) {
// create <li> element and put it back to the DOM
$li = $("<li />").html(li_content);
$ul.append($li);
}
});
$("#contact_div").show();
});
$(document).on('click', '.single_question .options li', function () {
// Save the question of the clicked option
question = $(this).parents('.single_question');
// Remove If Anyother option is already selected
question.find('.selected').removeClass('selected');
// Add selected class to the clicked li
$(this).addClass('selected');
// selected option value
selected_answer_value = $(this).attr("value");
// Value of correct answer from '.single-question' attribute
correct_answer_value = question.attr("data-correct-answer");
correct_answer_text = question.find('.options').find("li[value='" + correct_answer_value + "']").text();
if (correct_answer_value == selected_answer_value)
result = "<div class='correct'> Correct ! </div>";
else
result = "<div class='wrong'> Correct answer is -> " + correct_answer_text + "</div>";
// Write the result of the question
$(this).parents('.single_question').find('.result').html(result);
// Calculate the score
score_calculator();
});
/**
* It loops through every question and increments the value when "data-correct-answer" value and "option's value" are same
*/
function score_calculator() {
score = 0;
$('.single_question').each(function () {
question = $(this);
if (question.attr('data-correct-answer') == question.find('.selected').attr("value")) {
score++;
}
});
$('.correct_answers').html(score);
}
It looks like you're using jQuery, even though the question isn't tagged as such. If that's the case, you can use a code snippet written by Chris Coyier of CSS-Tricks called shuffle children.
Here's an example of the code in action.
$.fn.shuffleChildren = function() {
$.each(this.get(), function(index, el) {
var $el = $(el);
var $find = $el.children();
$find.sort(function() {
return 0.5 - Math.random();
});
$el.empty();
$find.appendTo($el);
});
};
$("ul.randomized").shuffleChildren();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Static List:</h4>
<ul>
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
<h4>Randomized List:</h4>
<ul class="randomized">
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
In order to apply it to your own code, all you'd need to do is modify the CSS selector at the bottom of the jQuery snippet. In your case, ul.options might be a good choice.
Here are a couple of examples using your markup:
jsFiddle
Self-Contained HTML Doc
I want to append the <li> from one <ul> to another <ul> that's created on the fly. I want to group the list-items into new sub-lists based on their data-group attribute.
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
Basically I'm trying to loop through this list and grap all <li> from each group, and then move it to another <ul>.
This is what I have so far, but I'm not getting the expected results. I have done this in Excel in the past but can't get it to work with jQuery.
var listItems = $("#sortable1").children("li");
listItems.each(function (idx, li) {
var product = $(li);
//grab current li
var str = $(this).text();
if (idx > 0) {
//append li
str += str;
if ($(this).data("group") != $(this).prev().data("group")) {
//I should be getting test and test1.
//but alert is only giving test1 test1.
alert(str);
//need to break into groups
//do something with groups
}
}
});
How about something like this:
$(function() {
var sortable = $("#sortable1"),
content = $("#content");
var groups = [];
sortable.find("li").each(function() {
var group = $(this).data("group");
if($.inArray(group, groups) === -1) {
groups.push(group);
}
});
groups.forEach(function(group) {
var liElements = sortable.find("li[data-group='" + group + "']"),
groupUl = $("<ul>").append(liElements);
content.append(groupUl);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
<div id="content">
</div>
I hope I didn't misunderstand you.