Javascript page overlay without changing dom - javascript

I am in the process of learning JS, and am trying to add an integer (number of clicks) to all links on my page (This data is being parsed from an external API).
I am currently changing the link textContent for each link, and appending the integer to the end of the textContent, which works well for all text links, however I am having an issue with adding this click count integer to the images on the page. What would be the best way to display the click count for images on the page. Would I be able to add the click count as an overlay on the image?
My code so far:
function ls(url) {
var getURL = "url" + url;
var req = new XMLHttpRequest();
req.open("GET", getURL, "true");
req.onload = function() {
var resObj = JSON.parse(req.responseText);
var links = document.querySelectorAll("a");
for (var i = 0; i < links.length; i++) {
var rawLink = links[i].href; var linkText = links[i].textContent; var link = links[i].href.replace(/(.*)#?/, "$1");
var escapedLink = escape(rawLink);
if (rawLink in resObj) {
links[i].textContent = linkText + " (" + resObj[rawLink] + ")";
} else if (escapedLink in resObj) {
links[i].textContent = linkText + " (" + resObj[escapedLink] + ")";
}
}
};
This just appends the link count to the end of the textContent, how can I add this linkcount to images without messing up the page layout.

One solution would be to wrap the images in a <div> and add the click count text as another child. Something like:
<div class="image-wrapper">
<img src="..." alt="..." />
<div class="click-count">10</div>
</div>
Then just style the click count text to be placed in a corner of the image using CSS. Possibly something like:
.image-wrapper { position: relative; }
.click-count { position: absolute; bottom: 10px; right: 10px; }
To add the text to the image, you would have to do something like this (note that I am using jQuery for simplicity and because the question is tagged as such):
$( 'img' ).each( function() {
// Test we need to add the click count
...
// Add the click count number
$( this ).wrap( '<div class="image-wrapper" />' ).append( '<div class="click-count">' + click_count + '</div>' );
});

Related

I'm trying to append my a tag to my li tag but it doesn't seem to be working?

I'm trying to append my a tag to my li tag and then add that li to the messages id, but for some reason it doesn't seem to be working.
When I append the message.url to #messages it prints to the screen fine, but when I append the var a to the screen it doesn't show up. Not quite sure what is going on, I've tried just about everything I can think of.
socket.on('newLocationMessage', function (message) {
var li = $('<li></li>');
var a = $('<a target="_blank"><My current location</a>');
li.text(`${message.from}: `);
a.attr('href', message.url);
li.append(a);
$('#messages').append(li);
});
Here is a simply way to solve your question without .text or .attr.
If you could provide your sample code(HTML) to here, it will be helpful.
// find elements
var button = $("button");
// handle event like newLocationMessage event
button.on("click", function() {
//replace your data
let message = {
url: "https://google.com",
from: "Google"
};
var li = $('<li><a target="_blank" href="' + message.url + '">' + message.from + '</a></li>');
$('#messages').append(li);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul id="messages"></ul>
<button>
trigger
</button>
It had an extra < next to My current location!
socket.on('newLocationMessage', function (message) {
var li = $('<li></li>');
var a = $('<a target="_blank"><My current location</a>');
li.text(`${message.from}: `);
a.attr('href', message.url);
li.append(a);
$('#messages').append(li);
});

Make text into links outside of <a> tags only

Here's my issue. I made a function that resolves links in javascript, but the use-case I'm stuck with is that there may already be HTML in posts with links.
Users can not post true HTML, but moderators and administrators can, meaning I need to handle both cases.
Here's an example of your typical user post HTML:
<div class="teaser">
This is just your normal post http://google.com some other stuff
</div>
And administrator/moderator:
<div class="teaser">
<b>
THIS LINK
</b>
<br><br>
Supplemental reading: Link again
</div>
Normally, I'd use something like
function replaceURLWithHTMLLinks(text) {
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
return text.replace(exp,"<a href='$1' target='_blank'>$1</a>");
}
c.not('a').each(function() {
var html = $(this).html();
$(this).html(replaceURLWithHTMLLinks(html));
});
But this causes links to be parsed which exist inside of the href property. I need to be able to create links only when they are outside of tags, and it needs to be through all children as you'll notice that is the first child in a mod/admin post (if they so choose).
Mods and admins can put basically any HTML they desire in their posts, so the tag could be anywhere in the post hierarchy which is not at all consistent.
I could just not parse links on admin or mod posts, but sometimes some mods and admins use the proper HTML tags, and sometimes they don't, which is why I'd like to know the proper way of doing this.
Try this:
var exp = /^(\b(https?|ftp|file):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig;
$('.teaser').each(function() {
var i, words;
$this = $(this);
words = $this.html().split(' ');
for (i = 0; i < words.length; i++) {
if (exp.test(words[i])) {
words[i] = words[i].replace(exp, "<a href='$1' target='_blank'>$1</a>");
}
}
$this.html(words.join(' '));
});
Demo Link
I found the answer here it seems.
filterTeaserLinkContent: function(data) {
var exp = /\b((https?|ftps?|about|bitcoin|git|irc[s6]?):(\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/|magnet:\?(dn|x[lts]|as|kt|mt|tr)=)([^\s()<>]+|\([^\s()<>]+\))+(\([^\s()<>]+\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/g;
var nodes = data[0].childNodes;
for(var i = 0; i < nodes.length; i++) {
var n = nodes[i];
if(n.nodeType == n.TEXT_NODE || n.nodeName == 'BR') {
var g = n.textContent.match(exp);
while(g) {
var idx=n.textContent.indexOf(g[0]);
var pre=n.textContent.substring(0,idx);
var a=document.createElement("a");
if (!/^[a-z][\w-]+:/.test(g[0])) {
a.href = "http://" + g[0];
} else {
a.href = g[0];
}
a.innerText = g[0];
n.textContent = n.textContent.substring(idx+g[0].length);
n.parentElement.insertBefore(a,n);
g=n.textContent.match(exp);
}
} else {
Board.filterTeaserLinkContent($(n));
}
}
},
filterTeaserContent: function(data) {
// Jam into <div> so we can play with it
var c = $('<div>' + data + '</div>');
// Remove <wbr> tag which breaks links
c.find('wbr').each(function() {
$(this).remove();
});
// Re-parse the HTML after removing <wbr> or else the text nodes won't be joined
c = $('<div>' + c.html() + '</div>');
// I actually forget what this does, but fuck it. Shit.
c.not("div, s, span, a").each(function() {
var content = $(this).contents();
$(this).replaceWith(content);
});
Board.filterTeaserLinkContent(c);
// Remove images in post preview because they don't need to be here...
c.find('img').each(function() {
$(this).remove();
});
// Simplify line breaks
return c.html().replace(/<br ?\/?><br ?\/?>/g, "<br>");
},
This is for use in the 4chan API in case anyone was curious.

Show image in JavaScript

I got a litlle js code that is showing me updates from a feed
google.load("feeds", "1");
function initialize() {
var feed = new google.feeds.Feed("http://google.com/");
feed.setNumEntries(1);
var count = 1;
feed.load(function(result) {
if (!result.error) {
var container = document.getElementById("feed");
var html = "";
for (var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
html = "<h5>" + count++ + ". <a href='" + entry.link + "'>" + entry.title + "</a></h5>";
var div = document.createElement("div");
div.innerHTML = html;
container.appendChild(div);
}
document.write(html);
}
});
}
google.setOnLoadCallback(initialize);
What i want to do is to show the first image from the posts from the feed. i would also like to have the title so entry.title and entry.content
Even though parsing html with regx is big dodo, I will still advise you this, parse your content html with /<img\s+src\s*=\s*(["'][^"']+["']|[^>]+)>/
Or a lazy way is to have a hidden div and do this
var temp = document.createElement( 'div' );
temp.innerHTML = html_str;
var images = temp.getElementsByTagName( 'img' );
First, you must use entry.content instead of entry.title in order to get the full HTML content of the entry. You may have something like this:
var content = entry.content;
var imgArray = content.match( /<img\s+src\s*=\s*(["'][^"']+["']|[^>]+)>/ );
// imgArray[0] would contain the first image (more likely the one that better describe the post)
P.S.: I didn't steal this Regex from actual answer, but it seems that we've got to the same reference for it :-)
UPDATE:
Then, to display it in a container, I would advise you to dynamically create DOM elements to gain more control over it, and in which you will be able to easily associate a value. Something like this:
var dom_h5 = document.createElement('h5');
var dom_entryTitle = document.createElement('div');
dom_entryTitle.className = 'title-classname';
dom_entryTitle.innerHTML = entry.title;
dom_h5.appendChild(dom_entryTitle);
container.appendChild(dom_h5);
To simplify the image part, you could create a separate div and inject the image tag as his innerHTML.
This may help you:
Web API Reference - document.createElement

Problems updating the content of a Kendo UI TabStrip without AJAX?

I have a small console that displayed the output of certain actions in my website, the need to have another console that would display a different kind of output made me want to combine both consoles in a Kendo UI TabStrip, the thing is that the information displayed on the console isn't received with AJAX so when I started to insert the HTML elements like before, the tab didn't got updated.
This is how I initialize the tab:
$('#tabConsole').kendoTabStrip({
animation: {
open: {
effects:'fadeIn'
}
}
});
This is how my HTML looks:
<div id="tabConsole">
<ul>
<li class="k-state-active">Salida</li>
<li id="notificacionTab">Notificaciones</li>
</ul>
<div id="userConsole"></div>
<div id="notificationConsole"></div>
</div>
This is how I try to update it:
function appendToConsole(content, type, optional) {
//code to append to console
var actualDate = new Date();
var prevContent = $('#userConsole').html();
if (typeof prevContent === 'undefined') {
prevContent = '';
}
var strType = '';
var iconType = '';
var moreOutput = '';
if (type == 1) {
strType = 'infoConsole';
iconType = 'infoIcon.png';
} else if (type == 2) {
strType = 'warningConsole';
iconType = 'warningIcon.png';
moreOutput = '<img id="viewDetails" value="' + optional + '" class="moreConsole" src="../Content/images/icons/arrow.png">';
} else if (type == 3) {
strType = 'errorConsole';
iconType = 'errorIcon.png';
}
var iconOutput = '<img class="iconConsole" src="../Content/images/icons/' + iconType + '">';
var dateOutput = '<div class="dateConsole">' + iconOutput + ' ' + actualDate.toLocaleDateString() + ', ' + actualDate.toLocaleTimeString() + ' : </div>';
var consoleOutput = prevContent + '<div class="outputConsole">' + dateOutput + content + moreOutput + '</div>';
$('#userConsole').html(consoleOutput.toString());
var height = $('#userConsole')[0].scrollHeight;
$('#userConsole').scrollTop(height);
//my try to update the tab
var tabStrip = $('#tabConsole'),
selectedIndex = tabStrip.data('kendoTabStrip').select().index(),
clone = original.clone(true);
clone.children('ul')
.children('li')
.eq(selectedIndex)
.addClass('k-state-active')
.end();
tabStrip.replaceWith(clone);
$('#tabConsole').kendoTabStrip({
animation: {
open: {
effects: 'fadeIn'
}
}
});
}
How can I update the contents of the DIV that are inside the TabStrip?
EDIT
It seems Kendo UI renames the DIVs' ids that represent the tabs to tabConsole-1 and tabConsole-2, explaining why the update wasn't working, still there's a lot of strange behavior, I had to specify the height for each DIV so the overflow propety would work, also the images with id viewDetails and class moreConsole when set to position absolute, get rendered outside the DIV that represents the tab, but if I change the position property to relative, the images stay inside the DIV but are displayed not at the end of the DIV like I want to, but relative to the size of the DIV that comes before them.
I'm really confused as to how to set the styles so the contents are displayed properly.
Adding content to a tabStrip can be achieved using:
$(tabConsole.contentElement(idx)).append(newContent)
where:
idx is the tab index,
newContent is what you want to add to the existing content and
tabConsole is the variable set to $("#...").kendoTabStrip(...).data("kendoTabStrip");.
You don't need to create a new tabStrip (in addition you should not re-create KendoUI elements since this is a pretty expensive operation).
About using multiple tags with the same id... you should not use it, use class instead. ids should be unique.
I'm still trying to understand your problem with the styling.

jQuery not removing absolute positioned divs?

I have the following code which will hide the parent div of the link you click on. When the div's are relatively positioned, there is no problem, but when they are absolutely positioned, they won't remove.
The script also saves the state of each element to localStorage, and the error only happens the first time you try to close one of the divs. What I mean by this is that, if you show three divs, say div one, two, and three, and then try to close the top most div, it won't close. If you reload the page, and try to close div three, which is on top from before you reloaded the page, it will close.
There's a little bit too much code to post, so here's the jsFiddle for it. But here's the code for posterity:
function loadWidgets() {
$(".base").each(function () {
var id = $(this).attr("id");
var counter = localStorage.getItem("counter-" + id) || 0;
var active = localStorage.getItem(id + "-active") || "";
$.each(active.split(" "), function (k, v) {
var s = v.split(",");
if (s.length != 2) {
return;
}
var newElement = $("#" + s[0]).clone(true, true);
newElement.attr("id", s[1]).attr("class", "drag " + id).data("id", id).appendTo("body");
});
});
}
function closeWidget() {
var id = $(this).parent().attr("id").match(/[a-zA-Z]+/g);
$(this).parent().remove();
var active = [];
$($("." + id).not(".base")).each(function () {
active.push(id + "," + $(this).attr("id"));
});
active = active.join(" ");
localStorage.setItem(id + "-active", active);
}
function cloneWidget() {
var id = $(this).attr("href").match(/[a-zA-Z]+/g);
var key = "counter-" + id;
var counter = localStorage.getItem(key) || 0;
counter++;
var newElement = $("#" + id).clone(true, true);
newElement.attr("id", id + counter).attr("class", "drag " + id).appendTo("body");
var active = [];
$($("." + id).not(".base")).each(function () {
active.push(id + ',' + $(this).attr("id"));
});
active = active.join(" ");
localStorage.setItem(id + "-active", active);
localStorage.setItem(key, counter);
}
loadWidgets();
$(".nav a").click(cloneWidget);
$(".close").click(closeWidget);​
And the HTML:
<div class="base" id="one" style="background-color:blue">
<a class="close" href="#">Close</a>
<input class="input" id="test"/>
<textarea class="textarea" id="test2"></textarea>
</div>
<div class="base" id="two" style="background-color:red">
<a class="close" href="#">Close</a>
</div>
<div class="base" id="three" style="background-color:green">
<a class="close" href="#">Close</a>
</div>
<div class="nav">
One
Two
three
</div>​
jQuery's clone doesn't copy events by default:
.clone( [withDataAndEvents] [, deepWithDataAndEvents] )
[...]
Normally, any event handlers bound to the original element are not copied to the clone. The optional withDataAndEvents parameter allows us to change this behavior, and to instead make copies of all of the event handlers as well, bound to the new copy of the element.
And since you have events bound to things inside what you're cloning, you want deepWithDataAndEvents to be true as well:
var newElement = $("#" + s[0]).clone(true, true);
Corrected fiddle: http://jsfiddle.net/ambiguous/Jdutt/
You create a new widget but you do not assign an event handler to the Close link.
Take the next line and put it at the end of the cloneWidget function:
$("#" + id + counter + " a.close").click(closeWidget);

Categories