Add new element into DOM with JavaScript - javascript

I am struggling with adding new "button" element into my "list". I was trying to append or someting els but doesn't work. It is not usual ul to li. If you ask why button parent it is form bootstrap list-group
UPDATE JS. IT is now adding "button but not corectlly.
<div class="list-group">
<button type="button" class="list-group-item">
<ul class="desc">
<li class="t-desc50">Add Device</li>
<li class="t-desc55"><i class="fa fa-plus fa-2x" aria-hidden="true"></i></li>
</ul>
</button>
<button type="button" class="list-group-item" id="new-item>
<ul class="desc">
<li class="t-desc">Lamp</li>
<li class="t-desc2">5 kwH</li>
<li class="t-desc3"><label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label></li>
</ul>
</button>
<button type="button" class="list-group-item" id="new-item>
<ul class="desc">
<li class="t-desc">AC</li>
<li class="t-desc2">5 kwH</li>
<li class="t-desc3"><label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label></li>
</ul>
</button>
</div>
JS
document.querySelector('.fa-plus').addEventListener('click', addItem
);
function addItem() {
var list = document.getElementById("list-group");
var li = document.createElement("button");
li.setAttribute('id', li);
li.appendChild(document.createTextNode(li));
list.appendChild(li);
}

If you want to add an element to the dom, you can use :
var element = document.createElement(tagName);
https://developer.mozilla.org/fr/docs/Web/API/Document/createElement
Then append your element.
You can add event listener to element, and add class before if you need.
Comment answer
The code you need is probably something like that :
function addItem() {
var list = document.getElementById('list-group')
//Button
var button = document.createElement('button');
button.classList.add("list-group-item");
//Ul
var ul = document.createElement('ul');
ul.classList.add("desc");
//li
var liFirst = document.createElement('li');
var liSecond = document.createElement('li');
var liThird = document.createElement('li');
liFirst.innerHTML = "Lamp"
liSecond.innerHTML = "5 kwH"
//Label
var label = document.createElement('label');
label.classList.add("switch");
var input = document.createElement('input');
input.type = 'checkbox';
var span = document.createElement('span');
span.classList.add("slider");
span.classList.add("round");
label.append(input)
label.append(span)
liThird.append(label)
ul.append(liFirst)
ul.append(liSecond)
ul.append(liThird)
button.append(ul)
list.append(button)
}

You need to pass the function as argument instead of calling it:
// wrong:
document.querySelector('.fa-plus').addEventListener('click', addElement());
// right:
document.querySelector('.fa-plus').addEventListener('click', addElement);
addEventListener expects a callback function, if you call the function first, you are sending the result of the function as argument, which is wrong.
You need to pass the addElement function instead, so the addEventListener calls it.

got it!
function addItem() {
var list = document.getElementById('list-group')
var button = document.createElement('button');
var ul = document.createElement('ul');
var liFirst = document.createElement('li');
var liSecond = document.createElement('li');
var liThird = document.createElement('li');
button.classList.add("list-group-item");
ul.classList.add("desc");
liFirst.classList.add("t-desc")
liSecond.classList.add("t-desc2")
liThird.classList.add("t-desc3")
liFirst.innerText = 'TV'
liSecond.innerText = '5kwh'
liThird.innerHTML = `<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>`
ul.append(liFirst)
ul.append(liSecond)
ul.append(liThird)
button.append(ul)
list.append(button)
}

