How to wrap a class around the first half of a headline? - javascript

I'm trying to wrap a class around the first or the second half of a headline so that I could create more dynamic and cool headlines with jQuery.
In theory I want to find all of the spaces in the sentence and divide it into two. If the headline contains an uneven number of words the script should detect that and also add the class to the nearest word.

This is an interesting problem. I would approach with the handy javascript splice method. Splice can be used to insert and delete items of an array. I'd recommend opening up an inspector and trying out some of the examples I've written below.
First we'll use jQuery to select the header then manipulate the html content string. I'm assuming that the specific header you want to manipulate will have a class and I've substituted 'dynamic':
var header = $("h1.dynamic").text();
=> "Header with some other stuff"
var header_as_array = header.split(" ")
=> ["Header", "with", "some", "other", "stuff"]
var first_half = header_as_array.splice(0, header_as_array.length/2)
Keep in mind that splice changes the original array, so at this point:
first_half = ["Header", "with"]
header_as_array = ["some", "other", "stuff"]
Now, you can join them back together and wrap them with spans like so:
var first = '<span class="first_half">'+first_half.join(" ")+'</span>';
var second = '<span class="second_half">'+header_as_array.join(" ")+'</span>';
var finished = first+" "+second;
Finally, we'll put our finished string back into the header with jQuery:
$("h1.dynamic").html(finished);
The way I've written it a header with an odd number of words will always have the second half as the longer half. If you would prefer it the other way around you could do this:
var splice_location = Math.ceil(test_as_array.length/2);
var first_half = header_as_array.splice(0, splice_location);
By default a non-integer value will be truncated, but here we are using the ceiling function to round things up instead of down.

Nice one #lashleigh. You can have a look at a working example here:
http://jsfiddle.net/johnhunter/KRJdm/
#Tony, I've implemented what you are after as a jquery plugin. You call it on the header you want formatted:
$(function() {
$('h1').splitWords();
});
...and it will produce html output like this:
Before:
<h1>This is a long headline</h1>
After:
<h1>
<span class="wrap-1">This is </span>
<span class="wrap-2">a long headline </span>
</h1>
UPDATED:
Not part of the original question but I have updated the example to allow you to specify at which word the wrapping occurs. If you provide an index argument it will use that offset on the list of words (minus values count back from the end). e.g:
$('h1.a').splitWords(); // Split these words equally
$('h1.b').splitWords(1); // Split these after the first word
$('h1.c').splitWords(-2); // Split these after the second last word
http://jsfiddle.net/johnhunter/KRJdm/

Try the following
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="jquery-1.5.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var headlineText = $('h1.mainHeader').text();
var headlineWords = headlineText.split(' ');
var headlineLength = headlineWords.length;
var headlineMidPoint = (headlineLength / 2) + 1;
var headlineFirstHalfText = headlineWords.slice(0, headlineMidPoint).join(' ') + ' ';
var headlineSecondHalfText = headlineWords.slice(headlineMidPoint).join(' ');
var d = document;
var headlineFirstHalf = $(d.createElement('span')).addClass('headlineHead').text(headlineFirstHalfText);
var headlineSecondHalf = $(d.createElement('span')).addClass('headlineTail').text(headlineSecondHalfText);
var headline = $(d.createElement('h1')).addClass('mainHeader').append(headlineFirstHalf).append(headlineSecondHalf);
$('h1.mainheader').replaceWith(headline);
});
</script>
<style type="text/css">
h1 { font-size:18px;}
span.headlineTail {font-size:1.2em;}
</style>
</head>
<body>
<h1 class="mainHeader">This is a dynamic headline</h1>
<p>Lorem ipsum dolor sit amet, consectetur...</p>
</body>
</html>

lashleigh's answer is great, however, I would challenge the premise that jQuery is the best choice of technology for achieving this effect. I would be inclined to suggest doing the same server-side. Phrasing the markup using PHP, Python or whatever language you are using and then caching the output with the inserted class. Saves on page weight and means the user's browser doesn't have to calculate everything when each a page is loaded. A significant benefit on light clients such as mobile devices.
Here is an example in PHP.
<?php
$headline = "This is a headline of epic proportions";
$split = explode(' ', $headline);
$a = array_slice($split, 0, (count($split)/2));
$b = array_slice($split, (count($split)/2));
$headline = '<span class="whatever">'. join(' ', $a) . '</span>' . join(' ', $b);
print $headline;
?>

