Make Javascript tooltip only display when I've specified the content - javascript

I'm using a small javascript to display a question mark icon with a explanatory tooltip next to product options on our ecommerce (bigcommerce) site. As it is, the script shows the icon for every product option, whether I've specified the content or not.
The content of the tooltip is set by using the following in the description section on the page:
<span id="[name of option]" style="display:none">[content of tooltip]</span>
If the content for the tooltip is not set, it displays "Description not available yet"
Here's an example of a page where the content is set:
http://www.www-savvyboater-com.mybigcommerce.com/carver-pontoon-bimini-top-sunbrella-a9sq4893ub
And here's an example of how it looks without the content set:
http://www.www-savvyboater-com.mybigcommerce.com/carver-bimini-top-double-duck-d5457ub
What I'd like is for the question mark icon to only show for the options where I've specified content for the tooltip. I don't know enough about javascript to figure it out on my own.
Here's the script in question:
$(document).ready(function() {
$(".productAttributeValue").each(function() {
var optionLabel = $(this).siblings('div');
var optionLabelText = optionLabel.children("label").children("span.name").text();
if ($("img", this).length < 1) {
$(this).siblings('div')
.children("label")
.children("span.name")
.append(" <div class='help_div' style='display: inline;'><img src='/product_images/uploaded_images/help.gif' alt='" + optionLabelText + "'/></div>");
}
});
$('.help_div').each(function() {
var slug = slugify($("img", this).prop('alt'));
var html = $("#" + slug).html();
var titleq = $("img", this).prop('alt').replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
titleq = "<strong style='font-size: 12px'>" + titleq + "</strong><br/>"
if (!html) html = "Description not available yet."
$(this).qtip({
content: titleq + html,
position: {
corner: {
tooltip: 'topRight',
target: 'bottomLeft'
}
},
style: {
tip: {
corner: 'rightTop',
color: '#6699CC',
size: {
x: 15,
y: 9
}
},
background: '#6699CC',
color: '#FFFFFF',
border: {
color: '#6699CC',
}
}
});
});
function slugify(text) {
text = text.replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
text = text.replace(/-/gi, "_");
text = text.replace(/^\s+|\s+$/g, "");
text = text.replace(/\s/gi, "-");
text = text.toLowerCase();
return text;
}
});

The best way to do this is to not create the HTML for the ? in the first place.
$(document).ready(function() {
$(".productAttributeValue").each(function() {
var optionLabel = $(this).siblings('div');
var optionLabelText = optionLabel.children("label").children("span.name").text();
// check that optionLabelText is not an empty string
if ($("img", this).length < 1 && slugify(optionLabelText).trim().length) {
$(this).siblings('div')
.children("label")
.children("span.name")
.append(" <div class='help_div' style='display: inline;'><img src='/product_images/uploaded_images/help.gif' alt='" + optionLabelText + "'/></div>");
}
});
$('.help_div').each(function() {
var slug = slugify($("img", this).prop('alt'));
var html = $("#" + slug).html();
var titleq = $("img", this).prop('alt').replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
titleq = "<strong style='font-size: 12px'>" + titleq + "</strong><br/>"
if (!html) html = "Description not available yet."
$(this).qtip({
content: titleq + html,
position: {
corner: {
tooltip: 'topRight',
target: 'bottomLeft'
}
},
style: {
tip: {
corner: 'rightTop',
color: '#6699CC',
size: {
x: 15,
y: 9
}
},
background: '#6699CC',
color: '#FFFFFF',
border: {
color: '#6699CC',
}
}
});
});
function slugify(text) {
text = text.replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
text = text.replace(/-/gi, "_");
text = text.replace(/^\s+|\s+$/g, "");
text = text.replace(/\s/gi, "-");
text = text.toLowerCase();
return text;
}
});
If that is not possible then there are two ways to handle this:
Hide the ? in CSS by default and then show them using javascript if data exists
.help_div {
display:none;
}
And in your javascript:
var slug = slugify($("img", this).prop('alt'));
var html = $("#" + slug).html();
var titleq = $("img", this).prop('alt').replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
titleq = "<strong style='font-size: 12px'>" + titleq + "</strong><br/>"
if (html) {
$(this).show();
}
Have the ? visible by default but destroy them if no data is found:
In your javascript:
var slug = slugify($("img", this).prop('alt'));
var html = $("#" + slug).html();
var titleq = $("img", this).prop('alt').replace(/[^-a-zA-Z0-9,&\s]+/ig, '');
titleq = "<strong style='font-size: 12px'>" + titleq + "</strong><br/>"
if (!html) {
$(this).remove();
}
Option 1 has less chance of causing issues/being jarring but it's up to you how you would like to implement this.