There are several semantic errors in both the markup and the code. Firstly, <button type="button" class="list-group-item" id="new-item> misses the closing double quotes. Secondly, one should not use an id twice as the OP's example does with id="new-item. At third addEventListener misses its 3rd argument.
Besides that it will be hard if not impossible to capture any click event on the fa-plus classified <i/> element; one should use the whole button instead ... that's what a button is for.
Additionally one might rethink how to retrieve/query the structure one wants to add the new element to. I would suggest a more generic approach that retrieves the top most group parent from within the structure where the click event did occur, thus one can make use of more than just on list-group classified element.
Having sanitized the code the OP'S given example then might look similar to this ...
function getClosestParentByClassName(elm, className) {
while (elm && !elm.classList.contains(className)) {
elm = elm.parentNode;
}
return elm;
}
function addItem(evt) {
//console.log(evt.currentTarget);
var
groupParent = getClosestParentByClassName(evt.currentTarget, 'list-group'),
itemBlueprint = groupParent && groupParent.querySelector('.list-group-item.new-item'),
newGroupItem = (itemBlueprint && itemBlueprint.cloneNode(true)) || createDefaultItem();
//console.log(groupParent, itemBlueprint, newGroupItem);
if (newGroupItem) {
// do whatever needs to be done in order to place the right content into this structure.
groupParent.appendChild(newGroupItem);
}
}
getClosestParentByClassName(document.querySelector('.fa-plus'), 'list-group-item').addEventListener('click', addItem, false);
function createDefaultItem() {
var
renderContainer = document.createElement('div');
renderContainer.innerHTML = [
'<button type="button" class="list-group-item new-item">'
, '<ul class="desc">'
, '<li class="t-desc">#missing t-desc</li>'
, '<li class="t-desc2">#missing t-desc2</li>'
, '<li class="t-desc3">'
, '<label class="switch">'
, '<input type="checkbox">'
, '<span class="slider round"></span>'
, '</label>'
, '</li>'
, '</ul>'
, '</button>'
].join('');
return renderContainer.querySelector('button');
}
.as-console-wrapper { max-height: 100%!important; top: 0; }
<div class="list-group">
<button type="button" class="list-group-item">
<ul class="desc">
<li class="t-desc50">Add Device</li>
<li class="t-desc55"><i class="fa fa-plus fa-2x" aria-hidden="true"></i></li>
</ul>
</button>
<button type="button" class="list-group-item new-item">
<ul class="desc">
<li class="t-desc">Lamp</li>
<li class="t-desc2">5 kwH</li>
<li class="t-desc3">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
</li>
</ul>
</button>
<button type="button" class="list-group-item new-item">
<ul class="desc">
<li class="t-desc">AC</li>
<li class="t-desc2">5 kwH</li>
<li class="t-desc3">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
</li>
</ul>
</button>
</div>

Related

display user input to list using javascript

I'm trying to create a to-do list app but i cant seems to append the user data to my list
html:
<div id="Html">
<input id="input-task" placeholder="New Task" >
<button id="add-btn" type="button" onclick="newTask()">
Add Tasks
</button>
</div>
<div>
<ul id="task-table">
<li>Task 1</li>
</ul>
</div>
separate javascript file:
const inputTask = document.getElementById('input-task').value;
var li = document.createElement('li');
var t = document.createTextNode('inputTask');
li.appendChild(t);
document.getElementById('task-table').appendChild(li);
}
inputTask is variable containing the text value but you using that as if it is string, remove the quotes around it.
I will also suggest you to avoid inline event handler, you can use addEventListener() instead like the following way:
document.getElementById('add-btn').addEventListener('click', newTask);
function newTask(){
const inputTask = document.getElementById('input-task').value;
var li = document.createElement('li');
var t = document.createTextNode(inputTask); //remove quotes here
li.appendChild(t);
document.getElementById('task-table').appendChild(li);
}
<div id="Html">
<input id="input-task" placeholder="New Task" >
<button id="add-btn" type="button">
Add Tasks
</button>
</div>
<div>
<ul id="task-table">
<li>Task 1</li>
</ul>
</div>
Try like this.
You should call newTask function and append child in it.
const inputTask = document.getElementById('input-task').value;
function newTask(){
var li = document.createElement('li');
var t = document.createTextNode(document.getElementById('input-task').value);
li.appendChild(t);
document.getElementById('task-table').appendChild(li);
document.getElementById('input-task').value="";
}
<div id="Html">
<input id="input-task" placeholder="New Task" >
<button id="add-btn" type="button" onclick="newTask()">
Add Tasks
</button>
</div>
<div>
<ul id="task-table">
<li>Task 1</li>
</ul>
</div>
Nothing wrong in your code!
Simple fixed this line
var t = document.createTextNode('inputTask');
Remove ('' quotes)
var t = document.createTextNode(inputTask);
And Final thing I don't know may be you have already done this but I want to mention this
Wrap this code inside the newTask() function
Example: -
function newTask(){
const inputTask = document.getElementById('input-task').value;
var li = document.createElement('li');
var t = document.createTextNode(inputTask);
li.appendChild(t);
document.getElementById('task-table').appendChild(li);
}

