Looping through divs and highlighting text - javascript

I am creating a mock blog where I will be appending the posts via the JavaScript file. I currently have it set up so that a search button will work to only show posts with the same text in the search bar. Now, I want the posts to have the found word highlighted.
HTML:
<div id= "custom_blog_div"></div>
JS:
if (document.getElementById("custom_blog_div")) {
//Blog Post 2
var post_2_div = document.createElement("div");
post_2_div.setAttribute("id", "post_2_div");
post_2_div.setAttribute("class", "post_div");
custom_blog_div.appendChild(post_2_div);
// Header
var post_2_Header = document.createElement("h2");
var post_2_Header_Text = document.createTextNode("Welcome, and Pardon the Construction!");
post_2_Header.setAttribute("class", "blog_post_header");
post_2_Header.appendChild(post_2_Header_Text);
post_2_div.appendChild(post_2_Header);
// Date
var post_2_Date = document.createElement("p");
var post_2_Date_Text = document.createTextNode("January 2, 2018 12:00 am");
post_2_Date.setAttribute("class", "blog_post_date");
post_2_Date.appendChild(post_2_Date_Text);
post_2_div.appendChild(post_2_Date);
// Blog
var post_2_Blog = document.createElement("p");
var post_2_Blog_Text = document.createTextNode("This is a Left Image:");
var post_2_Blog_Image_1 = document.createElement("img");
post_2_Blog.setAttribute("class", "blog_post_text");
post_2_Blog_Image_1.setAttribute("class", "Left_Image");
post_2_Blog_Image_1.setAttribute("width", "100px");
post_2_Blog_Image_1.setAttribute("src", "./series images/main series/spirit legends issue 5/Spirit Legends 5 - Cover.jpg")
post_2_Blog.appendChild(post_2_Blog_Text);
post_2_Blog.appendChild(post_2_Blog_Image_1);
post_2_div.appendChild(post_2_Blog);
// Blog Post 1
var post_1_div = document.createElement("div");
post_1_div.setAttribute("id", "post_1_div");
post_1_div.setAttribute("class", "post_div");
custom_blog_div.appendChild(post_1_div);
// Header
var post_1_Header = document.createElement("h2");
var post_1_Header_Text = document.createTextNode("Welcome, and Pardon the Construction!");
post_1_Header.setAttribute("class", "blog_post_header");
post_1_Header.appendChild(post_1_Header_Text);
post_1_div.appendChild(post_1_Header);
// Date
var post_1_Date = document.createElement("p");
var post_1_Date_Text = document.createTextNode("January 2, 2018 12:00 am");
post_1_Date.setAttribute("class", "blog_post_date");
post_1_Date.appendChild(post_1_Date_Text);
post_1_div.appendChild(post_1_Date);
// Blog
var post_1_Blog = document.createElement("p");
var post_1_Blog_Text = document.createTextNode("Hi, and welcome to the official Spirit Legends website! The site is live in order to test out certain things, but as you can see, it is very much incomplete. Please look forward to the complete site in the future!");
post_1_Blog.setAttribute("class", "blog_post_text");
post_1_Blog.appendChild(post_1_Blog_Text);
post_1_div.appendChild(post_1_Blog);
}
// Search Bar button
document.getElementById("search_news_button").onclick = function() {
var all_blogs = document.getElementById("custom_blog_div").querySelectorAll(".post_div");
var text_field = document.getElementById("search_news_button_text").value.toLowerCase();
var custom_blog = document.getElementById("custom_blog_div");
// Restore all Blog Posts before searching
for (i = 0; i < all_blogs.length; i++) {
if (all_blogs[i].style.display === "none") {
all_blogs[i].style.display = "inline";
}
}
// Loop through all Blog posts
for (i = 0; i < all_blogs.length; i++) {
// Display all Blog posts containing the text in the Search Bar
if (all_blogs[i].innerText.toLowerCase().includes(text_field) === true) {
all_blogs[i].style.display = "inline";
var x = "";
for (x = 0; x < custom_blog.innerText.length; x++) {
if (custom_blog[x].innerText.toLowerCase().includes(text_field) === true) {
x = custom_blog[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
// Highlight the found text in each blog post
var x = "";
for (x = 0; x < custom_blog.innerText.length; x++) {
if (custom_blog[x].innerText.toLowerCase().includes(text_field) === true) {
x = custom_blog[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
// Otherwise, if no Blog posts contain the text in the Search Bar or if Search Bar is empty, display the default
} else {
all_blogs[i].style.display = "none";
}
}
}
So, like I said, the blog is working, and the search button is working, but I cannot figure out how to get the searched word highlighted. Currently, this code results in the console telling me "TypeError: custom_blog[x] is undefined".
And, if it helps, the website is http://spiritlegendsofficial.com/ but this feature hasn't been added yet. Although you can look at the rest of the site's code on there and get some context for this mock blog.
Thanks!

Assuming custom_blog is an HTMLElement type, custom_blog[0] would represent the first child node of that HTMLElement. If you check that your variable custom_blog is defined in a javascript console, but custom_blog[x] isn't defined, it basically means your <div id= "custom_blog_div"></div> has no child elements.
I think your issue is somewhere in the loop that's grabbing your text for highlighting. You're checking the length of the string, but inside the loop you're attempting to target a child node in a case where there may not be one. You might want to change the for loop's condition for continuing to be based on the number of nodes instead:
if (custom_blog.hasChildNodes()) {
var children = custom_blog.childNodes;
for (x = 0; x < children.length; x++) {
if (children[x].innerText.toLowerCase().includes(text_field) === true) {
x = children[x].innerText.toLowerCase();
x.style.backgroundColor = "yellow";
}
}
}
For more info on childNodes: https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes

Related

Can I Use Google Apps Script to Get the List Preset From One Paragraph and Apply it to Another in Google Slides

I'm trying to write some code in apps script to pull text from a text box in google slides and split it by paragraphs into new text boxes and I'm hitting a snag when I get to preserving lists. I haven't been successful in finding a simple way to get the listPreset from the paragraphs in the original text box to the paragraphs in their own text boxes.
I was able to use ListStyle() methods getGlyph() and isInList() successfully but unless I make a dictionary of which listPreset each glyph is in, I don't seem to able to retrieve the listPreset with any of the listed methods which I would need in order to fill into applyListPreset().
I'd love a getListPreset() function so I could just nab that from the original list. Is there something like that I'm missing?
Here is an example "before" condition.
Here is an example of the expected "after" condition.
Here is an example of what the "after" condition is when I am unable to duplicate the listStyle from the original text box into the new text boxes.
In the following example I copy the text from the original textbox and gather various attributes from it. I attempt to input the listStyle() information into the applyListPreset() method even though I know that's wrong. I just don't know how else to get the List Preset from the original text box.
FYI I've already had a bit of help with this already so it's not all my work.
function myFunction() { // get slides in the presentation
var slides = SlidesApp.getActivePresentation().getSlides();
var numberOfLogs = 5;
for (let slide of slides) { // get the objects on each slide
splitParagraphs(slide);
}
}
function splitParagraphs(slide){
slideShapes = slide.getShapes();
for(let shape of slideShapes){
var shapetype = shape.getShapeType();
if (shapetype == "TEXT_BOX"){ // checks to see if the object is a text box
createSplitShapes(shape, slide);
shape.remove();
}
}
}
function createSplitShapes(shape, slide){
var paragraphs = shape.getText().getParagraphs();
var oldHeight = shape.getHeight();
var width = shape.getWidth();
var newShapeHeight = oldHeight / paragraphs.length;
for (let [index, paragraph] of paragraphs.entries() ){ // make a textbox for each paragraph distributed vertically over the original textbox
createParagraphShapes(shape, index, paragraph, newShapeHeight, width, slide);
}
}
function createParagraphShapes(shape, index, paragraph, shapeheight, width, slide){
var text = paragraph.getRange();
var list = text.getListStyle().isInList();
var style = text.getListStyle();
var glyph = text.getListStyle().getGlyph();
var rawText = text.asString();
var textStyle = text.getTextStyle();
var fontsize = textStyle.getFontSize();
var fontfamily = textStyle.getFontFamily();
var fontweight = textStyle.getFontWeight();
var paragraphStyle = text.getParagraphStyle();
var alignment = paragraphStyle.getParagraphAlignment();
var lineSpacing = paragraphStyle.getLineSpacing();
var indent = paragraphStyle.getIndentStart();
var shapetop = shapeheight * index + shape.getTop();
if ( ! isBlank(rawText) ) {
var t = slide.insertTextBox(rawText);
t.setLeft(shape.getLeft());
t.setTop(shapetop);
t.setWidth(width);
var newTextStyle = t.getText().getTextStyle();
newTextStyle.setFontSize(fontsize);
newTextStyle.setFontFamilyAndWeight(fontfamily, fontweight);
var newParagraphStyle = t.getText().getParagraphStyle();
newParagraphStyle.setParagraphAlignment(alignment);
newParagraphStyle.setLineSpacing(lineSpacing);
newParagraphStyle.setIndentStart(indent);
if (list = true) {
t.getText().getListStyle().applyListPreset(style);
}
}
}
function paragraphLogs(paragraph, numberOfLogs){
if(numberOfLogs > 0){
console.log("\tWhat's in paragraphs?: ");
for (var k = 0; k < paragraph.length; k++){
console.log("\t\t" + ( paragraphs[k].getRange().asString() ) );
}
}
}
function isBlank(str){
return (!str || str.trim().length === 0);
}

Illustrator Script All Text Properties

Currently working a script to make ALL the texts of a document with some specifics. Glad to say it's already functioning but not completely because it's just working on some of the textframes and not all of them.
The intention is to make the changes on every texts on the active document (point, area, frames, etc) and unfortunately, even when it works on some text frame, not all characters are affected because some special ones like - or + don't get the properties of the other normal characters.
Made some research and do believe I should be working with parentStory maybe? But I didn't figure out how to implement.
Here is my code:
var document = app.activeDocument;
var allTexts = document.textFrames[0];
for (i=0; i<allTexts.words.length; i++) {
allTexts.words[i].characterAttributes.autoLeading = true;
allTexts.words[i].characterAttributes.tracking = 250;
allTexts.words[i].characterAttributes.kerningMethod = AutoKernType.AUTO;
allTexts.words[i].characterAttributes.underline = false;
allTexts.words[i].characterAttributes.strikeThrough = false;
allTexts.words[i].characterAttributes.capitalization = FontCapsOption.NORMALCAPS;
allTexts.words[i].characterAttributes.language = LanguageType.UKENGLISH;
allTexts.words[i].characterAttributes.horizontalScale = 100;
allTexts.words[i].characterAttributes.verticalScale = 100;
allTexts.words[i].characterAttributes.baselineShift = 0;
allTexts.words[i].characterAttributes.rotation = 0;
allTexts.words[i].characterAttributes.baselinePosition = FontBaselineOption.NORMALBASELINE;
allTexts.words[i].characterAttributes.baselineDirection = BaselineDirectionType.Standard;
allTexts.words[i].characterAttributes.alternateGlyphs = AlternateGlyphsForm.DEFAULTFORM;
allTexts.words[i].characterAttributes.antialias = TextAntialias.SHARP;
}
already got helped in a different source by adding textRange to it.
var thisTextFrame;
for(var i = 0; i < app.activeDocument.textFrames.length; i++){
thisTextFrame = app.activeDocument.textFrames[i]
thisTextFrame.textRange.characterAttributes.tracking = 250;
// ...
}

Using a user selected choice from a drop-down to populate a text field in Google Forms

I am creating a Judging Form for a research competition and I am trying to use Google Forms to do so. What I am attempting to do is have a drop down list the Research Poster Numbers and have then have the user selected choice from the drop down fill text field for the poster title. I will be pulling the both the Poster Number and Title from an existing spreadsheet.
var caseScoreForm = FormApp.openById('FormTitle');
var scoreSheet = SpreadsheetApp.openById('SpreadSheetName');
var lastRow = scoreSheet.getLastRow();
function fillposterNumbersDropDown(posterNumberRange) {
var posterNumber = caseScoreForm.addListItem();
var posterNumberValue = "";
var posterNumberLog = "";
var posterNumberArr = [];
var posterNumberRange = scoreSheet.getRange('Score Sheet!A2:' + lastRow).getValues();
// loads the posterNumber array
for (var i = 0; i < posterNumberRange.length; i++) {
posterNumberValue = posterNumberRange[i][0];
Logger.log(posterNumberValue);
posterNumberLog = posterNumber.createChoice(posterNumberValue);
posterNumberArr.push(posterNumberLog);
}
posterNumber.setTitle('Poster Number:').setChoices(posterNumberArr).setRequired(true);
}
function setPosterTitleTextResponce(posterTitleRange) {
var posterTitleRange = scoreSheet.getRange('Score Sheet!B2:' + lastRow).getValues();
var posterTitle = caseScoreForm.addTextItem();
var posterTitleValue = "";
var posterTitleLog = "";
var posterTitleArr = [];
var posterNumberIndex = null;
var posterNumberChoices = FormApp.getActiveForm().getItems(FormApp.ItemType.LIST)[1].asListItem().getChoices();
var userChoice = getUserChoice();
//get the users choice index from the posterNumber dropdown
if (userChoice != null) {
for (var i = 0; i < posterNumberChoices.length; i++) {
if (userChoice == posterNumberChoices[i]) { // need getUserChoice();
posterNumberIndex = i;
break;
}
}
}
//loads the posterTitle array
for (var i = 0; i < posterTitleRange.length; i++) {
posterTitleValue = posterTitleRange[i][0];
posterTitleLog = Logger.log(posterTitleValue);
posterTitleArr.push(posterTitleLog);
}
//print out the posterTitle using the posteNumbers index
posterTitle.setTitle('Poster Title:').setRequired(true); // need way to wright to textfield
}
I think all I have left to do is just get the users choice for the active form and print it to the poster Title text field. I know there is the Get pre-filled URL link in Google forms, but we are projecting about 200 entrees for this competition.
If any one has any help/tip/suggestions or have any alternatives, please let me know.

How can I search an HTML table for only an exact match of my input in the search bar?

I am currently using the code below to create a single-column search for an HTML table on a website. At the moment, when I type something in to the search bar, the code returns every row that has content that contains the thing I searched for anywhere within it. For example (I'm using this for movie ratings), when I type "G" in to the search bar, I get back everything rated G, but also everything rated PG or PG-13. Is there a way that I can adapt this code to return only results that are exact matches for my search? In other words, is there a way to change things so that when I search for "G" (or "g"), I only get back my G-rated movies and not anything rated PG or PG-13?
Thank you!
The Current Code:
<script type="text/javascript">
function searchRows(tblId) {
var tbl = document.getElementById(tblId);
var headRow = tbl.rows[0];
var arrayOfHTxt = new Array();
var arrayOfHtxtCellIndex = new Array();
for (var v = 0; v < headRow.cells.length; v++) {
if (headRow.cells[v].getElementsByTagName('input')[0]) {
var Htxtbox = headRow.cells[v].getElementsByTagName('input')[0];
if (Htxtbox.value.replace(/^\s+|\s+$/g, '') != '') {
arrayOfHTxt.push(Htxtbox.value.replace(/^\s+|\s+$/g, ''));
arrayOfHtxtCellIndex.push(v);
}
}
}
for (var i = 1; i < tbl.rows.length; i++) {
tbl.rows[i].style.display = 'table-row';
for (var v = 0; v < arrayOfHTxt.length; v++) {
var CurCell = tbl.rows[i].cells[arrayOfHtxtCellIndex[v]];
var CurCont = CurCell.innerHTML.replace(/<[^>]+>/g, "");
var reg = new RegExp(arrayOfHTxt[v] + ".*", "i");
if (CurCont.match(reg) == null) {
tbl.rows[i].style.display = 'none';
}
}
}
}
</script>
firstly use toUpperCase()
then you can just use === if you only want to distinguish G, PG, PG-13, R, NC-17, you dont

Using labels like HTML5 placeholder

I am trying to use <label> elements in my html contact form like the HTML5 placeholder attribute for inputs. I have written the following JavaScript to to act as a reusable function witch will provide the following functionality.
Find the input by name.
Get the value of the input.
Find the label belonging to the input.
Change the label style depending on the state of the input.
Change the label style depending on the value of the input.
However it is not working and I don't know why as no errors appear in the console. What am I doing wrong? here is a JS Fiddle with code
function placeholder(field_name) {
// Get the input box with field_name
// Then get input value
var box = document.getElementsByName(field_name);
var i;
for (i = 0; i < box.length; i++) {
var value = document.getElementById(box[i].value);
}
// Get the labels belonging to each box using the HTML for attribute
var labels = document.getElementsByTagName('LABEL');
for (i = 0; i < labels.length; i++) {
if (labels[i].htmlFor !== '') {
var elem = document.getElementById(labels[i].htmlFor);
if (elem) {
box.label = labels[i];
}
}
}
// Colors
var focusColor = "#D5D5D5";
var blurColor = "#B3B3B3";
// If no text is in the box then show the label grey color
box.onblur = function () {
box.label.style.color = blurColor;
};
// If input focuses change label color to light grey
box.onfocus = function () {
box.label.style.color = focusColor;
};
// If there is text in the box then hide the label
if (box.value !== "") {
// Quick do something, hide!
box.label.style.color = "transparent";
}
}
// Call the function passing field names as parameters
placeholder(document.getElementsByName("email"));
placeholder(document.getElementsByName("firstName"));
placeholder(document.getElementsByName("lastName"));
This might be considered a little overkill on the number of listeners I've used, feel free to remove any you think unnecessary, but I've tried to employ your HTML structure as you have it and give you all desired effects. It should work for either the <label>s for matching the <input>s id OR matching it's <name> (given no id matches). I'll always say prefer using an id over name. I believe this JavaScript should also work in all browsers too, except the addEventListener for which you'd need a shim for old IE versions (let me know if it doesn't in one/the error message).
Demo
var focusColor = "#D5D5D5", blurColor = "#B3B3B3";
function placeholder(fieldName) {
var named = document.getElementsByName(fieldName), i;
for (i = 0; i < named.length; ++i) { // loop over all elements with this name
(function (n) { // catch in scope
var labels = [], tmp, j, fn, focus, blur;
if ('labels' in n && n.labels.length > 0) labels = n.labels; // if labels provided by browser use it
else { // get labels from form, filter to ones we want
tmp = n.form.getElementsByTagName('label');
for (j = 0;j < tmp.length; ++j) {
if (tmp[j].htmlFor === fieldName) {
labels.push(tmp[j]);
}
}
}
for (j = 0; j < labels.length; ++j) { // loop over each label
(function (label) { // catch label in scope
fn = function () {
if (this.value === '') {
label.style.visibility = 'visible';
} else {
label.style.visibility = 'hidden';
}
};
focus = function () {
label.style.color = focusColor;
};
blur = function () {
label.style.color = blurColor;
};
}(labels[j]));
n.addEventListener('click', fn); // add to relevant listeners
n.addEventListener('keydown', fn);
n.addEventListener('keypress', fn);
n.addEventListener('keyup', fn);
n.addEventListener('focus', fn);
n.addEventListener('focus', focus);
n.addEventListener('blur', fn);
n.addEventListener('blur', blur);
}
}(named[i]));
}
};
placeholder("email"); // just pass the name attribute
placeholder("firstName");
placeholder("lastName");
http://jsfiddle.net/cCxjk/5/
var inputs = document.getElementsByTagName('input');
var old_ele = '';
var old_label ='';
function hide_label(ele){
var id_of_input = ele.target.id;
var label = document.getElementById(id_of_input + '-placeholder');
if(ele.target == document.activeElement){
label.style.display = 'none';
}
if (old_ele.value == '' && old_ele != document.activeElement){
old_label.style.display = 'inline';
}
old_ele = ele.target;
old_label = label;
}
for(var i = 0; i < inputs.length; i++){
inputs[i].addEventListener('click', hide_label);
}
I will point out a couple things, you will have to find away around the fact that the label is inside the input so users now can't click on half of the input and actually have the input gain focus.
Also I guess you want to do this in IE (otherwise I would strongly advise using the html5 placeholder!) which means you would need to change the ele.target to ele.srcElement.

Categories