Related

DOM createElement() dynamically with click event to div specific url element

I am attempting to build a 9 divs (cards) dynamically containing information about store branch locations. Each card has a unique URL associated with it that links to each branches specific URL.
This approach, within the function, appends the first (0) URL to all the cards:
$("div").click(function() {
window.location = $(this).find("a").attr("href");
return false;
});
This approach appends the last URL (8) to all the cards:
branch.addEventListener("click", function(e){
e.preventDefault();
window.open(prop.pages_url);
})
Code I'm working with:
function buildLocationList(data) {
for (i = 0; i < 9; i++) {
var currentFeature = data.features[i];
var prop = currentFeature.properties;
//Create Card
var branches = document.getElementById('branches');
var url = branches.appendChild(document.createElement('a');
url.setAttribute('href', prop.pages_url);
)
var branch = branches.appendChild(document.createElement('div'));
branch.className = 'card';
branch.id = "branch-" + i;
branch.url = prop.pages_url;
branch.addEventListener("click", function(e){
e.preventDefault();
window.open(prop.pages_url);
})
//Append Branch Card Details
v
var company = branch.appendChild(document.createElement('h5'));
company.innerHTML = prop.name + '<br />';
var distancePhone = branch.appendChild(document.createElement('p'));
if (prop.distance) {
var roundedDistance = Math.round(prop.distance * 100) / 100;
distancePhone.innerHTML = '<span class="miles">Approx. ' + roundedDistance + ' miles</span>' + '<span class="location-phone">' + prop.phone_number + '</span>';
}
else {
distancePhone.innerHTML = prop.phone_number;
}
var address = branch.appendChild(document.createElement('p'));
if (prop.address_line_2) {
address.innerHTML += prop.address_line_1 + ', ' + prop.address_line_2 + '<br />';
}
else {
address.innerHTML += prop.address_line_1 + '<br />';
};
address.innerHTML += prop.address_city + ', ' + prop.address_state + ' ' +prop.address_postal_code + '</p>';
}
}
I would like the card to be clickable with a redirect to each branch's unique URL.
You're storing the URL on the card element:
branch.url = prop.pages_url
All you need to do in the click handler is access the property:
branch.addEventListener("click", function(e){
e.preventDefault();
window.open(e.currentTarget.url);
})
In the context of the event handler, e.currentTarget is the element to which the handler is attached. If you were interested in which element fired the event, you'd use e.target.
Here's your code snippet modified below. I don't think the links will open on here though due to the sandboxed iframe.
function buildLocationList(data) {
for (i = 0; i < data.features.length; i++) {
var currentFeature = data.features[i];
var prop = currentFeature.properties;
//Create Card
var branches = document.getElementById('branches');
var url = branches.appendChild(document.createElement('a'));
url.setAttribute('href', prop.pages_url);
var branch = branches.appendChild(document.createElement('div'));
branch.className = 'card';
branch.id = "branch-" + i;
branch.url = prop.pages_url;
branch.addEventListener("click", function(e){
e.preventDefault();
console.log(e.currentTarget.url);
window.open(e.currentTarget.url);
})
//Append Branch Card Details
var company = branch.appendChild(document.createElement('h5'));
company.innerHTML = prop.name + '<br />';
var distancePhone = branch.appendChild(document.createElement('p'));
if (prop.distance) {
var roundedDistance = Math.round(prop.distance * 100) / 100;
distancePhone.innerHTML = '<span class="miles">Approx. ' + roundedDistance + ' miles</span>' + '<span class="location-phone">' + prop.phone_number + '</span>';
}
else {
distancePhone.innerHTML = prop.phone_number;
}
var address = branch.appendChild(document.createElement('p'));
if (prop.address_line_2) {
address.innerHTML += prop.address_line_1 + ', ' + prop.address_line_2 + '<br />';
}
else {
address.innerHTML += prop.address_line_1 + '<br />';
};
address.innerHTML += prop.address_city + ', ' + prop.address_state + ' ' +prop.address_postal_code + '</p>';
}
}
buildLocationList({features:[{
properties: {
distance: 100,
name: 'Google',
pages_url: 'https://www.google.com',
phone_number: '123-456-7890',
address_line_1: '1234 Street',
address_city: 'Citytown',
address_state: 'State',
address_postal_code: '12345'
}
},{
properties: {
distance: 200,
name: 'Microsoft',
pages_url: 'https://www.microsoft.com',
phone_number: '123-456-7890',
address_line_1: '1234 Street',
address_city: 'Citytown',
address_state: 'State',
address_postal_code: '12345'
}
}]})
.card {
border: 1px solid #ccc;
padding: 10px;
max-width: 50%;
margin: 10px;
}
<div id="branches"></div>
<div>
w3schools
</div>
<script>
$("div").click(function() {
window.location = $(this).find("a").data("value");
});
</script>