add 'ids' to checkbox elems from ~ sibling element innerText val

Goal: I am trying to iterate through a series of checkboxes, and add an "id" to each elem with the value of the checkboxes sibling text value. i.e. inner text of .k-in
Recent attempt:
function addSelectors() {
const checks = document.querySelectorAll('.k-treeview-lines input[type="checkbox"]');
[].forEach.call(checks, function (checks) {
let knn = document.querySelectorAll('.k-treeview-lines input[type="checkbox"] ~ .k-in');
checks.id = knn.innerText;
});
}
HTML is a series of the below:
<div class="k-mid">
<span class="k-checkbox-wrapper" role="presentation">
<input type="checkbox" tabindex="-1" id="undefined"
class="k-checkbox"><-- id here
<span class="k-checkbox-label checkbox-span"></span>
</span>
<span class="k-in">I want this</span><---- this text
</div>
Do not want to load jQuery...
function addSelectors() {
const checks = document.querySelectorAll(
'.k-treeview-lines input[type="checkbox"]'
);
checks.forEach(function (checkbox) {
const textVal = checkbox.parentElement.nextElementSibling.innerText;
checkbox.setAttribute("id", textVal);
});
}
addSelectors();
<div class="k-treeview-lines">
<div class="k-mid">
<span class="k-checkbox-wrapper" role="presentation">
<input
type="checkbox"
tabindex="-1"
id="undefined"
class="k-checkbox"
/>
<span class="k-checkbox-label checkbox-span"></span>
</span>
<span class="k-in">tempID</span>
</div>
</div>
The item you are requesting is not actually the sibling, they don't share the same parent.
You could do something like this:
function addSelectors() {
const checks = document.querySelectorAll('input[type="checkbox"]');
checks.forEach(c => {
c.id = c.parentNode.nextElementSibling.innerText;
});
}
addSelectors();
<div class="k-mid">
<span class="k-checkbox-wrapper" role="presentation">
<input type="checkbox" tabindex="-1" id="undefined" class="k-checkbox">
<span class="k-checkbox-label checkbox-span"></span>
</span>
<span class="k-in">I want this</span>
</div>

Text of List item <li> does not reflected correctly after edited click save button from modal pop up in Javascript

