I am implementing a system similar to data-reactid (from scratch). Something like this: (not exactly for the same purpose as data-reactid is used):
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
<p></p>
<p></p>
<p></p>
</div>
</body>
</html>
to
<!DOCTYPE html>
<html data-id="0">
<head data-id="0.0">
<title data-id="0.0.0"></title>
</head>
<body data-id="0.1">
<div data-id="0.1.1">
<p data-id="0.1.1.0"></p>
<p data-id="0.1.1.1"></p>
<p data-id="0.1.1.2"></p>
</div>
</body>
</html>
I am able to create a JSON object of the parsed HTML but unable to do what I want in a simpler manner, could you please help me, with same!
function mapDOM(element, json) {
var treeObject = {};
// If string convert to document Node
if (typeof element === "string") {
if (window.DOMParser) {
parser = new DOMParser();
docNode = parser.parseFromString(element,"text/xml");
} else { // Microsoft strikes again
docNode = new ActiveXObject("Microsoft.XMLDOM");
docNode.async = false;
docNode.loadXML(element);
}
element = docNode.firstChild;
}
//Recursively loop through DOM elements and assign properties to object
var li=lj=lk=-1;
function treeHTML(element, object) {
++li;
object["type"] = element.nodeName;
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object["content"] = [];
for (var i = 0; i < nodeList.length; i++) {
++lj;
if (nodeList[i].nodeType == 3) {
object["content"].push(nodeList[i].nodeValue);
} else {
object["content"].push({});
treeHTML(nodeList[i], object["content"][object["content"].length -1]);
}
document.getElementsByTagName(nodeList[i])[i].setAttribute("data-reactid","0."+i+"."+li+"."+lj);
}
}
}
if (element.attributes != null) {
if (element.attributes.length) {
object["attributes"] = {};
for (var i = 0; i < element.attributes.length; i++) {
object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}
like that?
function processNode(node, id) {
id = !id ? "0" : String(id);
node.dataset.id = id;
return {
id: id,
type: node.nodeName.toLowerCase(),
content: processNodeList( node.childNodes, id + "." ),
attributes: processAttributes( node.attributes )
}
}
function processNodeList(nodes, prefix){
prefix = !prefix ? "" : String(prefix);
for(var out, i=0, j=0, len = (nodes && nodes.length)|0; i < len; ++i){
var node = nodes[i], nt = node.nodeType;
if(nt === 1){ //Element
value = processNode(node, prefix + j++);
}else if(nt === 3){ //Text-Node
//especially should be kept, and not replaced on stringify
var text = node.textContent.replace(/[\u00A0<>&\u00AD]/g, toHtmlEntity);
/*
//TODO: move that into a filter, applied when the Array is built
//remove all-whitespace-nodes between two block-nodes like p,div,section,h1-h6
if((i === 0 || i === nodes.length-1) && /^[\r\n\t ]*$/.test(text)){
//remove whitespace at the beginning or the end of the node
continue;
}
*/
//compact multiple spaces into a single one
value = text.replace(/([\r\n\t ])+/g, "$1");
}else{
continue;
}
out || (out = []);
out.push(value);
}
return out;
}
function processAttributes(attrs){
for(var out, i = 0, len = (attrs && attrs.length)|0; i < len; ++i){
var attr = attrs[i];
if(attr.nodeName === "data-id") continue;
out || (out = {});
out[attr.nodeName] = attr.nodeValue;
}
return out;
}
function toHtmlEntity(c){
switch(c.charCodeAt(0)){
case 160: return " ";
case 38: return "&";
case 60: return "<";
case 62: return ">";
case 173: return "";
}
return c;
}
function mapDOM(element) {
// If string convert to document Node
if (typeof element === "string") {
if (window.DOMParser) {
parser = new DOMParser();
docNode = parser.parseFromString(element,"text/xml");
} else { // Microsoft strikes again
docNode = new ActiveXObject("Microsoft.XMLDOM");
docNode.async = false;
docNode.loadXML(element);
}
element = docNode.firstChild;
}
return processNode(element);
}
var tree = mapDOM(document.body);
console.log(JSON.stringify(tree, null, 4));
Related
I have different id's on different elements that are used in an input field when the user can type in the letter (Element 1 = A, Element 2 = B.. Element 27 = AA). How can I properly scan these on input in order to determine if the element exists and if it does put it in a string that converts these id's to values which are later calculated?
I have an id system on a calculator where the user can generate different element (sliders, radio buttons, check boxes) that can be calculated. They all have a numeric id which is the translated into alphabetic characters in a progressive order ( Element 1 = A, Element 2 = B.. Element 27 = AA). I later have an input field where the user can create their own formula that will be calculated and put into a result tab.
Sample Formula: A+B*2
The reason I translate to letter is so that the user can use numbers in creating the formula. I have succeed in making this work for id's that are one letter but as soon as the id's start hitting AA and AB it doesn't work because currently I split this into an array and scan every element for it's value, which becomes problematic for two letters since they split into two different id's.
I have tried splitting the array based on the operators (+, -, *, /) but that removes them from the array.
function resultCalcInit(resultObject, resultFormulaObject) {
$('.createWrap').on('keyup input change', $(resultFormulaObject).find('.jvformbuilder-formula-panel-elements-result-field-formula'), function(e) {
var thisKey = new RegExp(String.fromCharCode(e.which).toLowerCase());
var keyNoRegEx = String.fromCharCode(e.which).toLowerCase();
var counter = 0;
var letters = /^[0-9a-zA-Z]+$/;
for (var call of $('.dropzone').find('.builder-elements')) {
if ($(call).find('.bf-number')[0]) {
var operators = ['»', '½', '/', '¿'];
if (String.fromCharCode(e.which) == $(call).find('.bf-number').attr("data-calcId").toUpperCase() || $.isNumeric(String.fromCharCode(e.which)) || wordInString(String.fromCharCode(e.which), operators)) {
counter++;
} else {}
} else if ($(call).find('.builder-list')[0]) {
var operators = ['»', '½', '/', '¿'];
if (String.fromCharCode(e.which) == $(call).find('.builder-list').attr("data-calcId").toUpperCase() || $.isNumeric(String.fromCharCode(e.which)) || wordInString(String.fromCharCode(e.which), operators)) {
counter++;
} else {}
} else if ($(call).find('.builder-radio')[0]) {
var operators = ['»', '½', '/', '¿'];
if (String.fromCharCode(e.which) == $(call).find('.builder-radio').attr("data-calcId").toUpperCase() || $.isNumeric(String.fromCharCode(e.which)) || wordInString(String.fromCharCode(e.which), operators)) {
counter++;
} else {}
} else if ($(call).find('.builderSlider')[0]) {
var operators = ['»', '½', '/', '¿'];
if (String.fromCharCode(e.which) == $(call).find('.builderSlider').attr("data-calcId").toUpperCase() || $.isNumeric(String.fromCharCode(e.which)) || wordInString(String.fromCharCode(e.which), operators)) {
counter++;
} else {}
} else if ($(call).find('.builder-checkboxes')[0]) {
var operators = ['»', '½', '/', '¿'];
if (String.fromCharCode(e.which) == $(call).find('.builder-checkboxes').attr("data-calcId").toUpperCase() || $.isNumeric(String.fromCharCode(e.which)) || wordInString(String.fromCharCode(e.which), operators)) {
counter++;
} else {}
}
}
if (String.fromCharCode(e.which).match(letters) && counter < 1) {
$(resultFormulaObject).find('.jvformbuilder-formula-panel-elements-result-field-formula').html($(resultFormulaObject).find('.jvformbuilder-formula-panel-elements-result-field-formula').html().replace(thisKey, ""));
var returnString = $(resultFormulaObject).find('.jvformbuilder-formula-panel-elements-result-field-formula').text();
$('#jvformbuilder-formula-panel').find('.jvformbuilder-formula-panel-elements').each(function() {
var formulaResultId = $(this).find('.jvformbuilder-formula-panel-elements-result-field-formula');
$('.builder-elements').each(function() {
if (formulaResultId.attr("id") == $(this).find('.result-number').attr("id")) {
var resultWindow = $(this).find('.result-number');
var formula = returnString.slice(1);
}
});
});
} else {
resultCalc(resultFormulaObject);
}
});
}
Here it check if the letter typed is an existing ID. If it isn't, it's removed. If it is, it stays and proceeds to be scanned for the value.
function resultCalc(resultFormulaObject) {
var returnString = $(resultFormulaObject).find('.jvformbuilder-formula-panel-elements-result-field-formula').text();
$('#jvformbuilder-formula-panel').find('.jvformbuilder-formula-panel-elements').each(function() {
var formulaResultId = $(this).find('.jvformbuilder-formula-panel-elements-result-field-formula');
$('.builder-elements').each(function() {
if (formulaResultId.attr("id") == $(this).find('.result-number').attr("id")) {
var resultWindow = $(this).find('.result-number');
var formula = returnString.slice(1).split("");
var formulaNbr = returnString.slice(1).split("");
var alphabet = ("abcdefghijklmnopqrstuvwxyz").split("");
var calculationArray = returnString.slice(1).split("");
var tempArr = formula;
for (var i = 0; i < formula.length; i++) {
$('.builder-elements').each(function() {
if ($(this).find('.builder-list').attr("data-calcid") == formula[i]) {
formulaNbr[i] = $(this).find('.builder-list').children("option:selected").val();
calculationArray[i] = "parseInt(ID" + alphabet.indexOf(formula[i]) + ").value)";
} else if ($(this).find('.builder-field').attr("data-calcid") == formula[i]) {
if ($(this).find('.bf-text')[0]) {
console.log(tempArr);
if (tempArr.indexOf(tempArr[i]) == 0) {
tempArr.splice(i, 2);
calculationArray.splice(i, 2);
} else {
tempArr.splice(i - 1, 2);
calculationArray.splice(i - 1, 2);
}
var formulaString = "";
for (var j = 0; j < formula.length; j++) {
formulaString += tempArr[j];
}
formulaResultId.empty();
formulaResultId.html("=" + formulaString);
} else if ($(this).find('.bf-telNum')[0]) {
if (tempArr.indexOf(tempArr[i]) == 0) {
tempArr.splice(i, 2);
calculationArray.splice(i, 2);
} else {
tempArr.splice(i - 1, 2);
calculationArray.splice(i - 1, 2);
}
var formulaString = "";
for (var j = 0; j < formula.length; j++) {
formulaString += tempArr[j];
}
formulaResultId.empty();
formulaResultId.html("=" + formulaString);
} else if ($(this).find('.bf-date')[0]) {
if (tempArr.indexOf(tempArr[i]) == 0) {
tempArr.splice(i, 2);
calculationArray.splice(i, 2);
} else {
tempArr.splice(i - 1, 2);
calculationArray.splice(i - 1, 2);
}
var formulaString = "";
for (var j = 0; j < formula.length; j++) {
formulaString += tempArr[j];
}
formulaResultId.empty();
formulaResultId.html("=" + formulaString);
} else if ($(this).find('.bf-number')[0]) {
if (!$(this).find('.bf-number').val()) {
formulaNbr[i] = 0;
} else {
formulaNbr[i] = $(this).find('.bf-number').val();
}
calculationArray[i] = "parseInt(ID" + alphabet.indexOf(formula[i]) + ").value)";
}
} else if ($(this).find('.builder-textarea').attr("data-calcid") == formula[i]) {
if (tempArr.indexOf(tempArr[i]) == 0) {
tempArr.splice(i, 2);
calculationArray.splice(i, 2);
} else {
tempArr.splice(i - 1, 2);
calculationArray.splice(i - 1, 2);
}
var formulaString = "";
for (var j = 0; j < formula.length; j++) {
formulaString += tempArr[j];
}
formulaResultId.empty();
formulaResultId.html("=" + formulaString);
} else if ($(this).find('.builder-radio').attr("data-calcid") == formula[i]) {
var resultRadio = [];
$(this).find('.builder-radio-input').each(function(i) {
resultRadio[i] = parseInt($(this).val());
});
var sum = resultRadio.reduce(add);
formulaNbr[i] = sum;
calculationArray[i] = "parseInt(ID" + alphabet.indexOf(formula[i]) + ").value)";
} else if ($(this).find('.builder-checkboxes').attr("data-calcid") == formula[i]) {
var resultCheck = [];
$(this).find('.builderCB').each(function(i) {
resultCheck[i] = parseInt($(this).val());
});
var sum = resultCheck.reduce(add);
formulaNbr[i] = sum;
calculationArray[i] = "parseInt(ID" + alphabet.indexOf(formula[i]) + ").value)";
} else if ($(this).find('.builderSlider').attr("data-calcid") == formula[i]) {
formulaNbr[i] = $(this).find('.builder-slider').val();
calculationArray[i] = "parseInt(ID" + alphabet.indexOf(formula[i]) + ").value)";
}
});
}
var calculationString = "";
for (var i = 0; i < calculationArray.length; i++) {
calculationString += calculationArray[i];
}
returnString = "";
for (var i = 0; i < formulaNbr.length; i++) {
returnString += formulaNbr[i];
}
if (returnString) {
printRes(returnString, resultWindow, calculationString);
}
}
});
});
}
Here it takes different values from the different objects that relates to the id written inside the formula tab. Later it is printed into the result tab.
function printRes(resString, resArea, calcString) {
resArea.empty();
var result = eval(resString);
if (!result) {
resArea.append(0)
resArea.attr("data-calcForm", "");
} else {
resArea.append(result)
resArea.attr("data-calcForm", calcString);
}
}
It completely crashes if the id becomes doubled. That's where I need you guys to help me. How can I make it scan after double characters id's as well as single ones, and triple ones and how ever many the user decides to generate.
There is no way to reproduce the issue you have from the big code bunch you posted. And I have to admit that what you try to achieve is unclear to me.
But what is really clear is that you need to segregate the formula's elements from the operator. You can achieve this with 2 regexes. I see you already use the first one: /[0-9a-zA-Z]+/, but I don't get how you use it...
Anyway, here is a real simple demo showing that you can have two arrays, one for the formula's elements and the other for the operators. Once you have that, you should be able to use it to do whatever you wish to.
$("button").on("click",function(){
// The input value
var input_val = $("input").val();
// Regexes
var elements_regex = /[0-9a-zA-Z]+/g;
var operators_regex = /[\+\-*\/]/g;
// Create the arrays
var elements_array = input_val.match(elements_regex);
var operators_array = input_val.match(operators_regex);
// Needed just for this demo
var regex_validation = $(".regex_validation");
var elements = $(".elements");
var operators = $(".operators");
// RESULTS
// Regex validation
for(i=0;i<elements_array.length;i++){
// Element
if(typeof(elements_array[i])!="undefined"){
regex_validation.append("<span class='element'>"+elements_array[i]+"<span>");
}
// Operator
if(typeof(operators_array[i])!="undefined"){
regex_validation.append("<span class='operator'>"+operators_array[i]+"<span>");
}
}
// Elements
elements.html(JSON.stringify(elements_array));
// Operators
operators.html(JSON.stringify(operators_array));
});
.result{
height: 50px;
width: 500px;
border: 1px solid black;
}
.element{
background: cyan;
}
.operator{
background: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Enter your formula: <input value="AA+B*2"><button type="button">Check</button><br>
<br>
Regex validation: (cyan for elements, yellow for operators)
<div class="result regex_validation"></div>
<br>
Elements array:
<div class="result elements"></div>
<br>
Operators array:
<div class="result operators"></div>
<br>
CodePen
As a challenge, I am trying to create a JavaScript selection engine i.e. a JavaScript function that will return DOM elements given a CSS selector.
I cant use document.querySelector/document.querySelectorAll.
I am currently creating a object of the parameter, but am now stuck. I now need to loop through every element on the page, and if it matches my tag, or class/id, push that element to an array.
$("div") //Should return 2 DIVs
$("img.some_class") //Should return 1 IMG
$("#some_id") //Should return 1 DIV
$(".some_class") //Should return 1 DIV and 1 IMG
function $ (selector) {
var elements =[];
var pageTags =[];
var all = document.getElementsByTagName("*");
//splits selector
var arg = parse(selector);
function parse(subselector) {
var obj = {tags:[], classes:[], ids:[], attrs:[]};
subselector.split(/(?=\.)|(?=#)|(?=\[)/).forEach(function(token){
switch (token[0]) {
case '#':
obj.ids.push(token.slice(1));
break;
case '.':
obj.classes.push(token.slice(1));
break;
case '[':
obj.attrs.push(token.slice(1,-1).split('='));
break;
default :
obj.tags.push(token);
break;
}
});
return obj;
}
console.log(arg);
for (var item of all) {
//gets tagname of all page elements
var element = item.tagName.toLowerCase();
console.log(element);
//if argument contains DOM element
if (arg.indexOf(element) !== -1) {
var x = document.getElementsByTagName(element);
for (var test of x) {
elements.push(test);
}
}
}
return elements;
}
<html>
<head>
<script src="Answer.js"></script>
<script src="Test.js"></script>
</head>
<body onload="test$()">
<div></div>
<div id="some_id" class="some_class some_other_class"></div>
<img id="some_other_id" class="some_class some_other_class"></img>
<input type="text">
</body>
</html>
Please any help on how to do this will be appreciated.
check this jsfiddle.
There would be many many more combinations of course ...
I limited the test cases to the html example you provided.
function _select(attrValues, tagFilter, cssSel) {
var results = [];
//var value = selector.slice(1);
var all = document.getElementsByTagName(tagFilter);
//look for an id attribute
if (cssSel === '#') {
for (var i = 0; i < all.length; i++) {
if (all[i].id === attrValues) {
results.push(all[i]);
}
}
} else {
if (typeof attrValues === 'string') {
for (var i = 0; i < all.length; i++) {
if (all[i].classList.contains(attrValues)) {
results.push(all[i]);
}
}
} else {
//multiple selector classes
var found = 0;
for (var i = 0; i < all.length; i++) {
for (var j = 0; j < attrValues.length; j++) {
if (all[i].classList.contains(attrValues[j])) {
found += 1;
if (found === attrValues.length) {
results.push(all[i]);
}
}
}
}
}
}
return results;
}
function $(selector) {
var cssSel = selector.charAt(0);
var cssSelectors = ['.', '#'];
if (cssSel === cssSelectors[0] || cssSel === cssSelectors[1]) {
//direct selector
var attrValue = selector.slice(1),
tagFilter = '*';
return _select(attrValue, tagFilter, cssSel)
} else {
for (var i = 0; i < cssSelectors.length; i++) {
var tokens = selector.split(cssSelectors[i]);
if (tokens.length > 1 && tokens[0] !== "") {
//nested selector
var tagFilter = tokens[0], //the first of the array should be the tagname ,because the case of the cssSelector at charAt(0) should have been caught in the if at the beginning.
attrValue = tokens.slice(1); //the rest of the array are selector values
return _select(attrValue, tagFilter, cssSel)
}
}
}
return document.getElementsByTagName(selector);
}
//TEST cases
var results = $("div")
console.log('Should return 2 DIVs')
for ( var e of results){
console.log(e)
}
var results = $(".some_class")
console.log('Should return 1 DIV and 1 IMG')
for ( var e of results){
console.log(e)
}
var results = $("#some_id")
console.log('Should return 1 DIV ')
for ( var e of results){
console.log(e)
}
var results = $("img.some_class")
console.log('Should return 1 IMG')
for ( var e of results){
console.log(e)
}
var results = $("div.some_class.some_other_class")
console.log('Should return 1 div')
for ( var e of results){
console.log(e)
}
I have a JS function which searches for a string in the HTML source, and outputs the parent node:
function searchHTML(searchTerm) {
queue = [document.body],
curr
;
while (curr = queue.pop()) {
if (!curr.textContent.match(searchTerm)) continue;
for (var i = 0; i < curr.childNodes.length; ++i) {
switch (curr.childNodes[i].nodeType) {
case Node.TEXT_NODE : // 3
if (curr.childNodes[i].textContent.match(searchTerm)) {
console.log(curr);
// End of search
}
break;
case Node.ELEMENT_NODE : // 1
queue.push(curr.childNodes[i]);
break;
}
}
}
}
Currently, its output (in Javascript console) is not a string.
I need to perform regex on the output (curr), so I need it to be a string.
What I have tried:
curr = curr.toString()
curr = curr.replace(/[0-9]/g, "")
You can use .text() jQuery function to get the string from an HTML.
Here is an example of how you get string :
text= curr.text();
curr = text.replace(/[0-9]/g, "");
It seems to me you need to find the commonAncestorContainer for the term searched. That means if the term starts in a node and ends in another, you don't really have a clear definition of the common parent, until you get the a range.
I put together the function below where you can call search('My Term') and it should get a commonAncestorContainer. Some tweek should still be needed to search the same term more than once and to make sure that words ending inside an element still consider that element as the parent instead of the next one after the parent.
var search = function (searchTerm) {
// Stop if there is nothing to look for
if (!searchTerm || typeof searchTerm !== 'string')
return null;
searchTerm = searchTerm.toLowerCase();
var bodyText = document.body.textContent.toLowerCase(),
range = document.createRange(),
startOffset = bodyText.indexOf(searchTerm),
endOffset = startOffset + searchTerm.length,
iterationObject = {
index: 0,
length: bodyText.length,
startOffset: startOffset,
endOffset: endOffset,
startInNodeOffset: -1,
endInNodeOffset: -1,
startNode: null,
endNode: null
};
var textContent = function (textNode) {
return textNode.nodeValue || textNode.textContent || textNode.wholeText;
};
(function iterate (node, iterationObject) {
if (node.nodeType === 1) {
var childNodes = node.childNodes;
// Keep iterating but we should try to stop it when nodes are found
for (var i = 0, iLen = childNodes.length; i < iLen; i++)
iterate(childNodes[i], iterationObject);
} else if (node.nodeType === 3) {
var text = textContent(node),
startInNodeOffset,
endInNodeOffset;
// Change index and move on
if (iterationObject.index + text.length < iterationObject.startOffset)
iterationObject.index += text.length;
else if (iterationObject.startNode === null) {
startInNodeOffset = iterationObject.startOffset - iterationObject.index;
// Start range in the current node
// This condition should really only be needed to decide if the selection should start
// before or after this node. But that is another story.
if (startInNodeOffset <= text.length) {
iterationObject.startNode = node;
iterationObject.startInNodeOffset = startInNodeOffset;
}
iterationObject.index += text.length;
} else {
// Now try to find the endNode
if (iterationObject.index + text.length < iterationObject.endOffset)
iterationObject.index += text.length;
else if (iterationObject.endNode === null) {
endInNodeOffset = iterationObject.endOffset - iterationObject.index;
if (endInNodeOffset <= text.length) {
iterationObject.endNode = node;
iterationObject.endInNodeOffset = endInNodeOffset;
}
}
}
}
if (iterationObject.startNode !== null && iterationObject.endNode !== null)
return;
})(document.body, iterationObject);
if (iterationObject.startInNodeOffset > -1 && iterationObject.endInNodeOffset > -1) {
range.setStart(iterationObject.startNode, iterationObject.startInNodeOffset);
range.setEnd(iterationObject.endNode, iterationObject.endInNodeOffset);
return range.commonAncestorContainer;
}
return null;
};
If you are using jQuery, you can try outerHTML to get the string from the commonAncestorContainer.
var parentElement = search('Whatever'),
result = '';
if (parentElement !== null)
result = $(parentElement).outerHTML();
You can create a temporary DOM node, and then append curr to it. Then get the innerHTML and the result will be a string:
var tempNode = document.createElement("div");
tempNode.appendChild(curr);
console.log(temp.innerHTML);
Working example here:
http://codepen.io/anon/pen/QypxwM
Let's have an example:
<table>
<tr class="need"></tr>
<tr class="no-need"></tr> // This is ourElement, needs to be removed
<tr></tr> // This element needs to be removed
<tr class="no-need"></tr> // This element needs to be removed
<tr class="no-need"></tr> // This element needs to be removed
<tr class="need"></tr> // Elements removed until this
</table>
I want to remove those four elements at once.
This is what I've done:
function remove(ourElement) {
var body = ourElement.parentNode,
bodyRows = body.getElementsByTagName('tr');
for (var i = 0; i < bodyRows.length; i++) {
if (bodyRows[i] == ourElement) {
if (!bodyRows[i+1].className) {
body.removeChild(bodyRows[i+1]);
}
}
if (bodyRows[i] > ourElement) {
if (bodyRows[i].className == 'no-need') {
body.removeChild(bodyRows[i]);
}
if (bodyRows[i].className == 'need') {
break;
}
}
}
body.removeChild(ourElement);
}
The function removes only the first empy row after ourElement and the ourElement itself.
As i wrote above, I need to remove those four elements at first run of our function.
Pure Javascript needed.
I just realised you may be looking for a function to delete items inside boundaries lets say:
items between class"need" and class"need" and delete all items inside them. if thats your question the answer is as follows:
function remove( tagElement, boundClass ) {
var tr = document.getElementsByTagName(tagElement),
re = new RegExp("(^|\\s)"+ boundClass +"(\\s|$)"),
bound = false,
r = [];
for( var i=0, len=tr.length; i<len; i++ ) {
if( re.test(tr[i].className) ) {
bound = ( bound === true ) ? false : true;
if(bound) continue;
}
if( bound ) r.push( tr[i] );
}
while( r.length )
r[ r.length - 1 ].parentNode.removeChild( r.pop() );
}
remove( "tr", "need" ); // use it like this
you need something like this:
function remove(ourElement) {
var body = ourElement.parentNode;
var childRows = body.childNodes;
var found = false;
for (var i = 0; i < childRows.length; i++) {
var row = childRows[i];
if(found) {
if(!row.className || row.className == "no-need") {
body.removeChild(row);
i--; // as the number of element is changed
} else if(row.className == "need") {
break;
}
}
if(row == ourElement) {
body.removeChild(ourElement);
found = true;
i--; // as the number of element is changed
}
}
}
You cannot use the < or > operators with DOM elements.
function remove(ourElement) {
var body = ourElement.parentNode,
bodyRows = body.getElementsByTagName('tr'),
lb = false;
for (var i = 0; i < bodyRows.length; i++) {
lb = (lb)?(bodyRows[i] == ourElement):lb;
if(lb){
if (!bodyRows[i].className) {
body.removeChild(bodyRows[i]);
}else if (bodyRows[i].className == 'no-need') {
body.removeChild(bodyRows[i]);
}else if (bodyRows[i].className == 'need') {
break;
}
}
}
}
Try this, every time it removes a child it decreases i to compensate:
function remove(ourElement) {
var body = ourElement.parentNode,
bodyRows = body.getElementsByTagName('tr'),
lb = false;
for (var i = 0; i < bodyRows.length; i++) {
if (!lb && bodyRows[i] != ourElement) {
continue;
} else if(bodyRows[i] == ourElement){
lb = true;
}
if (bodyRows[i].className == 'no-need' || !bodyRows[i].className) {
body.removeChild(bodyRows[i]);
i--;
}
}
}
I used the below code to upload multiple files. Its working absolutely fine but as i need to check that the file which i am uploading is duplicate or not, i am facing one problem in that. I created one function called checkDuplicate for that and calling it inside the function. But the problem is that the for loop is looping double the size of the array. I don't know why it is so. Please kindly help me if anyone has any idea.
Here is the Javascript
<script type="text/javascript">
function MultiSelector(list_target, max) {
this.list_target = list_target;
this.count = 0;
this.id = 0;
if (max) {
this.max = max;
} else {
this.max = -1;
};
this.addElement = function(element) {
if (element.tagName == 'INPUT' && element.type == 'file') {
element.name = 'file_' + this.id++;
element.multi_selector = this;
element.onchange = function() {
var new_element = document.createElement('input');
new_element.type = 'file';
this.parentNode.insertBefore(new_element, this);
this.multi_selector.addElement(new_element);
this.multi_selector.addListRow(this);
this.style.position = 'absolute';
this.style.left = '-1000px';
};
if (this.max != -1 && this.count >= this.max) {
element.disabled = true;
}
;
this.count++;
this.current_element = element;
}
else {
alert('Error: not a file input element');
}
;
};
this.addListRow = function(element) {
var new_row = document.createElement('div');
var new_row_button = document.createElement('img');
new_row_button.setAttribute("src","<%=request.getContextPath()%>/images/deletei.gif");
new_row_button.onclick = function() {
this.parentNode.element.parentNode.removeChild(this.parentNode.element);
this.parentNode.parentNode.removeChild(this.parentNode);
this.parentNode.element.multi_selector.count--;
this.parentNode.element.multi_selector.current_element.disabled = false;
return false;
};
if(checkDuplicate(element)) {
new_row.element = element;
new_row.innerHTML = element.value + " ";
new_row.appendChild(new_row_button);
this.list_target.appendChild(new_row);
}
};
};
function checkDuplicate(element) {
var arr = new Array();
var i = 0,dup=0;
//alert(new_row.element = element.value);
if(dup==0) {
arr[i++] = element.value;
dup=1;
}
alert("Length ==> "+ arr.length);
for ( var j = 0; j < arr.length; j++) {
alert("Name ==> " + arr[j]);
if(arr[j] == element.value && j>=1) {
alert("Duplicate");
} else {
alert("Not Duplicate");
arr[i++] = element.value;
}
}
}
</script>
Here is the HTML
<body>
<!-- This is the form -->
<form enctype="multipart/form-data" action=""method="post">
<input id="my_file_element" type="file" name="file_1">
<input type="submit">
<br/>
<br/>
Files:
<!-- This is where the output will appear -->
<div id="files_list"></div>
</form>
<script>
var multi_selector = new MultiSelector(document
.getElementById('files_list'), 15);
multi_selector.addElement(document.getElementById('my_file_element'));
</script>
</body>
</html>
because you have the arr[i++] = element.value; in the last line, and j < arr.length in the for, so every time the array.lenght gets bigger and bigger.
change the for line to these two lines:
var len = arr.length;
for ( var j = 0; j < len; j++) {