How to wrap divs inside a new div?

I'm trying to wrap the two divs <div class="cm-cp-title"> and <div class="cm-cp-value"> inside a div called cm-cp-container. Actually it is working, but it merges all together, it is shown like below after I put the wrapAll();
what is that issues? im wonder how to separate each of it?
Below is the result i needed,
$(function() {
// document
'use strict';
var coupon = $('div.cm-coupon');
// Settings
coupon.each(function() {
var _coupon = $(this);
var cpValue = _coupon.attr("data-value") + "";
// Different Data type
if (_coupon.data('type') == "c1")
{
_coupon.addClass('red').css(
{
"background" : "black",
"display": "table"}
);
_coupon.append(
'<div class="cm-cp-title">' + 'black here' + '</div>' + '\n' + '<div class="cm-cp-value">' + cpValue + '</div>'
);
}
else if (_coupon.data('type') == "c2")
{
_coupon.addClass('green').css(
{
"background" : "green",
"display": "table"}
);
_coupon.append('<div class="cm-cp-title">'+ 'green here' + '</div>' + '\n' + '<div class="cm-cp-value">' + cpValue + '</div>');
}
else if (_coupon.data('type') == "c3")
{
_coupon.addClass('blue').css(
{
"background" :"blue",
"display": "table"}
);
_coupon.append('<div class="cm-cp-title">'+ 'blue here' + '</div>' + '\n' + '<div class="cm-cp-value">' + cpValue + '</div>');
} else {
return false;
}
});
$('.cm-cp-title, .cm-cp-value').wrapAll("<div class='cm-cp-container'/>");
// alignment to middle
$('.cm-coupon').on('resize',function() {
$(".cm-cp-container").css('margin-top', function() {
return($('.cm-coupon').height() - $(this).height()) / 2
});
}).resize();
});//end
.cm-coupon {
width: 340px;
height: 156px;
float: left;color: #fff;
margin: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cm-coupon" data-type="c1" data-value="50"></div>
<div class="cm-coupon" data-type="c2" data-value="20"></div>
<div class="cm-coupon" data-type="c3" data-value="70"></div>
Working Snippet :
$(function() {
'use strict';
var coupon = $('div.cm-coupon');
var colors = new Map([["c1", "black"], ["c2", "green"], ["c3", "blue"]]);
// Settings
coupon.each(function() {
var _coupon = $(this);
var cpValue = _coupon.attr("data-value") + "";
var color = colors.get(_coupon.data('type'));
_coupon.addClass(color).css({
"background" : color,
"display": "table"
});
_coupon.append('<div class="cm-cp-title">' + color + ' here' + '</div>' + '\n' + '<div class="cm-cp-value">' + cpValue + '</div>');
$(_coupon.children()).wrapAll("<div class='cm-cp-container'/>");
});
// alignment to middle
$('.cm-coupon').on('resize',function() {
$(".cm-cp-container").css('margin-top', function() {
return($('.cm-coupon').height() - $(this).height()) / 2
});
}).resize();
});//end
.cm-coupon {
width: 340px;
height: 156px;
float: left;
color: #fff;
margin: 0 10px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cm-coupon" data-type="c1" data-value="50"></div>
<div class="cm-coupon" data-type="c2" data-value="20"></div>
<div class="cm-coupon" data-type="c3" data-value="70"></div>
Explanation :
First
I reduced the code removing the if statements because the only difference between the blocks if/else/else was the color ("black"/"green"/"blue"). I used a Map instead, to switch the value of the color according to the type.
What I did:
var colors = new Map([["c1", "black"], ["c2", "green"], ["c3", "blue"]]);
coupon.each(function () {
var _coupon = $(this);
var color = colors.get(_coupon.data('type'));
And then use color where need to.
Second
The problem you are encoutering is because you are not wrapping all the divs into the container, but wrapping the children of the divs.
So
$('.cm-cp-title, .cm-cp-value').wrapAll("<div class='cm-cp-container'/>");
becomes
$(coupon).wrapAll("<div class='cm-cp-container'/>");
EDIT :
It seems like you want to wrap the inner elements of the coupons instead.
Then use _coupon.children() instead, like this
$(_coupon.children()).wrapAll("<div class='cm-cp-container'/>");
and move it inside the each loop.
I edited the snippet. you can check.
In fact, the way you did it in your code, it is selecting all the matching elements in the document and wrapping it altogether. That is why the last two were moving inside the black div.

toLocaleString() not working no errors showing up

I'm trying to add commas to the input to both the value integers and the summary number in the middle. I've added
$summaryNumber.toLocaleString();
but nothing works. I'm trying to understand what I'm doing wrong.
here's a fiddle with what I'm working with
https://jsfiddle.net/cmLkbq6e/2/
$(function(){
$("#doughnutChart").drawDoughnutChart([
{ title: "test", value : 150000000, color: "#e65c53" },
{ title: "test", value: 150000000, color: "#26a3b1" },
{ title: "test", value: 250000000, color: "#19818d" },
{ title: "test", value : 200000000, color: "#396b7e" },
{ title: "test", value : 100000000, color: "#a5a5a5" }
]);
});
those are the values I'm trying to target
and here's the summary number I'm trying to target
var $summaryTitle = $('<p class="' + settings.summaryTitleClass + '">' + settings.summaryTitle + '</p>').appendTo($summary);
var $summaryNumber = $('<p class="' + settings.summaryNumberClass + '"></p>').appendTo($summary).css({opacity: 0});
$summaryNumber.toLocaleString();
In the jsFiddle, find the below part of the code and change it,
Here is the updated JsFiddle : https://jsfiddle.net/cmLkbq6e/11/
Previously,
function drawDoughnutText(animationDecimal, segmentTotal) {
$summaryNumber
.css({opacity: animationDecimal})
.text((segmentTotal * animationDecimal).toFixed(1));
}
After Modification,
function drawDoughnutText(animationDecimal, segmentTotal) {
$summaryNumber
.css({opacity: animationDecimal})
.text((segmentTotal * animationDecimal).toLocaleString());
}
The problem is the$summaryNumber is object , it is not number
as I checked it in your code it be to
var $summaryNumber = $('<p class="' + settings.summaryNumberClass + '"></p>').appendTo($summary).css({opacity: 0});
which mean be an Object so your code is not working,
You should do something like:
afterDrawed : function() {
var number = parseFloat($('#doughnutChart .doughnutSummaryNumber').html());
$('#doughnutChart .doughnutSummaryNumber').html(number.toLocaleString());
},

JavaScript not able to replace text with new text

I am trying to convert selected text's font with help of AngularJs and jQuery. This is my code. Everything is working fine but i am not able to change the text with a new text.
This is my code:
var app = angular.module('myApp', []);
app.controller('editor', function($scope) {
$scope.color = "black";
$scope.selectedText = "";
$scope.changeFont = function() {
if ($scope.selectedText != "") {
var changedText = "<span style='font-size:" + $scope.kys_selected_font + "px' >" + $scope.selectedText + "</span>";
alert($scope.selectedText + $scope.kys_selected_font + " " + changedText);
document.getElementById("#content").innerHTML.replace($scope.selectedText, changedText);
} else {
$("#content").append("<span id='one' style='font-size:" + $scope.kys_selected_font + "px' > this is some text </span>");
$("#one").focus();
}
};
$("#content").mouseup(function() {
$scope.selectedText = window.getSelection();
});
});
innerHTML.replace(...) returns a new string, rather than modifying the existing one, so your replacement won't modify the element.
You need to actually update the property:
var el = document.getElementById("content");
el.innerHTML = el.innerHTML.replace($scope.selectedText, changedText);
(also note # removed from element ID as per #IvanSivak's comment)

Problems to place the input field at correct position in JQuery

When I double click the card the dialog pops up, and it is then possible to create comments. So far so good. When creating the comments it is possible to edit it.
The issue is when I edit the text the input filed where I edit the text is placed in wrong position. And cover the "Edit/Delete" paragraph. I want the input filed to be placed when pressing the edit on the text position.
Live Demo
JQuery: "click" handler
$('#divComments').on('click', '.edit', function () {
var element = $(this).parent()
var text = $(this).parents(".CommentStyle").find("label").text();
var input = $('<input id="attribute" value="' + text + '" />')
element.children('label,p').addClass('hidden').end().append(input);
input.select();
input.blur(function () {
var text = $('#attribute').val();
element.children('label').text(text);
element.children('.hidden').removeClass('hidden');
$('#attribute').remove();
element.children('label').change();
});
});
JQuery: Add comment function
function addComment(commentString) {
var container = $('#divComments');
var inputs = container.find('label');
var id = inputs.length + 1;
var data1 = {
commentString: commentString
};
var div = $('<div />', { class: 'CommentStyle' });
$('<label />', {
id: 'comment' + id,
text: commentString
}).on('change', function () {
data1.commentString = $(this).text();
}).appendTo(div);
$('<br/>').appendTo(div);
var $Image = $('<img />',
{
"src": "/Pages/Images/alert.png",
"class": "CommentImage",
"for": "comment" + id
}).appendTo(container);
var d = new Date();
var $fulaDate = $('<div>' + d.getDate()
+ "-" + monthNames[d.getMonth()]
+ "-" + d.getFullYear()
+ "//" + d.getHours()
+ ":" + d.getMinutes()
+ '</div>').addClass('labelStyle').append(' ~').appendTo(div);
var $edit = $('<p />', {
class: 'edit',
text: 'Edit'
}).append(' ~').appendTo(div);
var $delete = $('<p />', {
class: 'delete',
text: 'Delete'
}).appendTo(div);
div.appendTo(container).focus();
container.data('comments').push(data1);
}
Simply modify the following line
element.children('label,p').addClass('hidden').end().append(input);
to
element.children('label,p').addClass('hidden').end().prepend(input);
JSFiddle Demo
Instead of appending the input-field as the last element, you should insert it where the label was.
$('#divComments').on('click', '.edit', function () {
var element = $(this).parent()
var label = $(this).parents(".CommentStyle").find("label");
var text = label.text()
var input = $('<input id="attribute" value="' + text + '" />')
element.children('label,p').addClass('hidden')
label.after(input)
input.select();
input.blur(function () {
var text = $('#attribute').val();
element.children('label').text(text);
element.children('.hidden').removeClass('hidden');
$('#attribute').remove();
element.children('label').change();
});
});
To hide the timestamp, just add .labelStyle to the list of elements you want to hide:
element.children('label,p,.labelStyle').addClass('hidden')

Categories