I have nested list item of <li> structured as below. What I am trying to do is to edit each item text from pop up modal and reflect change after I clicked on button Save.
However, the first list item I edited is working well, but from the second time onward, it does not work as expected.
$(document).ready(function() {
$('.modal').modal(); // modal
var child;
$('body').on('click', '.fa-pencil', function(e) {
var text = $(this).closest("li").clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
child = $(this).closest("li").children();
var li_element = $(this).closest('li');
console.log(li_element);
var dataActive = $(this).closest('li').attr('data-act');
var li_icon = li_element.attr('data-icon');
var modal1 = $('#modal1');
var modalBody = modal1.find('.modal-content');
modalBody.find('h4.itemdes').text('');
modalBody.find('.modalBody').html('');
var modalHeader = modalBody.find('h4.itemdes').attr('contenteditable', true).text(text);
dataActive = $(this).closest('li').attr('data-act') == 'Y' ? 'checked="checked"' : '';
ActiveOpt = '<p><label><input type="checkbox" id="active" class="filled-in" ' + dataActive + ' /><span>Active</span></label></p>';
IconOpt = '<p><i class="' + li_icon + '" id="icon_element" aria-hidden="true"></i></p>';
var datahtml = ActiveOpt + IconOpt;
modalBody.find('.modalBody').html(datahtml);
// modalBody.find('.modalBody').append(IconOpt);
$('body').on('click', '.saveChange', function() {
var textarea = $('.itemdes').text();
var appendItem = textarea;
li_element.text('').empty().append(appendItem).append(child);
// $(this).closest("li").text('').empty().append(appendItem).append(child);
ActiveOpt = '';
IconOpt = '';
// li_element = '';
});
// Function to check li data-Acive
$('body').on('change', '#active', function() {
li_element.removeAttr('data-act');
// console.log(li_element.prop('checked'));
if ($(this).prop('checked')) {
li_element.attr('data-act', 'Y');
// li_element.attr('checked','checked');
} else {
li_element.attr('data-act', 'N');
// li_element.removeAttr('checked');
}
})
});
})
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Materialized CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Modal Trigger -->
<!-- Modal Structure -->
<div id="modal1" class="modal">
<div class="modal-content">
<h4 style="width: auto; float: left;"><i class="fa fa-pencil-square-o" aria-hidden="true"> </i></h4>
<h4 class="itemdes">Modal Header</h4>
<div class="modalBody">
<p>A bunch of text</p>
</div>
Save
</div>
</div>
<ol class="example example2">
<li data-formdesc="User" data-act="Y" data-icon="fa fa-heart">
<i class="fa fa-heart"></i>User<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Cash Withdrawal" data-act="Y" data-icon="">
<i class=""></i>Cash Withdrawal<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Branch1" data-act="Y" data-icon="fa fa-futbol-o">
<i class="fa fa-futbol-o"></i>Branch1<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Customer Centre" data-act="Y" data-icon="">
<i class=""></i>Customer Centre<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Customers Detail Listing" data-act="Y" data-icon="">
<i class=""></i>Customers Detail Listing<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
<li data-formdesc="2 two" data-act="Y" data-icon="fa fa-linkedin">
<i class="fa fa-linkedin"></i>2 two<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Cash Withdrawal" data-act="Y" data-icon="">
<i class=""></i>Cash Withdrawal<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
<li data-formdesc="Till to Till Transfer" data-act="Y" data-icon="">
<i class=""></i>Till to Till Transfer<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol>
<li data-formdesc="Disbursement Voucher" data-act="Y" data-icon="">
<i class=""></i>Disbursement Voucher<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
<li data-formdesc="Income Posting" data-act="Y" data-icon="">
<i class=""></i>Income Posting<i class="fa fa-pencil modal-trigger" aria-hidden="true" data-target="modal1"></i>
<ol></ol>
</li>
</ol>
</li>
</ol>
For example, first time I edit list item 'User' to 'Users', after I clicked on save, the item text changed well. But at second time I edit another item, let's say 'Cash Withdrawal' to 'Cash Withdrawaling', after clicked Save, the item I edited change to 'Cash Withdrawaling', but list item 'Users' that I edited previously, also change to 'Cash Withdrawaling' as well.
I did not know what is incorrect with my JavaScript. How can I correct that? Thanks
At every click on .fa-pencil you add again event listeners to .saveChange and #active, using local variables like li_element, which are scoped to the callback function. This means that the second time you edit an item, two callbacks are executed, but the first still uses the previous value for li_element, thus setting the new value to the previous edited element too.
You should declare all the event listeners once, and move all the needed variables to the same level as var child.
This should work
$(document).ready(function() {
$('.modal').modal(); // modal
var child;
var li_element;
$('body').on('click', '.fa-pencil', function(e) {
var text = $(this).closest("li").clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
child = $(this).closest("li").children();
li_element = $(this).closest('li');
console.log(li_element);
var dataActive = $(this).closest('li').attr('data-act');
var li_icon = li_element.attr('data-icon');
var modal1 = $('#modal1');
var modalBody = modal1.find('.modal-content');
modalBody.find('h4.itemdes').text('');
modalBody.find('.modalBody').html('');
var modalHeader = modalBody.find('h4.itemdes').attr('contenteditable', true).text(text);
dataActive = $(this).closest('li').attr('data-act') == 'Y' ? 'checked="checked"' : '';
ActiveOpt = '<p><label><input type="checkbox" id="active" class="filled-in" ' + dataActive + ' /><span>Active</span></label></p>';
IconOpt = '<p><i class="' + li_icon + '" id="icon_element" aria-hidden="true"></i></p>';
var datahtml = ActiveOpt + IconOpt;
modalBody.find('.modalBody').html(datahtml);
// modalBody.find('.modalBody').append(IconOpt);
});
$('body').on('click', '.saveChange', function() {
var textarea = $('.itemdes').text();
var appendItem = textarea;
li_element.text('').empty().append(appendItem).append(child);
// $(this).closest("li").text('').empty().append(appendItem).append(child);
ActiveOpt = '';
IconOpt = '';
// li_element = '';
});
// Function to check li data-Acive
$('body').on('change', '#active', function() {
li_element.removeAttr('data-act');
// console.log(li_element.prop('checked'));
if ($(this).prop('checked')) {
li_element.attr('data-act', 'Y');
// li_element.attr('checked','checked');
} else {
li_element.attr('data-act', 'N');
// li_element.removeAttr('checked');
}
})
})

