Novice/Beginner Javascript Request - javascript

HTML code:
<td>
<img src="../images/items/333.png"><br>
<b>Product One</b><br>
(2 in stock)<br>
<i>65 USD</i><br>
<form action="shopping.php?shop=1&item=333&price=65&buy=conf&type=" method="post">
<input name="" value="Buy this item" type="submit">
</form></td>
<td>
<img src="../images/items/444.png"><br>
<b>Product Two</b><br>
(4 in stock)<br>
<i>5 USD</i><br>
<form action="shopping.php?shop=1&item=444&price=5&buy=conf&type=" method="post">
<input name="" value="Buy" type="submit">
</form></td>
This is the html code on the page I'm working on, the html code cannot be altered.
There are several td tags on the page which contains the following information you see in the code above.
I would like to write a script that would do something like this:
if (document.body.innerHTML.indexOf("Product One") > -1) {
document.location = "shopping.php?shop=1&item="+itemID+"&price="+USD+"&buy=conf&type="
}
Search the body/td of the page for the "Product Name" specified in my script, and then if it's found, go to the url that contains variables that need to be extracted, itemID and USD.
itemID is extracted from the src of the image.png by taking the numbers. For example, the itemID of ../images/items/444.png is 444.
USD is extracted from the price defined between the italics tags. For example the extracted value for USD for<i>5 USD</i> would be 5.
Catch is
I would need a lot of if (document.body.innerHTML.indexOf("Name") > -1) {document.location = "shopping.php?shop=1&item="+itemID+"&price="+USD+"&buy=conf&type="} to cater to the large number of products I would specify. I might want to specify "Product One to Hundred" and "Sub-product A to Z"
Solution
Some ways I thought of to handle this (needs to be put into javascript code) is to:
Put list of products I will specify into an array (something like) var list = new Array ("Product One","Product Two","Sub-Product A"); and have a function check the page for the presence of any product from this array that displays on the page.
When the product is found, to get the itemID, isolate the numbers before .png and after /items/ from the image src of the product. And to get USD, get the value between the <i> </i> tags and only take the numerical values
To do this I think nextSibling or previousSibing can be used, but I'm not too sure about that.
Alternatively, to make it easier, there could be a function to immediately locate the form's action value and set the window.location since <form action="shopping.php?shop=1&item=444&price=5&buy=conf&type=" method="post">
I've seen this done before using XPath?

This is not difficult using jQuery -- especially if we extend it to search for case-insensitive, regular expressions.
The following script should work with the HTML structure from the question, if it is precisely accurate and not added by AJAX. Note the power that regular expressions give when targeting product descriptions.
You can see the underlying code at work at jsFiddle.
// ==UserScript==
// #name _Auto-follow targeted product links.
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// ==/UserScript==
var targetList = [
"Shoes, pumps",
"Horse shoes",
"(?:Red|Pink|Burgundy)\\s+shoes?"
];
/*--- Extend jQuery with a case-insensitive version of contains().
Also allows regular expressions.
*/
jQuery.extend (
jQuery.expr[':'].containsCI = function (a, i, m) {
//--- The next is faster than jQuery(a).text()...
var sText = (a.textContent || a.innerText || "");
var zRegExp = new RegExp (m[3], 'i');
return zRegExp.test (sText);
}
);
$.each (targetList, function (index, value) {
var jqSelector = 'td > b:containsCI("' + value + '")';
var productFound = $(jqSelector);
if (productFound.length) {
var matchingForm = productFound.first ().nextAll ("form");
if (matchingForm.length) {
alert (productFound.text () );
document.location = matchingForm.attr ("action");
}
}
} );

Here is a solution that does not rely on external libraries like jQuery:
function findProducts(referenceList) {
var productsOnPage = {}, listMatches = {},
tds = document.getElementsByTagName("TD"),
bold, form, i, productName, productUrl;
// build an index of products on the page (HTML scraping)
for (i = 0; i < tds.length; i++) {
bold = tds[i].getElementsByTagName("B")[0];
form = tds[i].getElementsByTagName("FORM")[0];
if (bold && form) {
productName = bold.innerHTML.toLowerCase();
productUrl = form.action;
productsOnPage[productName] = productUrl;
}
}
// match reference list against all available products on the page
for (i = 0; i < referenceList.length; i++) {
productName = referenceList[i].toLowerCase();
productUrl = productsOnPage[productName];
listMatches[productName] = productUrl;
}
return listMatches;
}
Call it:
var availableProducts = findProducts(["Product One","Product Two","Sub-Product A"]);
After that you'd have an object availableProducts that's looking like this:
{
"product one": "shopping.php?shop=1&item=333&price=65&buy=conf&type=",
"product two": "shopping.php?shop=1&item=444&price=5&buy=conf&type=",
"sub-product a": undefined
}
Note that all keys are lower case to make string comparisons consistent. To look up a product you would use
function navigateIfAvailable(productName) {
var url = availableProducts[productName.toLowerCase()];
if (url) document.location = url;
}
Now
navigateIfAvailable("Product Two");
would go somewhere. Or not.

