Replace "Save To Foursquare" button with custom button - javascript

I am trying to replace the generic "Save to foursquare" button that can be set up here: https://foursquare.com/buttons/savetofoursquare
I want to replace it with my own custom foursquare button (.svg versions from Fairhead Creative, distributed by Zurb Foundation here: http://zurb.com/playground/social-webicons), and not have the script automatically wipe out and replace my custom button with the pre-packaged foursquare save button.
I am pretty sure I just need to script my own solution, using the documentation here: https://developer.foursquare.com/overview/widgets -- but I'm a bit confused. Wish there were examples there.
I also have several buttons on one page referencing various vcards (multiple museum locations). To do that, I used the data-context attribute from the answer here: Multiple Foursquare 'save' buttons on one page. That is all working.
I'm using my own html:
<span id="venue1-foursquare" class="fc-webicon foursquare" data-context="venue1_vcard">save Venue 1 to foursquare</span>
And later on the page:
<span id="venue2-foursquare" class="fc-webicon foursquare" data-context="venue2_vcard">save Venue 2 to foursquare</span>
How to do this?

OK, I knew I should keep searching and tinkering before posting this question. :)
Thanks to vnads here, I saw how to set up the global onReady functionality. I set it up to use a jQuery each(), loop through the spans, grab the data-context values, and then attach the functionality to my DOM element. The critical bit here came from vnads' comment at the end of the (currently) accepted solution: foursquare is looking for a DOM element, not a jQuery object.
Oh, and the widget.attach() instead of widget.replace() keeps the custom graphic from getting run-over.
<!-- 4Square js: -->
<script type='text/javascript'>
(function() {
window.___fourSq = {
"explicit": false,
"onReady": function () {
$('.fc-webicon.foursquare').each(function() {
var this_widget = $(this);
var this_context = this_widget.data("context");
var widget = new fourSq.widget.SaveTo({
"context": this_context
});
widget.attach(this_widget[0]);
});
}
};
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'http://platform.foursquare.com/js/widgets.js';
s.async = true;
var ph = document.getElementsByTagName('script')[0];
ph.parentNode.insertBefore(s, ph);
})();
</script>

Related

How to extend Leaflet Icon Class to add data-open attribute to marker HTML?