Related

Build hyperlink using value in array in javascript

I'd like to display hyperlinks in my page template based on values in an array.
If the page contains a certain value, I'd like to insert the corresponding hyperlink.
From another question, I've managed to cobble together a script that displays a link when a value is found in a string:
<style>
#viewSchoolLink
{display: none;}
</style>
<div id="schoolName">University of Houston</div>
<div id="viewSchoolLink">View on Some Link</div>
<script type="text/javascript">
var div = document.getElementById("schoolName");
var text = div.innerHTML;
if (text.indexOf("University of Houston") >= 0) {
// if so set display to block.
document.getElementById("viewSchoolLink").style.display = "block";
}
</script>
The thing is, I have like 80-90 schools in my list. I suppose I could create 80-90 separate divs with their own unique links, but I imagine there is a much more efficient way to do it. I have an array I've set up as follows:
const schoolLink = {
"University of Houston": "https://www.somelink.com/widget=4379",
"Vanderbilt University" : "https://www.somelink.com/widget=2537",
"University of Dundee": "https://www.somelink.com/widget=2845",
}
Is there a way I can loop through the array to find a match in the key and then insert the value from the array as a hyperlink?
<script type="text/javascript">
var div = document.getElementById("schoolName");
var text = div.innerHTML;
if (text.indexOf("key in array") >= 0) {
// if so display div and use value from the array as hyperlink
}
</script>
Or, since the only part of the link URL that is unique is the widget number, could I set up my array like this:
const schoolLink = {
"University of Houston": 4379,
"Vanderbilt University" : 2537,
"University of Dundee": 2845,
}
and then just build the URL based on the value in the array:
var part = value in array
var link = ''View on Some Link ';
to insert any of the HTML using Javascript we assign in the following manner:
var div = document.getElementById("schoolName")
div.innerHTML = "<a href='https://www.somelink.com/widget=value in array'/>"
if you want to enter the dynamic data in the place of "value in array", then:
div.innerHTML = `<a href="https://www.somelink.com/widget=${variable}"/>`

Insert span in a dom element without overwrite child nodes?