Related

jquery if input contains phrase from array-child friendly global chat

I have found some code for a chat system. I am going to be using it as a child-friendly (so I can't be blamed for anything) global chat. The way the code works is by checking the input to see if it contains any word from an array, if it does then the program will display something to a <ol> tag, for me to see if it works. Otherwise is does nothing.
JQUERY
var banned_words = {
'songs': ['hello', 'sorry', 'blame'],
'music': ['tempo', 'blues', 'rhythm']
};
function contains(words) {
return function(word) {
return (words.indexOf(word) > -1);
};
};
function getTags(input, banned_words) {
var words = input.match(/\w+/g);
return Object.keys(banned_words).reduce(function(tags, classification) {
var keywords = banned_words[classification];
if (words.some(contains(keywords)))
tags.push(classification);
return tags;
}, []);
};
// watch textarea for release of key press
$('#sendie').keyup(function(e) {
$('#tags').empty();
var tags = getTags($(this).val().toLowerCase(), banned_words);
var children = tags.forEach(function(tag) {
$('#tags').append($('<li>').text(tag));
});
if (e.keyCode == 13) {
var text = $(this).val();
var maxLength = $(this).attr("maxlength");
var length = text.length;
// send
if (length <= maxLength + 1) {
chat.send(text, name);
$(this).val("");
} else {
$(this).val(text.substring(0, maxLength));
}
}
});
HTML
<form id="send-message-area">
<p style="text-align:center">Your message: </p>
<input id="sendie" maxlength = '100' />
</form>
<ol id="tags">
</ol>
But, what I'm also wanting to do is check if the input value contains phrases from the array so I can ban phrases that are too sensitive for children. How can I add this in, or is there another more efficient way to check the input?
UPDATE
I have already tried to place the phrase directly into the banned_words (I changed them as this post would get flagged for inappropriate language) and using the hexadecimal character for the space-bar. None of these worked.
You can try either of the following since the space is also a known charachter:
test 1:
Just put your phrase between quotes such as 'cry baby','red apple' etc.
sometimes it does not work, you can try
test 2:
replace the space with the hexidecimal character \x20 such as 'cry\x20baby','red\x20apple'
I hope one or both of these works for you.
I have done some more research and have found a cool plugin for JQuery. It's called jQuery.profanityFilter. It uses a json file filled with sensative words.
Link to github download: https://github.com/ChaseFlorell/jQuery.ProfanityFilter

Get all form values into javascript array

I am attempting to get all the form values into a normal array[]. I had it working for tags but then I added some tags and can't seem to get it.
With just tags it worked with this
var content = document.querySelectorAll("#form input[name='content[]']");
I am currently trying something like this
var content = document.elements["content[]"].value;
This form can change from user input down the road as each section of the form is a module that they choose to add. It is also important to get the values in order, if that isn't possible then I would need to make it a JSON array. Pure javascript or jquery is fine either way.
Thank you for any help.
EDIT
I used this to solve my problem
var contents=[]
var content = $('#form').serializeArray()
for (var i = 0; i < content.length; i++) {
contents[contents.length]=content[i].value
};
Try
html
<form id="form">
<input type="text" name="content[]" value="abc" />
<textarea name="textarea" value="">123</textarea>
</form>
js
$(function() {
var form = $("#form");
// escape `[]`
var content = form.find("input[name=content\\[\\]]");
// array `literal declaration`
var _arr = [content.prop("value")];
// map all form values to single array
var arr = $.map(form.serializeArray(), function(v, k) {
return [v.value]
});
// array literal with `textarea` `value`
var t = [$("textarea").prop("value")];
console.log(_arr, arr, t);
// _arr: `["abc"]` , arr:`["abc", "123"]` t:`["123"]`
})
Demo.
See Arrays

Can you perform certain onload functions from a link on a previous page

I'm not even sure what I'm thinking of will work and can't seem to find the right wording to get and search results that are remotely helpful so here goes.
What I want to be able to do is have a link from one page then cause the linked page to display a certain way. The code below is the script being used on the page I'll be linking to.
$(document).ready(function() {
$('.hideshow').click(function () {
var name = $(this).attr('id').replace("-L","");
if ($(this).hasClass("hidden")) {
$(this).addClass("shown");
$(this).removeClass("hidden");
$('div#' + name).show(500);
} else {
$(this).addClass("hidden");
$(this).removeClass("shown");
$('div#' + name).hide(500);
}
});
});
This code will hide or show content when links on the page are clicked using the id names used in the body of the file. Now what I want to be able to do is have the link from the previous page indicate certain links on this page as being shown. The following is some of the in body code.
<a class="hideshow hidden" id="cat-articles-L" style="cursor:pointer;"><font style="font-size:24px; color:#06F; text-decoration:underline;"> Cat Articles</font></a><br />
<div id="cat-articles" style="display:none;">
<a class="hideshow hidden" id="cat-beds-L" style="cursor:pointer;"><font style="font-size:18px; color:#06F; text-decoration:underline;">Cat Beds</font></a><br />
On default the "Cat Articles" are visible but "Cat Beds" is hidden until "Cat Articles" is clicked, then there could be sublevels so more items under "Cat Beds" The idea is when you link from the other page having it load with certain items already open.
Hope I made this clear enough, still new to this site and posting questions.
Add a parameter to the link on the original page. Something like domain.com/page.html?id=5 and then have javascript check for a QueryString of id and do something like a switch with it.
See How can I get query string values in JavaScript? for how to get QueryStrings if you aren't familiar.
If you need to pass multiple of the same type (example, multiple IDs), you can make an array and pass that array to the other page. In that array, include every id you want to display.
See an example of an array to url here: JavaScript Array to URLencoded
Example (Original Page):
var idArray = new Array(1,5,15,38);
var url = "http://www.blah.com/link.html?"+idArray.join('&');
Example (Linked page):
var qs = (function(a) {
if (a == "") return {};
var b = {};
for (var i = 0; i < a.length; ++i)
{
var p=a[i].split('=');
if (p.length != 2) continue;
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split('&'));
var idArray = qs["id"];
for (var i = 0; i < idArray.length; i++) {
switch(idArray[i]){
case 1:
//show link1
break;
case 2:
//show link3
break;
default:
//do nothing, but required
break;
}
}
Note: It may look that I'm using JQuery, but I'm not. This will work without it just fine.

How can I reduce this Javascript/HTML/jQuery code?

I have hundreds, maybe thousands of charts for stores. The only difference is the name of the store and the product. The HTML code is dynamically generated once/day. Even minified, it takes forever to load (at least it feels like an eternity). If I use Firebug, then loading the file does take a very, very long time to load.
The stores and products are created from a table that's generated each morning. Since each table has a title (e.g., "JohnsMarket"), the ids cannot be reduced to numbers (e.g., 'store1', 'store2').
All of the other SO solutions to repetitive code use numbered ids.
For each store/product, I have to repeat the following 3 snippets.
<div id="JohnsMarket_Soup" class="frmStep">
<div id="JohnsMarket_soup_chart" ></div>
<div class="layout">
<div class="layout_slider-settings">
<div class="loading" id="JohnsMarket_soup_loading"></div>
</div>
<div class="layout_slider"><input id="JohnsMarket_soup_slider" name="area" value="1" ></div>
<div class="layout_slider-settings"> </div>
</div>
</div>
if ( ui.panel.id==='JohnsMarket' )
{
if( typeof JohnsMarket_soup_chart_data === 'undefined' )
{
$('.loading_graph_msg').show();
window.setTimeout(function() { JohnsMarket_soup_data=checkData( JohnsMarket_soup_data,'JohnsMarket' );
JohnsMarket_soup_chart_data = createChart(JohnsMarket_soup_data, 'JohnsMarket_soup_chart', 'JohnsMarket Soup', 50, 7, -1); },50 );
$('.loading_graph_msg').hide('fast');
}
}
});
jQuery('#JohnsMarket_soup_slider').slider({}
$('#JohnsMarket_soup_loading').show();
var x = this.getValue();
window.setTimeout(function() {
JohnsMarket_soup_chart_data.replot();
JohnsMarket_soup_chart_data.destroy();
JohnsMarket_soup_chart_data = createChart(JohnsMarket_soup_data, 'JohnsMarket_soup_chart_data', 'JohnsMarket Soup', 5, x*7, -1);
},20 );
}
});
I can't say I fully understand what your whole problem statement looks like, but you can drastically compress all your code into one function that is used over and over again. This will, at least trim the size of the code down. Since you only showed one example of the data, I can't be sure what exactly is common from one data set to the next, but I made an assumption in order to show you how it can all be procedurized. You could collapse all the code to this:
function checkItem(idStr) {
if ( ui.panel.id == idStr) {
// generate derived names
var soupChartDataName = idStr + "_soup_chart_data";
var soupDataName = idStr + "_soup_data";
var soupChartData = idStr + "_soup_chart_data";
var soupChart = idStr + "_soup_chart";
var soup = idStr + " Soup";
var soupSlider = idStr + "_soup_slider";
var soupLoading = idStr + "_soup_loading";
if (typeof window[soupChartDataName] === 'undefined') {
$('.loading_graph_msg').show();
window.setTimeout(function() {
window[soupDataName] = checkData(window[soupDataName], idStr );
window[soupChartData] = createChart(window[soupChartData], soupChart, soup, 50, 7, -1);
}, 50);
$('.loading_graph_msg').hide('fast');
}
$("#" + soupSlider).slider({});
$("#" + soupLoading).show();
var x = this.getValue();
window.setTimeout(function() {
window[soupChartDataName].replot();
window[soupChartDataName].destroy();
window[soupChartDataName] = createChart(soupDataName, soupChartData, soup, 5, x*7, -1);
}, 20);
}
}
checkItem("JohnsMarket");
Then, for all the other items just call checkItem() with a different idString and no additional code. If I didn't guess the commonality among them quite correctly, you should be able to get the idea for how you can generate all the names being used from one or two common roots. For example, if "soup" isn't common among all the derived names, then maybe you need to pas that root into checkItem too so it can vary from one name to the next. If this were my code, I wouldn't be using so many global variables and I'd hang them off some object in my page, but that's your choice.
Note - for global variables, we access them off the windowobject so we can use the derived variable names as indexes.
And, you could create the HTML from a string template like this:
function createItem(idStr) {
var template = '<div id="xxxx_soup_chart" ></div><div class="layout"><div class="layout_slider-settings"><div class="loading" id="xxxx_soup_loading"></div></div><div class="layout_slider"><input id="xxxx_soup_slider" name="area" value="1" ></div><div class="layout_slider-settings"> </div></div>';
var o = document.createElement("div");
o.id = idStr + "_Soup";
o.className = "frmStep";
o.innerHTML = template.replace(/xxxx/g, idStr);
document.body.append(o); // change this to append the item wherever it's supposed to go
}
createItem("JohnsMarket");
Any of that data seems like it could be stored in a hash keyed on the store name, including the chart itself; the rest is just string concatenation. But I agree, I'd try to move some of that onto the server side, even if it's just to retrieve the data used to create the charts.