I'm trying to trigger some functionality based on the click of a marker on a GeoJSON layer in Leaflet. The eventual functionality I'm trying to implement is a flyout, or scroll out type modal populated from the individual feature's JSON attributes. Essentially, I'm trying to implement the functionality in this Tutsplus Tutorial with dynamic feature content based on the marker click.
I THINK I've figured out most of the pieces I need, but I'm struggling with how to add a data attribute, specifically data-open, to the individual marker. Building on an earlier question of mine I've realized it's not enough to just update a DOM element's CSS, but rather my app should be implementing changes based on data attributes to fully get the functionality I want.
From this question I know that this should be done by extending the L.Icon class that Leaflet provides, but the answer is a bit too terse for my current JS skills. I apologize for this effectively being a "ELI5" of a previously asked question, but I'm not sure where the options and slug come into function. I think they're implied by the question, rather than the answer I'm citing and being set on the marker itself.
Here's a simplified version of the the click handler on my markers, which grabs and zooms to location, gets feature info, and populates that info to a div. The zoom functionality works, as does extracting and placing the feature info, but I'm struggling with how to connect the functionality to trigger the modal and place the div with the feature info over the map.
function zoomToFeature(e) {
var latLngs = [e.target.getLatLng()];
var markerBounds = L.latLngBounds(latLngs);
var street = e.target.feature.properties.str_addr;
document.getElementById('street').textContent = street;
mymap.fitBounds(markerBounds);
//where the modal trigger should be
document.getElementById('infoBox').classList.add('is-visible');
}
Here are the event listeners taken from the linked tutorial, which are currently not firing, but I have them working in a standalone implementation:
const openEls = document.querySelectorAll("[data-open]");
const closeEls = document.querySelectorAll("[data-close]");
const isVisible = "is-visible";
//this is the event I want to trigger on marker click
for (const el of openEls) {
el.addEventListener("click", function() {
const modalId = this.dataset.open;
console.log(this);
document.getElementById(modalId).classList.add(isVisible);
});
}
for (const el of closeEls) {
el.addEventListener("click", function() {
this.parentElement.parentElement.parentElement.classList.remove(isVisible);
});
}
document.addEventListener("click", e => {
if (e.target == document.querySelector(".modal.is-visible")) {
document.querySelector(".modal.is-visible").classList.remove(isVisible);
}
});
So, where I'm trying to get is that when my markers are clicked, the trigger the modal to appear over the map. So, I think I'm missing connecting the marker click event with the event that triggers the modal. I think what's missing is adding the data attribute to the markers, or some way chain the events without the data attributes. As there's no direct way to add an attribute to the markers, I try to add slug option on my circle markers:
var circleMarkerOptions = {
radius: 2,
weight: 1,
opacity: 1,
fillOpacity: 0.8,
slug: 'open',
}
and If I read the previously asked question's answer correctly, than extending the Icon Class this way should add a data-open attribute.
L.Icon.DataMarkup = L.Icon.extend({
_setIconStyles: function(img, name) {
L.Icon.prototype._setIconStyles.call(this, img, name);
if (options.slug) {
img.dataset.slug = options.slug;
}
}
});
A stripped down version of my code is here (thanks #ghybs). My full implementation pulls the markers from a PostGIS table. It's a bit hard to see in the Plunker, but this code adds my class to my modal, but doesn't trigger the functionality. It does trigger the visibility if the class is manually updated to modal.is-visible, but the current implementation which renders modal is-visbile doesn't, which I think is because the CSS is interpreted on page load(?) and not in response to the update via the dev tools, while the concatenated css class matches extactly(?). When I do trigger the modal via the dev tools, the close modal listeners don't seem to work, so I'm also missing that piece of the puzzle.
So, it's a work-around to setting the data attribute, but I realized I was shoe-horning a solution where it wasn't needed. Assuming someone ends up with the same mental block. Appropriate listeners on the modal close button and another function passed to the existing marker click listener produce the desired functionality.
const closeM = document.querySelector(".close-modal");
closeM.addEventListener("click", closeMe);
var modal = document.getElementById('infoBox');
and
function modalAction(){
modal.style.display = 'block';
}
function closeMe(){
modal.style.display = 'none';
}

Angularjs: ng-class and CSS animations (running only once)

I am an AngularJS newbie so please be patient.
First, the code. Here's the relevant .html part:
<span ng-class="{'error-text': true, 'animated-error': vm.email_error}" ng-show="vm.email_error" translate>EMAIL_ERROR</span>
The .scss part:
.error-text{
position: absolute;
&.animated-error{
animation: bigandnormal 2s;
}
}
And there is a .js that is modifying vm.email_error after a click:
var validateEmail = function(){
var isEmailValid = /(.+)#(.+){2,}\.(.+){2,}/.test(vm.email);
vm.email_error = !isEmailValid;
return isEmailValid;
};
A button click runs the validateEmail() function.
What happens here is that when I perform the first click (with an invalid email) the class is added correctly to the span and the animation runs.
But if I click again, the animation is NOT run again.
Looking at the inspector, it seems that the class in never added again.
I have even tried to reset vm.email_error to false in the first line of the validateEmail() function and removed the animated-error from the console before clicking again:
angular.element(".error-text").each(function(index, el) {
angular.element(el).removeClass('animated-error');
});
But I cannot see anymore the animation and the class.
But in any case I do not think I am not doing it the right way, there should be a way to accomplish this.
This is what I am asking you :)
Thanks in advance.
UPDATE: I if put vm.email_error = !isEmailValid; in a setTimeout it works properly. It would be great to have an explanation from someone who knows that technology. Of course, it is clear that this cannot be the real solution.
Try to declare your email_error variable as a $scope or $rootScope variable rather than as a controller variable.
var validateEmail = function(){
var isEmailValid = /(.+)#(.+){2,}\.(.+){2,}/.test(vm.email);
$scope.email_error = !isEmailValid; // or $rootScope.email_error = !isEmailValid;
return isEmailValid;
};
And you don't need the quotes around your css class name.
Then call it in your html without prefixes, like this:
<span ng-class="{error-text: true, animated-error: email_error}" ng-show="email_error" translate='EMAIL_ERROR'></span>
Also, be careful on how to use angular translate :
If you use it as a directive, you have to write it as
<p translate='MY_TRAD'></p>
If you use it as a filter, then it's
<p>{{ 'MY_TRAD' | translate }}</p>
(angular translate doc: https://github.com/angular-translate/angular-translate)

angular-recaptcha: Change language with site language change

I have website which uses three different languages switchable by user. Language switch is done on client side by JavaScript (AngularJS).
I am using reCAPTCHA 2 on my website and need to change language of reCAPTCHA when the user switches languge of website.
I know already that I can force the language by this code when the reCAPTCHA is initialized:
<script src="https://www.google.com/recaptcha/api.js?hl=cs"></script>
However, when you need reloading reCAPTCHA, you use this code and it doesn't take any parameter for custom language:
grecaptcha.reset();
Is it possible to do that without refreshing the page and re-initialization of reCAPTCHA widget with different language?
EDIT
I am using angular-recaptcha to render the widget. This means that:
I need calling vcRecaptchaApiLoaded callback after reCAPTCHA API init
I cannot change the code rendered by vcRecaptcha directive
This is code which renders reCAPTCHA widget:
<div
vc-recaptcha
key="'---- YOUR PUBLIC KEY GOES HERE ----'"
></div>
This is the code which insludes reCAPTCHA API into my web:
<script
src="https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit&hl=cs"
async defer
></script>
You can simply empty the div.g-recaptcha and load the script again (programmaticaly).
The function below should do the trick:
function changeRecaptchaLanguage(language) {
document.querySelector('.g-recaptcha').innerHTML = '';
var script = document.createElement('script');
script.src = 'https://www.google.com/recaptcha/api.js?hl=' + language;
script.async = true;
script.defer = true;
document.querySelector('head').appendChild(script);
}
Take a look at the example in the snippet below:
function changeRecaptchaLanguage(language) {
document.querySelector('.g-recaptcha').innerHTML = '';
var script = document.createElement('script');
script.src = 'https://www.google.com/recaptcha/api.js?hl=' + language;
script.async = true;
script.defer = true;
document.querySelector('head').appendChild(script);
}
var curr = 'en';
changeRecaptchaLanguage(curr);
document.querySelector('button').addEventListener('click', function() {
curr = curr === 'en' ? 'pt-BR' : 'en';
changeRecaptchaLanguage(curr);
});
<div>Other stuff</div>
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
<button>Change language</button>
I think this is a duplicate question. Please see one proposed solution here:
Change ReCaptcha language OnClick
To summarize:
It is not possible to do set recaptcha language through javascript directly at the moment. As you stated, it is however possible using the parameter 'hl' during script loading.
If you need to change the language of your application dynamically without reloading the page, you can do this by removing the recaptcha script link from the head section and instead, loading it directly with a call from javascript. When your user changes the language by clicking a button, you can now reload recaptcha with the new language by calling the load function again.
You can simply just add the value in "lang" directive.
<div vc-recaptcha key="publicKey" lang="en"></div>
I just stumbled on this question. I know it has been asked a while ago but I think the best way to do this is to use the method useLang from the service inside a $watch in the variable lang.
So in the html identify the lang we are on:
<div id="g-recaptcha" class="g-recaptcha" vc-recaptcha key="domainkey" lang="$root.lang" on-success="setResponse(response)"></div>
And, if you can, inside the directive just put the $watch on that variable:
scope.$watch('lang', function(){
if(scope.widgetId!=null){
vcRecaptcha.useLang(scope.widgetId,scope.lang);
}
});
How to set ng-recaptcha language on init:
<re-captcha class="g-recaptcha"
siteKey="asdfasdfasdfasdfasdasd"
[(ngModel)]="myRecaptcha"
name="captcha"
#recaptcha></re-captcha>
app.module.ts
import {RecaptchaModule ,RECAPTCHA_LANGUAGE} from 'ng-recaptcha';
const getDomainBaseUrl = location.toString();
export const language = baseUrl.toLocaleLowerCase();
...
providers: [
...
{
provide: RECAPTCHA_LANGUAGE,
useValue: language,
},
],

jQuery-Mobile controlgroup does not render

I am trying to insert a controlgroup widget in to the page but when I call controlgroup() the redering is incorrect. All the expected buttons are showing as links (Chrome 38.0.2125.101 m).
I'm assuming that it is something I'm doing and not a bug since the demos appear to work nicely. Is there a step I'm missing?
Here's my sample code:
http://jsfiddle.net/Lwr4mm4v/5/
function Body() {
this.left_buttons = $('<div data-role="controlgroup"></div>').appendTo( 'div' );
this.save_button = $('save description').appendTo(this.left_buttons);
this.run_button = $('run description').appendTo(this.left_buttons);
this.stop_button = $('stop description').appendTo(this.left_buttons);
this.add_button = $('add state').appendTo(this.left_buttons);
this.left_buttons.controlgroup();
}
var test = new Body();
Thanks
You are using an old version of JQM which requires calling an additional method .trigger("create").
It's recommended to use JQM 1.4.4 where you don't have to use any additional methods.
JQM 1.3: http://jsfiddle.net/Lwr4mm4v/6/
JQM 1.4: http://jsfiddle.net/4dfu9vtu/
Looking at the latest documentation, one adds a class="ui-btn" to anchor elements that you want to use as buttons.
Here is some sample code that achieves your goal:
function Body() {
this.left_buttons = $('<div data-role="controlgroup" data-type="horizontal"></div>').appendTo('#root');
this.save_button = $('Save').appendTo(this.left_buttons);
this.run_button = $('Run').appendTo(this.left_buttons);
this.stop_button = $('Stop').appendTo(this.left_buttons);
this.add_button = $('Add').appendTo(this.left_buttons);
this.left_buttons.controlgroup();
}
var test = new Body();
I have built a new sample illustrative jsFiddle that can be found here:
jsFiddle
See also this documentation on using the "Controlgroup Widget":
Control Group Widget

How should I be sharing Javascript functions across multiple pages?

I don't completely understand how javascript works in an OOP model, so I come to stack overflow for wisdom.
My example code:
(function($) {
var $container = $('#container');
var $sidebar = $('#sidebar');
// Sidebar
var currTab = $('#s1');
if(currTab) {
currTab.parent().parent().parent().addClass('selectedTop');
currTab.find(".sideContent").delay(300).slideToggle("slow");
currTab.addClass('selected');
}
$('#sideTop').delegate('li', 'hover', function(event) {
var $this = $(this);
if (event.type == 'mouseenter') {
if(!$this.hasClass("selected")){
$this.siblings(".selected").children(".sideContent").toggle();
$this.siblings(".selected").removeClass('selected');
$this.find(".sideContent").toggle().addClass('selected');
$this.addClass('selected');
}
}
});
})(this.jQuery);
This code caches my container and sidebar div and controls the hovering of tabs on my sidebar. These will be on every page, so I originally just included the js file on each page and it works as usual. Now I've gotten to a point where I want to customize each page with a specific tab of the sidebar open by default (defined by the currTab variable). When set, it will open by default, and stay open after the mouse leaves the sidebar.
I haven't found a way to customize currTab on each page without having to completely re-paste all the code associated with the sidebar, making any updates to the script cumbersome.
How should I be approaching this? Thanks
I'm sorry to have caused confusion with my lack of understanding, but one of the related questions answered mine in a way I didn't know how to search for:
He setup a "class" first, which could be included as a seperate JS, then communicated using jQuery.ClassName(options)
I've tried it and it works perfectly, seperating the code that is consistent, with the values that will change on each page.
(function($){
var undefined;
$.ClassName = function(options){
var self = this;
var cfg = $.extend(true, {}, this.defaults, options);
// ********************
// start:private
// ********************
function _init(){
};
// ********************
// start:public
// ********************
this.methodName = function(){
};
_init();
};
$.ClassName.prototype.defaults = {};
})(jQuery);
With classes. Just add a class such as "currTab" to whichever tab is active. In your JS, check for that class on the tab, and when the tab is changed, remove that class from the old one and add it to the new one.
Add a class to the item you want to be active by default. Use JS to detect the class and react accordingly.
One way is, to declare currTab differently inside each HTML page, and remove "var currTab = $('#s1');" from your JavaScript file. The rest of currTab occurences in the JavaScript file are still able to reference it.

Categories

Resources