Is it possible to display a JavaScript variable where the value will change in between two <li> tags?

Apologies if the question title is a little vague, I'm still a beginner in javascript (I'm open to edit suggestions!). If you look at the screenshot above I have 5 input boxes with values in it. These values are ratings returned by Google Places APIs and every time a user searches a new location these values will change. I'm displaying them like so.(I'll use the Gym option as an example).
Gymcallback function (Calucluates an average rating for all gyms in the area)
function gymCallback(results2, status2) {
var totalRating = 0,
ratedCount = 0;
results2.forEach(function( place ) {
if (place.rating !== undefined) {
ratedCount++;
totalRating += place.rating;
}
});
var averageRating = results2.length == 0 ? 0 : totalRating / ratedCount;
var averageRatingRounded = averageRating.toFixed(1);
var averageGymRatingTB = document.getElementById('gymAvgRating');
averageGymRatingTB.value = averageRatingRounded;
}
The averageGymRatingTB value will then be passed into the input box in the screenshot like so:
<p>
Gyms:
<input type="text" size="10" name="gymAvgRating" id="gymAvgRating" />
</p>
My question is, is it possible to display the gym rating next "fitness" in the navbar?
Fitness list option in the navbar
<li data-toggle="collapse" data-target="#fitness" class="collapsed">
<a onclick="clearMarkers();GymReport();" href="#"><i class="fa fa-heart fa-lg"></i> Fitness <span
class="arrow"></span></a>
</li>
I've looked at using the following approach by adding an innerhtml element using 'test' as the value I'm passing through but this won't work, so I'm unsure.
<li data-toggle="collapse" data-target="#fitness" class="collapsed">
<a onclick="clearMarkers();GymReport();" href="#"><i class="fa fa-heart fa-lg"></i> Fitness <span
class="arrow"></span></a><h5 id = demo></h5>
</li>
And in my javascript I use this:
document.getElementById("demo").innerHTML = "test";
You can simply add a span to the navigation, store it in a variable and change the content of using innerText.
function clearMarkers() {}
function GymReport() {}
var a = document.querySelector('li[data-target="#fitness"] > a'); //get the a in the menu
var fitnessScore = document.createElement("span"); //create a new span
a.appendChild(fitnessScore); // add the span to the a
function changeValue(v) {
fitnessScore.innerText = Math.random();
}
<ul>
<li data-toggle="collapse" data-target="#fitness" class="collapsed">
<a onclick="clearMarkers();GymReport();" href="#"><i class="fa fa-heart fa-lg"></i> Fitness <span
class="arrow"></span></a>
</li>
</ul>
<input type="button" onclick='changeValue()' value="Change value">