Looping through array and display results using JavaScript?

I've got a simple array that I want to loop through and search for whatever a user has typed into a text box. Here is what I have got. Bare in mind I am very new to JavaScript:
function recipeInfo(name, ingredients, url) {
this.name = name;
this.ingredients = ingredients;
this.url = url;
}
var vIngredients = new Array();
vIngredients[0] = new recipeInfo("Ackee Pasta", "ackee", "ackpast.html");
vIngredients[1] = new recipeInfo("Ackee and Saltfish", "ackee saltfish", "acksalt.html");
vIngredients[2] = new recipeInfo("Jerk Chicken", "jerk", "jerkchick.html");
// do the lookup
function getData(form) {
// make a copy of the text box contents
var inputText = form.Input.value
// loop through all entries of vIngredients array
for (var i = 0; i < vIngredients.length; i++) {
var list = $("#search-results");
// compare results
if (inputText == vIngredients[i].ingredients) {
console.log(vIngredients[i].name);
//add to the list the search result plus list item tags
list.append (
$("<li class='arrow'><a href='#' >" + vIngredients[i].name + "</a></li>" )
);
}
else {
// advise user
var list = $("#search-results");
// empty list then tell user nothing is found
list.empty();
list.append (
$("<li>No matches found for '" + inputText + "'</li>")
);
}
}
}
</script>
<form name="search" id="search" action="">
<ul class="rounded">
<li><input type="search" name="Input" placeholder="Search..." onkeydown="if (event.keyCode == 13) getData(this.form)"></li>
</ul>
<ul class="edgetoedge" id="results">
<li class="sep">Results</li>
</ul>
<ul class="edgetoedge" id="search-results">
</ul>
</form>
Here are the problems I'm having:
My search only looks for exact matches. In my example, the "ingredients" property will have more than 1 word in it, so I want to be able to search for any of those words instead of exactly what is in the array
If someone searches, the list just keeps appending to the existing list. How can I erase the contents of the before every search?
Lastly, my feedback for the user if no match is found always is shown instead of results, regardless if there are results or not. Commenting that section out makes the search work as normal but alas without the feedback if there is no match.
Thanks!
For #1, you want to see if the text in array slot contains the typed word as a substring. Do it like this:
// compare results
if (vIngredients[i].ingredients.indexOf(inputText) != -1) {
For #2, list.empty() should do it. You have that in your "else" block for the case when no results were found.
For #3 how do you know that results are actually being found? Does "inputText == vIngredients[i].ingredients" ever evaluate to "true"? Does console.log(vIngredients[i].name); log as you'd expect it to?
If you're new to javascript, you may not know about breakpoint debuggers in various browser developer tools. These are invaluable .

Categories

Resources