I have written a script to add a Pinterest button to most images on my site. The issue is that when someone has the Chrome Pin it extension enabled in their browser, the "pin it" button shows up twice for the user.
Is there anyway, in JavaScript, to check if the user has this extension enabled in their browser?
(function($) {
$(function() {
$('.container img').each(function() {
if ($(this).parent('a')) {
var $permalink = $(this).parent('a').attr('href');
}
else {
var $permalink = $(location).attr('href');
}
var $permalink = $(location).attr('href'),
$title = $('h1.product_name').text() || $('h2.header');
var $linkhtml = $('<a/>', {
'class':'pin-it-button pinme',
'html': '<img src="//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_gray_20.png" />',
'count-layout': 'horizontal',
'style': 'cursor:pointer; position:absolute; bottom:30px; left:0; border:0 none; opacity: 0.4;',
'href': 'http://pinterest.com/pin/create/button/?url=' + $permalink + '&media=' + $(this).attr('src') + '&description=' + $title
});
if ($(this).parent('a')) {
$(this).addClass('pinme').parent('a').after($linkhtml);
}
else {
$(this).addClass('pinme').after($linkhtml);
}
$('.pinme').hover(
function() {
if ($(this).hasClass('pin-it-button')) {
console.log('hello');
$(this).css('opacity', '1');
}
else {
$(this).parent().siblings('.pin-it-button').css('opacity', '1');
}
}, function() {
if ($(this).hasClass('pin-it-button')) {
$(this).css('opacity', '0.4');
}
else {
$(this).parent().siblings('.pin-it-button').css('opacity', '0.4');
}
}
);
});
});
})(jQuery);
The new Pinterest extension (2017)
injects a <span> hover button directly under <body:
<span style="border-radius: 3px;
text-indent: 20px;
width: auto;
padding: 0px 4px 0px 0px;
text-align: center;
font-style: normal;
font-variant: normal;
font-weight: bold;
font-stretch: normal;
font-size: 11px;
line-height: 20px;
font-family: "Helvetica Neue", Helvetica, sans-serif;
color: rgb(255, 255, 255);
background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMzBweCIgd2lkdGg9IjMwcHgiIHZpZXdCb3g9Ii0xIC0xIDMxIDMxIj48Zz48cGF0aCBkPSJNMjkuNDQ5LDE0LjY2MiBDMjkuNDQ5LDIyLjcyMiAyMi44NjgsMjkuMjU2IDE0Ljc1LDI5LjI1NiBDNi42MzIsMjkuMjU2IDAuMDUxLDIyLjcyMiAwLjA1MSwxNC42NjIgQzAuMDUxLDYuNjAxIDYuNjMyLDAuMDY3IDE0Ljc1LDAuMDY3IEMyMi44NjgsMC4wNjcgMjkuNDQ5LDYuNjAxIDI5LjQ0OSwxNC42NjIiIGZpbGw9IiNmZmYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxIj48L3BhdGg+PHBhdGggZD0iTTE0LjczMywxLjY4NiBDNy41MTYsMS42ODYgMS42NjUsNy40OTUgMS42NjUsMTQuNjYyIEMxLjY2NSwyMC4xNTkgNS4xMDksMjQuODU0IDkuOTcsMjYuNzQ0IEM5Ljg1NiwyNS43MTggOS43NTMsMjQuMTQzIDEwLjAxNiwyMy4wMjIgQzEwLjI1MywyMi4wMSAxMS41NDgsMTYuNTcyIDExLjU0OCwxNi41NzIgQzExLjU0OCwxNi41NzIgMTEuMTU3LDE1Ljc5NSAxMS4xNTcsMTQuNjQ2IEMxMS4xNTcsMTIuODQyIDEyLjIxMSwxMS40OTUgMTMuNTIyLDExLjQ5NSBDMTQuNjM3LDExLjQ5NSAxNS4xNzUsMTIuMzI2IDE1LjE3NSwxMy4zMjMgQzE1LjE3NSwxNC40MzYgMTQuNDYyLDE2LjEgMTQuMDkzLDE3LjY0MyBDMTMuNzg1LDE4LjkzNSAxNC43NDUsMTkuOTg4IDE2LjAyOCwxOS45ODggQzE4LjM1MSwxOS45ODggMjAuMTM2LDE3LjU1NiAyMC4xMzYsMTQuMDQ2IEMyMC4xMzYsMTAuOTM5IDE3Ljg4OCw4Ljc2NyAxNC42NzgsOC43NjcgQzEwLjk1OSw4Ljc2NyA4Ljc3NywxMS41MzYgOC43NzcsMTQuMzk4IEM4Ljc3NywxNS41MTMgOS4yMSwxNi43MDkgOS43NDksMTcuMzU5IEM5Ljg1NiwxNy40ODggOS44NzIsMTcuNiA5Ljg0LDE3LjczMSBDOS43NDEsMTguMTQxIDkuNTIsMTkuMDIzIDkuNDc3LDE5LjIwMyBDOS40MiwxOS40NCA5LjI4OCwxOS40OTEgOS4wNCwxOS4zNzYgQzcuNDA4LDE4LjYyMiA2LjM4NywxNi4yNTIgNi4zODcsMTQuMzQ5IEM2LjM4NywxMC4yNTYgOS4zODMsNi40OTcgMTUuMDIyLDYuNDk3IEMxOS41NTUsNi40OTcgMjMuMDc4LDkuNzA1IDIzLjA3OCwxMy45OTEgQzIzLjA3OCwxOC40NjMgMjAuMjM5LDIyLjA2MiAxNi4yOTcsMjIuMDYyIEMxNC45NzMsMjIuMDYyIDEzLjcyOCwyMS4zNzkgMTMuMzAyLDIwLjU3MiBDMTMuMzAyLDIwLjU3MiAxMi42NDcsMjMuMDUgMTIuNDg4LDIzLjY1NyBDMTIuMTkzLDI0Ljc4NCAxMS4zOTYsMjYuMTk2IDEwLjg2MywyNy4wNTggQzEyLjA4NiwyNy40MzQgMTMuMzg2LDI3LjYzNyAxNC43MzMsMjcuNjM3IEMyMS45NSwyNy42MzcgMjcuODAxLDIxLjgyOCAyNy44MDEsMTQuNjYyIEMyNy44MDEsNy40OTUgMjEuOTUsMS42ODYgMTQuNzMzLDEuNjg2IiBmaWxsPSIjYmQwODFjIj48L3BhdGg+PC9nPjwvc3ZnPg==") 3px 50% / 14px 14px no-repeat rgb(189, 8, 28);
position: absolute;
opacity: 1;
z-index: 8675309;
display: none;
cursor: pointer;
border: none;
-webkit-font-smoothing: antialiased;
top: 240px;
left: 110px;
">Save</span>
So a simple check would be:
var pin = document.querySelector('body > span[style*="8675309"][style*="rgb(189, 8, 28)"]')
Or you can check for the entire background base64 string which contains the P logo.
Old answer for the old PinIt extension:
Examining a page with Pin It extension installed we can see that it adds its own attribute to <body>:
<body data-pinterest-extension-installed="cr1.39.1">
It's easy to determine the presence of the attribute in js:
if (document.body.dataset.pinterestExtensionInstalled) {
console.log("Pin It extension detected!");
}
Note that the attribute is added after the page has been loaded so you can't check it right in DOMContentLoaded event handler; make a pause with setInterval or use MutationObserver:
Content script with "run_at": "document_end" or "document_idle" (the default mode):
var PinItInstalled = undefined;
new MutationObserver(function(mutations) {
PinItInstalled = document.body.dataset.pinterestExtensionInstalled;
this.disconnect();
}).observe(document.body, {
attributes: true,
attributeFilter: ["data-pinterest-extension-installed"]
});
Content script with "run_at": "document_start":
var PinItInstalled = undefined;
document.addEventListener("DOMContentLoaded", function() {
new MutationObserver(function(mutations) {
PinItInstalled = document.body.dataset.pinterestExtensionInstalled;
this.disconnect();
}).observe(document.body, {
attributes: true,
attributeFilter: ["data-pinterest-extension-installed"]
});
});
P.S. Don't forget to test what happens if the Pin It extension's option to show its button on hover is disabled.
While detecting the presence of the extension or pinit.js on the page may be worthwhile, the easier solution is to simply add the data-pin-no-hover attribute to your images. This will tell the extension to ignore the images.
<img src="whatevz" data-pin-no-hover="true" />
There really isn't any reason to care if it is installed or not if the data-pin attribute is set.
The other option is to not create your own hover buttons, but use pinit.js that creates the hover buttons for you. See the docs.
<script
type="text/javascript"
async defer
data-pin-hover="true"
src="//assets.pinterest.com/js/pinit.js"
></script>
Related
In Anki, I have a note type where one card is effectively a cloze deletion, however I am using other cards at the same time, with the cloze deletion field in it. I've tried to use javascript to replace everything within two '\'s and it appears to work in the preview when editing, but when the card appears during normal use, only the first line appears as plain text. I'm using the desktop linux program for editing, but would also like to be able to use it in AnkiDroid.
So the question is: what's the problem and how can I fix it?
Front Template:
<script>
function showDef() {
document.getElementById("def").innerHTML = '{{Bedeutung 1}}'.replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
};
var initial = false;
var beispiel = (function () {/*{{Beispiel 1}}*/}).toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
var splitBeispiel = beispiel.split('\\');
document.write(splitBeispiel[0] + "<n id='cloze'>[...]</n>" + splitBeispiel[2]);
</script>
<p onclick="showDef()" id="def">Click to show definition</p>
Styling:
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
#cloze {
font-family: arial;
font-size: 25px;
text-align: center;
color: blue;
background-color: white;
}
#def {
font-family: arial;
font-size: 15px;
text-align: center;
color: green;
background-color: white;
}
#beispiel {
font-family: arial;
font-size: 15px;
text-align: center;
color: orange;
background-color: white;
}
Back Template:
<script>
var initial = false;
var beispiel = (function () {/*{{Beispiel 1}}*/}).toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
var splitBeispiel = beispiel.split('\\');
document.write(splitBeispiel[0] + "<n id='cloze'>" + splitBeispiel[1] +"</n>" + splitBeispiel[2]);
</script>
<hr id=answer>
{{Singular Nominativ}}
The 'Beispiel 1' field in the following example is "ein kirchlicher, ein \gesetzlicher\ Feiertag"
Screenshot of editor preview:
Screenshot of test:
I guess, you should look for the solution here.
Avoid using document.write in your templates and use document.getElementById("HTMLidToReplace").innerHTML = '<b>' + your_var + '</b>';, for example. Hope it helps.
I would like to develop a popup function (html,css,js) and use it anywhere in the webpage.
Here is the pop function:
function pop (options) {
var mod = function( options ) {
var that = this;
this.op = { title: 'new pop' }; // for startup
for( var option in options ){
this.op[ option ] = options[ option ];
};
this.title = options.title;
this.build();
this.remove = function() { // remove this pop
document.body.removeChild( that.cover );
};
};
mod.prototype.build = function() { // create new pop
this.cover = document.createElement('div');
document.body.appendChild( this.cover );
};
return new mod( options );
}; // pop
var callpop = pop( { title: 'make a pop' } ); // so i can call
callpop.remove(); // and remove it
First question, is this design pattern make sense?
Second question, can i do :
this.remove = function() { // remove this pop
document.body.removeChild( that.cover );
that = undefined; // add this line to make the callpop undefined
};
console.log( callpop ); // so i can check if pop is display, than i can remove it by callpop.remove(), and make a new one callpop = pop()
beside give me a link, can u give me some short example please? Many thank!
Update 1:
I just would like to know, if you get a job to write a popups function, how would you code it? is my example make sense?
Since you are driving the whole popup flow with javascript thus it would be hard to make modifications on markup side. It's better to keep html in either markup or templates. Because it's easier to make edits in markup for the display part.
One very nice example of this would be how bootstrap manages its modal popups. Have a look at here. They drive it completely by markup and events are attached at the time of page load.
You can customize this behavior as per your needs but try to keep javascript in .js and html in .html or .templates.
Also, have a look at their source code for modal.
And for using template for modal you should have look at how angular-ui-bootstrap handles those scenarios.
Update:
For a basic reference see this demo in jsbin. And code here.
<SCRIPT TYPE="text/javascript">
function popup(mylink, windowname)
{
if (!window.focus)
return true;
var href;
if (typeof(mylink) == 'string')
href=mylink;
else href=mylink.href;
window.open(href, windowname, 'width=400,height=200,scrollbars=yes');
return false;
}
</SCRIPT>
popup('autopopup.html', 'ad')
Hi you can use this popup. Below the complete example of custom design
popup.
$(document).ready(function() {
// When site loaded, load the Popupbox First
loadPopupBox();
$('#popupBoxClose').click(function() {
unloadPopupBox();
});
$('#container').click(function() {
unloadPopupBox();
});
});
function unloadPopupBox() {
// TO Unload the Popupbox
$('#popup_box').fadeOut("slow");
$("#container").css({
// this is just for style
"opacity": "1"
});
}
function loadPopupBox() {
// To Load the Popupbox
$('#popup_box').fadeIn("slow");
$("#container").css({
// this is just for style
"opacity": "0.3"
});
return false;
}
/* popup_box DIV-Styles*/
#popup_box {
display: none;
/* Hide the DIV */
position: fixed;
_position: absolute;
/* hack for internet explorer 6 */
height: auto;
width: auto;
background: #FFFFFF;
top: 150px;
z-index: 100;
/* Layering ( on-top of others), if you have lots of layers: I just maximized, you can change it yourself */
margin-left: 15px;
/* additional features, can be omitted */
border: 2px solid #ff0000;
padding: 15px;
font-size: 15px;
-moz-box-shadow: 0 0 5px #ff0000;
-webkit-box-shadow: 0 0 5px #ff0000;
box-shadow: 0 0 5px #ff0000;
}
#container {
background: #d2d2d2;
/*Sample*/
width: 100%;
height: 100%;
}
a {
cursor: pointer;
text-decoration: none;
}
/* This is for the positioning of the Close Link */
#popupBoxClose {
font-size: 20px;
line-height: 15px;
right: 5px;
top: 5px;
color: #6fa5e2;
font-weight: 500;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<!-- HTML Structure for popup box-->
<div id="popup_box">
<!-- OUR PopupBox DIV-->
<h1>This IS A Cool PopUp</h1>
<div runat="server" id="dvContent"></div>
<a id="popupBoxClose">Close</a>
</div>
<!-- Main Page -->
<div id="container">
<h1>Click on link to load sample popup</h1>
<input type="button" value="Click Me" id="btnClick" onclick="loadPopupBox();" />
</div>
so i have a menu and i add a font awesome icon on each parent menu.
and if they click the icon it will show slide down animation to show their child menu.
currently my code is like this
on css
li {
a {
border-bottom: solid thin $color-green;
#include font-size(1.2);
padding: 5px 0px;
}
.sub-menu {
display: none;
list-style: none;
padding: 0;
a {
padding: 5px 20px;
display: block;
}
}
&.menu-item-has-children {
a {
&::after {
content: '\f055';
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
float: right;
}
&::before{
content: '\f056;';
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
float: right;
}
}
}
}
on my php file( im using wp)
<div id="navbar-main-menu" class="collapse navbar-collapse">
<?php
if (has_nav_menu('primary_navigation')) :
wp_nav_menu(['theme_location' => 'primary_navigation', 'menu_class' => 'nav top-menu ']);
endif;
?>
</div>
<!--/.nav-collapse -->
i want to jquery active only on max resolution 767, so my script is like this.
but i dont know how to target the after and make specifict code so when i click 1 parent link it didnt trigger the other parent link to show their child menu.
var resizeTimer;
$(window).resize(function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if ($(window).width() <= 767) {
$('.menu-item-has-children a::after').click(function() {
$('a').slideToggle();
});
} else {
}
});
});
this is my progress now
please help
Use this keyword instead of targeting a element.
var resizeTimer;
$(window).resize(function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if ($(window).width() <= 767) {
$('.menu-item-has-children a').click(function() {
$(this).slideToggle();
});
} else {
}
});
});
On a separate note why are you using a timer to check the width. I am not sure if this is hindering with your code or not. If the above code doesn't work, please create a JSfiddle and share the link so that I can have a better look.
Update
Pseudo element doesn't work with jquery selector. Updated the code for the same. But this may not be complete solution OP is looking for.
I made a quote generator and it works fine with the Chrome developer tools open, but then won't generate a new quote when the developer tools are closed. This happens with my project in CodePen. On my computer, it generates a quote three times (works fine the first three clicks of the generate quote button) then stops working. It's not working at all in Safari. Why would this be?
I'm sure my JavaScript could use some refactoring too, any help there would also be great. Thanks!
Link to CodePen Demo
HTML
<html>
<head>
<title>Random Quote Generator</title>
<link rel="stylesheet" type="text/css" href="css/quote.css">
<link href='https://fonts.googleapis.com/css?family=Lato:300italic,300' rel='stylesheet' type='text/css'>
</head>
<body>
<div class="quote-container">
<div class="quote" id="msg"></div>
</div>
<div class="button-container">
Get Quote
</div>
<div id="twtbtn"></div>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script>
<script type="text/javascript" src="js/quote.js"></script>
</body>
</html>
CSS
body {
background: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url('https://images.unsplash.com/photo-1437652010333-fbf2cd02a4f8?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&s=2330269f135faf1c33bf613b85d5f1df');
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
* {
font-family: 'Lato', sans-serif;
}
.quote-container {
display: flex;
flex-direction: column;
justify-content: center;
}
.quote {
width: 80%;
text-align: center;
margin: 0 auto;
font-size: 48px;
font-style: italic;
color: white;
}
.button-container {
margin: 30px auto 50px auto;
text-align: center;
}
#button {
border: 1px solid white;
padding: 12px 30px;
background: transparent;
font-size: 18px;
border-radius: 2px;
}
#button:hover {
background-color: white;
}
a {
text-decoration: none;
color: white;
}
a:hover {
color: black;
};
JavaScript
$(document).ready(function(){
//get quote from random quote API
$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
//append quote and author to document
$(".quote").append(a[0].content + "<p>— " + a[0].title + "</p>")
//initiate twitter button function
window.twttr = (function (d,s,id) {
var t, js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return; js=d.createElement(s); js.id=id;
js.src="https://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js, fjs);
return window.twttr || (t = { _e: [], ready: function(f){ t._e.push(f) } });
}(document, "script", "twitter-wjs"));
//insert tweet button
insertTweetBtn();
});
});
$("a").click(function(){
//get quote from random quote API
$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
//replace HTML with newly generated quote
$(".quote").html(a[0].content + "<p>— " + a[0].title + "</p>")
//remove contents of tweet button div
$("#twtbtn").empty();
//insert new tweet button to grab newly generated quote
insertTweetBtn();
});
});
function insertTweetBtn() {
var msg = document.getElementById('msg').textContent;
twttr.ready(function (twttr) {
twttr.widgets.createShareButton(
'',
document.getElementById('twtbtn'),
function (el) {
console.log("Button created.")
},
{
text: msg ,
}
);
twttr.events.bind('tweet', function (event) {
console.log(event, event.target);
});
});
}
Ok...so i was going crazy trying to figure it out then I went to the documentation for getJSON for jquery. I am not 100% about JSONP but thats the thing, when you add the &callback into the url..it uses JSONP. So I removed it and it works great in safari. Here is the codepen
FIXED
and here is the quote from jquery:
"If the URL includes the string "callback=?" (or similar, as defined by the server-side API), the request is treated as JSONP instead. See the discussion of the jsonp data type in $.ajax() for more details."
$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1", function(a) {stuff}
This unfortunately doesn't explain why safari is the only one it didn't work in...but hey, it fixes it :)
Am currently working with the Soundcloud API to pull images and track links for songs. Am currently showing track info through a modal window upon clicking the album image. However, for the songs on the bottom of the screen, the modal window only appears at the top of the screen, requiring a user to scroll up to see the track info. Probably has something to do with the css positioning but removing position:absolute only puts the modal window at the bottom of all the album images, requiring a scroll down. How can I make it so that a user's click on an image will open and start the modal window right where they currently are, without scrolling? Javascript / jquery /css answers all welcomed.
My CSS:
#modal {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
position: absolute;
top: 0;
left: 0;
}
#trackinfo {
width:380px;
height: 180px;
padding: 20px;
margin-right: auto;
margin-left: auto;
margin-top: 100px;
box-shadow: 10px 10px 5px;
border-radius: 15px;
text-align: center;
background: #c4e5c1;
font-family: Rockwell, "Courier Bold", Courier, Georgia, Times, "Times New Roman", serif;
}
.hidden {
display:none;
}
My Javascript for show and hide modal:
function doSearch() {
var searchTerm = document.getElementById('search').value;
// Search soundcloud for artists
SC.get('/tracks', { q: searchTerm}, function(tracks) {
for(track in tracks) {
var img = document.createElement('img');
img.setAttribute("src", (tracks[track]["artwork_url"]));
var title = tracks[track].title.replace("'", "\\\'").replace("\"", "\\\"");
linky = document.createElement('a');
linky.setAttribute("href", (tracks[track].permalink_url));
console.log(linky);
img.setAttribute("onclick", "showTrackInfo('" + title + "\\n"+ tracks[track].uri + " " + "\\n\\n(click to close) " + "')");
console.log(img);
if (tracks[track]["artwork_url"] == null) {
console.log(""); }
else {
var Catalog = document.getElementById('catalog');
Catalog.appendChild(img);
$('div#catalog').append('<img src="http://i.imgur.com/rGdvfl7.png">');
}
}
});
};
function showTrackInfo(track) {
var trackInfoElement = document.getElementById("trackinfo");
trackInfoElement.appendChild(document.createTextNode(track));
var modal = document.getElementById("modal");
modal.setAttribute("class", "");
}
function hidemodal() {
var trackInfoElement = document.getElementById("trackinfo");
trackInfoElement.childNodes;
while ( trackInfoElement.firstChild ) trackInfoElement.removeChild( trackInfoElement.firstChild );
var modal = document.getElementById("modal");
modal.setAttribute("class", "hidden");
}
The functions all work well, I just need to know how to position the modal box upon click so that the user doesn't need to scroll to see the trackinfo. Any help much appreciated.
Try position: fixed; on the dialog box, should make it fill the page no matter where they are on it