How to remove element in jquery sortable?

My HTML Code is like this :
<div class="content">
box 1 (Customer)
<ol class='example mauDIDROP vertical'>
<li>Valentino Rossi</li>
<li>David Beckham</li>
<li>Eden Hazard</li>
<li>Lionel Messi</li>
<li>Christiano Ronaldo</li>
<li>Frank Lampard</li>
</ol>
</div>
<div class="content">
<form id="myForm" action="" method="POST">
box 2 (Room Type)
<br>
<select id="room_type">
<option value="1">Single Room</option>
<option value="2">Double Room</option>
<option value="3">Twin Room</option>
</select>
<input type="button" value="Add" style="margin-top: -10px;" id="add_room">
<ol class="example areaDROP vertical" id="room_list">
<li class="room_number msg1" id="room_remove11">Deluxe Room<div class="room-remove"><i class="fa fa-times"></i></div><ol><li id="room_remove21">John Terry<div class="room-remove"><i class="fa fa-times"></i></div></li></ol></li>
<li class="room_number msg1" id="room_remove12">Family Room<div class="room-remove"><i class="fa fa-times"></i></div><ol><li id="room_remove22">Jose Mourinho<div class="room-remove"><i class="fa fa-times"></i></div></li></ol></li>
</ol>
<button type="submit">Save</button>
</form>
</div>
My Javascript is like this :
function delete_room(id){
$('#room_remove'+id).remove();
}
$(document).ready(function(){
$("ol.mauDIDROP").sortable({
group: '.example'
});
$("ol.areaDROP").sortable({
group: '.example',
});
var room_type_number = 5;
$('#add_room').click(function(){
var text = $("#room_type option:selected").html();
var room_type_id = $.trim($('#room_type').val());
$('#room_list').append('<li class="room_number msg" id="room_remove'+(++room_type_number)+'" data-id="'+room_type_id+'" data-name="'+text+'">'+text+'<div class="room-remove"><i class="fa fa-times"></i></div><ol></ol></li>');
$("ol.mauDIDROP").sortable({
group: '.example'
});
$("ol.areaDROP").sortable({
group: '.example',
});
});
});
Demo is like this : https://jsfiddle.net/oscar11/4wnfnz6z/1/
When I click on the close icon, the selected element successfully deleted.
But what I want:
When I click on the close icon, the selected element removed and deleted customer element appears in box 1.
For example : http://imgur.com/rEzryt3
When I click on the close icon(deluxe room), it will look like this : http://imgur.com/YpkBTKH
How to keep deleted customer element in moving towards the box 1?
Any suggestion to solve my problem?
Thank you
You can change a bit your delete_room function so it would grab the names of customers from the room you are removing and then append them as lis to your left container:
function delete_room(id){
var customers = '';
$('#room_remove'+id).find('li').each( function() {
customers += '<li>'+$(this).text()+'</li>';
});
$('#room_remove'+id).remove();
$('ol.example.mauDIDROP.vertical').append(customers);
}
Check fiddle: Fiddle
This approach have better performance, cause you are setting the find to a var and doing a loop instead of doind a loop with the find.
var child = $('#room_remove'+id).find('li');
if(child.length > 0){
var li = "";
child.each(function(){
li += "<li>"+$(this).text()+"</li>";
});
}
$(".mauDIDROP").append($(li));

Categories

Resources