I have an HTML article with some annotations that I retrieve with SPARQL queries. These annotations refer to some text in the document, and I have to highlight this text (wrapping it in a span).
I had already asked how to wrap text in a span, but now I have a more specific problem that I do not know how to solve.
The code I wrote was:
var currentText = $("#"+v[4]["element"]+"").text();
var newText = currentText.substring(0, v[5]["start"]) + "<span class=' annotation' >" + currentText.substring(v[5]["start"], v[6]["end"]) + "</span>" + currentText.substring(v[6]["end"], currentText.length);
$("#"+v[4]["element"]+"").html(newText);
Where:
v[4]["element"] is the id of the parent element of the annotation
v[5]["start"] is the position of the first character of the annotation
v[6]["end"] is the position of the last character of the annoation
Note that start and end don't consider html tags.
In fact my mistake consists in extracting data from the node with the text() method (to be able to go back to the correct position of the annotation) and put back with the html() method; but in this manner if parent node has children nodes, they will be lost and overwritten by simple text.
Example:
having an annotation on '2003'
<p class="metadata-entry" id="k673f4141ea127b">
<span class="generated" id="bcf5791f3bcca26">Publication date (<span class="data" id="caa7b9266191929">collection</span>): </span>
2003
</p>
It becomes:
<p class="metadata-entry" id="k673f4141ea127b">
Publication date (collection):
<span class="annotation">2003</span>
</p>
I think I should work with nodes instead of simply extract and rewrite the content, but I don't know how to identify the exact point where to insert the annotation without considering html tags and without eliminating child elements.
I read something about the jQuery .contents() method, but I didn't figure out how to use it in my code.
Can anyone help me with this issue? Thank you
EDIT: Added php code to extract body of the page.
function get_doc_body(){
if (isset ($_GET ["doc_url"])) {
$doc_url = $_GET ["doc_url"];
$doc_name = $_GET ["doc_name"];
$doc = new DOMDocument;
$mock_doc = new DOMDocument;
$doc->loadHTML(file_get_contents($doc_url.'/'.$doc_name));
$doc_body = $doc->getElementsByTagName('body')->item(0);
foreach ($doc_body->childNodes as $child){
$mock_doc->appendChild($mock_doc->importNode($child, true));
}
$doc_html = $mock_doc->saveHTML();
$doc_html = str_replace ('src="images','src="'.$doc_url.'/images',$doc_html);
echo($doc_html);
}
}
Instead of doing all these, you can either use $(el).append() or $(el).prepend() for inserting the <span> tag!
$("#k673f4141ea127b").append('<span class="annotation">2003</span>');
Or, If I understand correctly, you wanna wrap the final 2003 with a span.annotation right? If that's the case, you can do:
$("#k673f4141ea127b").contents().eq(1).wrap('<span class="annotation" />');
Fiddle:
$(document).ready(function() {
$("#k673f4141ea127b").contents().eq(1).wrap('<span class="annotation" />');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p class="metadata-entry" id="k673f4141ea127b">
<span class="generated" id="bcf5791f3bcca26">Publication date (<span class="data" id="caa7b9266191929">collection</span>): </span>
2003
</p>
At the end my solution is in this Fiddle.
Generalizing:
var element = document.getElementById(id);
var totalText = element.textContent;
var toFindText = totalText.substring(start,end);
var toReplaceText = "<span class='annotation'>"+toFindText+"</span>";
element.innerHTML = element.innerHTML.replace(toFindText, toReplaceText);
Hope it could help someone else.
Note: This don't check if two or more annotations refers to the same node, I'm working on it right now.

Adding tags to HTML using javascript

I have HTML produced from XSLT that looks like:
<span id="text">It's like what Sir Ian McKellan told me the day I sold my boat to Karl Lagerfeld: <span id="quote">Parting is such sweet sorrow.</span></span>
I'm trying to use javascript to parse it such that extra tags are added to mark the context around the quote. The goal is to give users the option whether or not to display the quote plus context or just the quotation. The end result would be, e.g.,
<span id="text"><span id="preContext">It's like what Sir Ian McKellan told me the day I sold my boat to Karl Lagerfeld: </span><span id="quote">Parting is such sweet sorrow.</span></span>
This way, it would be simple to define the style.display of preContext as none. I've tried using insertAdjacentHTML; for example,
document.getElementById("text").insertAdjacentHTML('afterbegin', "<span id='preContext'>");
document.getElementById("quote").insertAdjacentHTML('beforebegin', "</span>");
But, as I've discovered, insertAdjacentHTML can insert nodes but not individual tags. The above gets me <span id="text"><span id="preContext"></span>It's like. . .
Is this possible in javascript, or does this need to be done in XSLT? (PS: I don't want to use JQuery. . )
Working example: http://jsfiddle.net/vcSFR/1/
This code gets the first textNode, wraps it in a span, and then swaps the original first text node for the new span.
var oDiv = document.getElementById("text");
var firstText = "";
for (var i = 0; i < oDiv.childNodes.length; i++) {
var curNode = oDiv.childNodes[i];
if (curNode.nodeName === "#text") {
firstText = curNode.nodeValue;
break;
}
}
firstTextWrapped = '<span id="preContext">' + firstText + '</span>';
oDiv.innerHTML = oDiv.innerHTML.replace(firstText, firstTextWrapped);
Thanks to https://stackoverflow.com/a/6520270/940252 for the code to get the first textNode.

Javascript no jquery - Split a textareas single column list (unknown line count) & display in csv's of 150

I am trying to put together what I thought would be an easy solution for a friend.
He has a list of fan emails that he collects at gigs and off his website.
He sticks them in a single column file and saves them.
He needs to have them in comma delimited format containing 150 each, one single line.
He wants a "simple" local HTML form he can paste the list into and have the results displayed.
So, I started working on it but, it has proven past my ability.
So far I have some basics but, I really need help.
As you can see, I am really a beginner.
<html><head>
<script type="text/javascript">
function makeit(){
var enteredEmails = document.getElementById("emails").value;
var cnt = document.getElementById("breakcnt").value;
var mails = enteredEmails.toString();
var textareacnt = '1';
// Now I think I need to loop or create arrays of emails up to cnt //
csvmails = mails.splice(0,cnt)
// Then dynamically generate some textareas or boxes populated with a single comma delimited line of cnt" emails //
document.write("<textarea id=\"textareacnt\">" + csvmails + "</textarea>")
textareacnt++;
}
</script>
</head><body>
<form onsubmit="makeit();">
<textarea name="emails" id="emails" rows="10" cols="75"></textarea><br />
<input type="text" name="breakcnt" id="breakcnt"><br />
<input type="submit" name="submit" value="submit">
</form>
<textarea id="results"></textarea>
</body></html>
The textarera will have emails pasted into it like:
amail1#sometld.com
bmail1#sometld.com
cmail1#sometld.com
amail4#sometld.com
zmail10#sometld.com
... up to 6000 fan emails he has collected over the years
He needs the results to be:
amail1#sometld.com,bmail1#sometld.com,cmail1#sometld.com,amail4#sometld.com,zmail10#sometld.com
up to 150 emails long as I am sure the last chunk or array will not contain 150.
I cant get anything to work and I spent 6 hours on this so far.
Can someone please help? I feel like a complete idiot.
All you have to do is split the text into an array and then splice the array in a loop and join the slices you take out like this:
var emails= document.getElementById('emails').value.split(/\s+/), list="";
while(emails.length) {
list+=emails.splice(0,150).join(',')+"\n";
}
//list now has the result you are looking for
I have made an example of how to this here: http://jsfiddle.net/PfB42/2/
All you have to do is paste the emails into the text area and it will automatically change the format to the one you are looking for, and insert it to the <pre> area below the textarea
This should achieve what you want.
Don't be so hard on yourself mate :)
<html><head>
<script type="text/javascript">
function makeit(){
var enteredEmails = document.getElementById("emails").value;
var results = document.getElementById("results");
var index = 0;
var index2 = enteredEmails.indexOf("\n");
while(true) {
results.value += enteredEmails.substring(index, index2);
index = index2+1;
var index2 = enteredEmails.indexOf("\n", index+1);
//EOF
if(index2 == -1) {
results.value += ",";
results.value += enteredEmails.substring(index, enteredEmails.length);
break;
} else {
results.value += ",";
}
}
}
</script>
</head><body>
<form onsubmit="makeit();">
<textarea name="emails" id="emails" rows="10" cols="75"></textarea><br />
<input type="button" value="submit" onclick="makeit()">
</form>
<textarea id="results"></textarea>
</body></html>
Ouch, don't use that complicated scripts. Strings have functions exactly for that purpose:
var input = document.getElementById("emails").value;
input = input.replace(/\r\n/g, "\n"); // I hate this
var emails = input.split("\n"); // make an Array
var output = emails.join(","); // should we use ", " instead?
Of course you could put everyhing in one line ;-)

Count characters in paragraph using jQuery (*not* for input/textarea)

How do I work out in jQuery a character counter of a p/div tag?
Basically i want to show a different css value IF the character value >=50.
Been struggling for hours with it :)
Use
$("#myDiv").text().length;
var $div = $('#mydiv');
if($div.text().length >= 50) {
$div.addClass('class');
}
Put a "long" class on all div and p elements with more than 50 characters:
$("p, div").filter(function(){
return $(this).text().length >=50;
}).addClass('long');
If you don't know how much content you have, though, then presumably this content is generated dynamically by the server, right? And if this is the case, wouldn't it make more sense to have the server—which knows how much content it's plopping into these containers—add the class dynamically while generating the page to send? Why rely on jQuery?
Try this snippet it works even if the text's length was greater than 50 characters.
You can also calculate the character digits of the paragraph. (Excluding new lines and space bars)
window.setInterval(function() {
var txt = $("#txt").val();
var parLength = $("#data").text().length;
var charLength = txt.replace(/ /g, '').replace(/\n/g, '').length;
$("#data").text(txt);
$("#calcLength").text("The paragrapgh's length is: " + parLength);
$("#calcChar").text("The amount of characters is: " + charLength);
}, 10);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea id="txt" placeholder="Enter text here..." style="height:100px;width:250px"></textarea>
<p id="data"></p>
<p id="calcLength"></p>
<b>Note: even a space character is calculated through the length function</b>
<p id="calcChar"></p>
<b>Note: a space bar,and every empty line is trimmed in the second calculated value</b>
I have provided this example to make it simple for use and compatability.

Categories

Resources