How to get ID of link that opened Fancybox3 within onComplete? - javascript

I have seen what looks like it could be the solution to this issue in other questions on stackoverflow, but NONE of them have worked.
I am trying to get the innertext of the link that was clicked to open Fancybox:
$("a.turnDateLink").each(function() {
var that = $(this);
$( "a.turnDateLink" ).fancybox({
'type': 'modal',
'onComplete': function() {
var currentday = $(that).text();
console.log(currentday);
},
'afterClose': clearCurrentDay,
'fullScreen' : false
});
});
It only returns the innerText of the last a.turnDateLink. EVERY TIME! ugh.
Keep in mind that I would like to use the fancybox grouping with this.
See the Fancybox documentation to understand grouping: http://fancyapps.com/fancybox/3/docs/#usage
If you have a group of items, you can use the same attribute
data-fancybox value for each of them to create a gallery. Each group
should have a unique value:

Check documentation about events - http://fancyapps.com/fancybox/3/docs/#events
The first examaple contains useful tips, including how to find clicked element:
onComplete: function( instance, slide ) {
// Tip: Each event passes useful information within the event object:
// Object containing references to interface elements
// (background, buttons, caption, etc)
// console.info( instance.$refs );
// Current slide options
// console.info( slide.opts );
// Clicked element
// console.info( slide.opts.$orig );
// Reference to DOM element of the slide
// console.info( slide.$slide );
}

Try like this.Change $( "a.turnDateLink" ) to that.
$("a.turnDateLink").each(function() {
var that = $(this);
that.fancybox({
'type': 'modal',
'onComplete': function() {
$("#currentday").html('');
var currentday = that.text();
console.log(currentday);
},
'afterClose': clearCurrentDay,
'fullScreen' : false
});
});

Related

jQuery .remove() does not work with div created inside the function

I've tried a couple of things since yesterday, but I can't achieve my goal.
The idea is :
When clicking on a character "Div", it appears a little menu to change a parameter inside my website. The problem is, I want to remove the "Class Picker", but it just does not work.
var CharacterClasses = [
{ id: 1, name: 'Warrior', cssClass: 'warrior'},
{ id: 2, name: 'Paladin', cssClass: 'paladin'},
...
]
$('.group_miniature').click( function(){
// Removing all existant class choices
$(".group-panel_class_picker").remove()
// Creating the class picker
var Panel = $("<div id=\"panel_class_picker\"></div>").addClass('group-panel_class_picker')
// Append the whole thing
$(this).append(Panel)
// Iterating each class to add a div
CharacterClasses.forEach( function(item){
// Creating the div
let btn_class = $("<div>&nbsp</div>").addClass( [item.cssClass,'group-btn_class'] )
Panel.append(btn_class)
Panel.on("click", ".group-btn_class", function(event){
$(this).parent().remove() // This is my problem, it does not remove the parent
console.log('Click :)') // This appears in my console
})
})
})
Panel.on("click", ".group-btn_class", function(event){
$(this).parent().hide()
event.stopPropagation()
console.log('Click criss')
})
I discovered that I had to add event.stopPropagation()
Now it works just fine ! :)

How to make a code reusable in jQuery?

In my WordPress' projects, I'm using the following code again and again for many of my fields where I'm using a button to initiate the WordPress media uploader and on selection of the file I'm sending its path/url to a text field.
var project_field_image_uploader;
$('#button-input').click( function(e) {
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title:"Choose an image",
button:{
text: "Insert"
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
$('#text-field').val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
});
For each of the field I need to edit the following things:
First variable - project_field_image_uploader (not necessarily it should be meaningful, it is only for creating different instances, so in a reusable way, it can be anything, but not conflicting)
Button's ID - $('#button-input')
Text field's ID - $('#text-field')
Media Library Modal's head - title:"Choose an image",
Media Library's Media Insertion button's text - text: "Insert"
Is there a way I can make this code reusable, so that I can be with DRY ideology? A jQuery function may do the job for me, but I cannot sort things out, how can I sort this thing.
<script>
$(function(){
$('#button-input').click(function(e){
var text_field = $('#text-field');
....................
var mytext = 'my text';
myfunc(e,project_field_image_uploader,text_field,mytitle,mytext);
});
//reuse with any other button click with different parameters
});
function myfunc(e,project_field_image_uploader,text_field,mytitle,mytext){
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title:mytitle,
button:{
text: mytext
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
text_field.val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
}
</script>
Thanks to #alamnaryab for his answer that directed me to the right way (+1 for that). But passing a variable as a function parameter was problematic. It produces an error:
project_field_image_uploader is not defined
I figured out things that, a variable need not to pass as a function parameter to be unique, because a variable inside a function is a local variable. So I simply called the variable inside the function and reused the function multiple times. I'm here posting the working example code.
And declaring multiple variables, I used comma with a single var declaration. There's no need to repeat things. Thanks again to Mr. Alam Naryab.
<script>
$(function(){
$('#button-input').click(function(e){
var text_field = $('#text-field'),
media_lib_head = 'Choose an image',
btn_text = 'Insert';
//using the function where necessary
project_reusable_repeating_func( e, text_field, media_lib_head, btn_text );
});
});
/**
* Reusable function
* #author alamnaryab
* #link http://stackoverflow.com/a/32035149/1743124
*/
function project_reusable_repeating_func( e, text_field, media_lib_head, btn_text ){
//a variable that need not to be unique, because it's local
var project_field_image_uploader;
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title: media_lib_head,
button:{
text: btn_text
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
text_field.val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
}
</script>

Change selectMenu option programmatically in child inAppBrowser

I open a window using javascript window.open()
The window that opens has the following code:
jQuery(document).ready(function(){
jQuery("#lang").change(function(){
var lname = jQuery(this).val().split("-");
window.location = '<?php echo JURI::root();?>index.php?lang='+lname[0];
alert(lname[0]);
alert('lang '+lang);
});
Now this code is triggered upon 'lang' select menu change. I open the window programmatically using window.open and I managed to populate data into the window fields using Window.executeScript(). For example this works for me:
loginWindow.executeScript({
code: "jQuery('input#username').val('10500050')"
});
However, when I tried to follow the same logic for changing the selected item in selectMenu called 'lang' for the same window, I failed.
Attempts
I tried all the following lines in executeScript;
code: "$('#lang').val('ms')"
code: "jQuery('#lang option[value=ms]').prop('selected', true)"
code: "jQuery('#lang').selectmenu('value', 'ms')"
with these in the next executeScript to trigger change
code: "$('#lang').trigger('change')"
code: "$('#lang').selectmenu('refresh', true)"
code: "jQuery('#lang').selectmenu('refresh')"
code: "jQuery('#lang').selectmenu('change')"
code: "$('#lang').change()"
None of them helped. I'm not sure if I should combine them in one executeScript. I do not know how to do that. The window that opens is from different domain.
Am I missing something here?
The entire code on the opener side is as follows:
loginWindow.addEventListener( 'loadstop', function() {
alert('test');
var loop = setInterval(function() {
loginWindow.executeScript({
code: "jQuery('input#username').val('10500050')"
},
function( values ) {
var give = values[ 0 ];
if ( give ) {
clearInterval( loop );
giveMeUsername();
}
});
loginWindow.executeScript({
code: " jQuery('input#name').val('10500050')"
},
function( values ) {
var give = values[ 0 ];
if ( give ) {
clearInterval( loop );
giveMeUsername();
}
});
loginWindow.executeScript({
//code: "$('#lang').val('zh')"
//code: "jQuery('#lang option[value=ms]').prop('selected', true)"
code: "jQuery('#lang').selectmenu('value', 'ms')"
//code: "localStorage.setItem( 'lan', 'ms' )"
},
function( values ) {
var give = values[ 0 ];
if ( give ) {
clearInterval( loop );
giveMeUsername();
}
});
loginWindow.executeScript({
//code: "$('#lang').trigger('change')"
//code: "$('#lang').selectmenu('refresh', true)"
//code: "jQuery('#lang').selectmenu('refresh')"
//code: "jQuery('#lang').selectmenu('change')"
code: "$('#lang').change()"
},
function( values ) {
var give = values[ 0 ];
if ( give ) {
clearInterval( loop );
giveMeUsername();
}
});
});
});
The first two executeScript work fine. But the last two (selectMenu part) do not work. Nothing occurs.
UPDATE
When add this code to the window itself, it works and the select box value is changed:
jQuery("#lang option[value='zh-TW']").attr("selected","selected");
jQuery('#lang').change();
However, when I add it inside executeScript in the parent window (opener), it does not work!
As the code works when I paste it directly in the child window inside jQuery(document).ready(function(), I assumed it should work from the parent window using executeScript. After many trial and error experiments, the following code worked for me:
loginWindow.executeScript(
{
code: "jQuery('#lang option[value=zh-TW]').attr('selected','selected'), jQuery('#lang').change()"
});
Which is the same code I mentioned in "Update" part of my question, except the difference in single quote and double quote. Here using executeScript, I had to manipulate to use double quote only to enclose the entire injected code, the rest I use single quote.
The code above, change the option selected in select box in child window using executeScript method in parent window (opener).

Best way to silently bind window resize event to jQuery plugin without keeping a reference to the targeted element

I'm looking for best-practice advice.
I'm writing a small jQuery plugin to manage horizontal scroll on elements.
I need all the dom elements targeted by that plugin to update on window resize.
Fact is, my website is a full ajax 'app' so when I remove DOM elements, I need them gone so memory doesn't leak.
But I can't find a way to bind the resize event without keeping a reference to the DOM node.
EDIT :
Actually I need the resize handler to get the plugin-targeted elements at 'call' time, coz I don't want to keep any reference to those elements in memory, because I might call .html('') on a parent of theirs...
I did not paste all my code, just an empty shell. I already have a destroy method that unbinds handlers. But I'm generating, removing and appending html nodes dynamically and I the the elements targeted by the plugin to remove silently.
Kevin B stated I could override jQuery .remove method to deal with the handlers, but would have to load jQuery UI for it to work. I don't want that either..
Here is what I tried (attempts commented):
(function($) {
// SOLUTION 2 (see below too)
// Not good either coz elements are not removed until resize is triggered
/*
var hScrolls = $([]);
$(window).bind('resize.hScroll',function(){
if(!hScrolls.length) return;
hScrolls.each(function(){
if($(this).data('hScroll')) $(this).hScroll('updateDimensions');
else hScrolls = hScrolls.not($(this));
});
});
*/
// END SOLUTION 2
// SOLUTION 3 (not implemented but I think I'm on the right path)
$(window).bind('resize.hScroll',function(){
// need to get hScroll'ed elements via selector...
$('[data-hScroll]').hScroll('updateDimensions');
// I don't know how....
});
// END SOLUTION 3
var methods = {
init : function(options) {
var settings = $.extend( {
defaults: true
}, options);
return this.each(function() {
var $this = $(this),
data = $this.data('hScroll');
if (!data) {
$this.data('hScroll', {
target: $this
});
// SOLUTION 1
// This is not good: it keeps a reference to $this when I remove it...
/*
$(window).bind('resize.hScroll', function(){
$this.hScroll('updateDimensions');
});
*/
// END SOLUTION 1
$this.hScroll('updateDimensions');
// SOLUTION 2 (see above too)
hScrolls = hScrolls.add(this);
}
});
},
updateDimensions: function(){
var hScroll = this.data('hScroll');
// do stuff with hScroll.target
}
}
$.fn.hScroll = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if ( typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.hScroll');
}
};
})(jQuery);​
Thanks all in advance!
jQuery calls cleanData any time you do something that removes or replaces elements (yes, even if you use parent.html("") ). You can take advantage of that by extending it and having it trigger an event on the target elements.
// This is taken from https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 10/17/2012
if (!$.widget) { // prevent duplicating if jQuery ui widget is already included
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
try {
$( elem ).triggerHandler( "remove" );
// http://bugs.jquery.com/ticket/8235
} catch( e ) {}
}
_cleanData( elems );
};
}
Now you can bind to the remove event when setting up your plugin and have it run your destroy method.
$(elem).bind("remove",methods.destroy)
You might use a class name and forward the resize event:
$.fn.hScroll = function(method) {
this
.addClass('hScroll')
.data('method', arguments)
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$(".hScroll").each(function(){
var method_config = $(this).data('method');
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
// Would alert "hey you" for <a class="test">you</a> on every resize
Update
If you change the dom and want to keep the selector you might try this one:
var elements = [];
$.fn.hScroll = function(method) {
elements.push({'selector' : this.selector, 'arguments' : arguments });
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$.each(elements,function(i, element){
$(element.selector).each(function(){
var method_config = element.arguments;
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
$(document.body).html("<a class='test'>you</a>");
// Would alert "hey you" for every window resize
You should have the scroll event bound in the extension. Also, you will want to add a "destroy" method to your extension as well. Before you remove the element from the DOM, you will want to call this method. Inside the detroy method is where you will want to unbind the resize event.
One important thing in making this work is that you have a reference to each handler method that is bound to the resize event. Alternatively, you can unbind All resize events upon the removal on an element and then rebind the scroll event to the remaining elements that require it.

ckeditor add event handler to dialog element

I'm writing a custom dialog/plugin for ckeditor. What I want to know is how I can add an eventlistener to a select box in the dialog, to alert when the selected value has been changed. How can I do this?
I've looked at the API and I've come across some useful information but it is not detailed enough. I can't make a connection between the API information and what I am trying to implement.
The select elements in the dialogs automatically fire a change event when they are changed. You can add an onChange function in the definition for the select element. Here's an example from the api:
onChange : function( api ) {
// this = CKEDITOR.ui.dialog.select
alert( 'Current value: ' + this.getValue() );
}
These pages have examples for creating definitions used by dialogs and ui elements:
Class CKEDITOR.dialog
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.html
Class CKEDITOR.dialog.definition
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.definition.html
Class CKEDITOR.dialog.definition.select
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.definition.select.html
If you would like to listen for a change to a select element from another location, you can create a listener that keys on the "dialogShow" event. Here's an example:
// Watch for the "dialogShow" event to be fired in the editor,
// when it's fired, perform this function
editor.on( 'dialogShow', function( dialogShowEvent )
{
// Get any data that was sent when the "fire" method fired the dialogShow event
var dialogShowEventData = dialogShowEvent.data;
// Get the dialog name from the array of data
// that was sent when the event was fired
var currentDialogName = dialogShowEventData._.name;
alert( currentDialogName );
// Create a reference to a particular element (ELEMENT-ID)
// located on a particular tab (TAB-ID) of the dialog that was shown.
var selectorObj = dialogShowEventData._.contents.TAB-ID.ELEMENT-ID;
// Watch for the "change" event to be fired for the element you
// created a reference to (a select element in this case).
selectorObj.on( 'change', function( changeEvent )
{
alert("selectorObj Changed");
});
});
You can check if the dialog you want to work with is the one that fired the "dialogShow" event. If so, you can create an object for the select element you're interested in and listen for a "change" event.
Note: the TAB-ID and ELEMENT-ID placeholders I used do not refer to the Id attribute of the element. The Id refers to the Id assigned in the dialog definition file. The Id attribute for the various elements are different each time the dialog is loaded.
This page has some info on events:
Class CKEDITOR.event
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.event.html
Be Well,
Joe
Answers to additional questions asked in comments:
Q1) Your event here is 'dialogShow', what other events are allowed? i.e are they pre-defined or user defined?
A1) The 'dialogShow' event is predefined. You can look at the file containing the dialogs code in your CKEditor install directory or on the website:
ckeditor\_source\plugins\dialog\plugin.js
http://docs.cksource.com/ckeditor_api/symbols/src/plugins_dialog_plugin.js.html
If you search the file for 'fire', you'll see all the events that are fired for dialogs. The end of the file has definitions for the various events.
You can also define your own events to key on by using the "fire" method in your dialog code:
this.fire( 'yourEventNameHere', { yourPropertyOne : "propertyOneValue", yourPropertyTwo : "propertyTwoValue" } );
Then watch for it:
editor.on( 'yourEventNameHere', function( eventProperties )
{
var propOne = eventProperties.data.yourPropertyOne; // propOne = "propertyOneValue"
var propTwo = eventProperties.data.yourPropertyTwo; // propTwo = "propertyTwoValue"
Do something here...
});
Q2) Can you explain the syntax dialogShowEventData._.name ? I've seen it before but i don't know the significance, something to do with private variables?
A2) For anyone wondering about the "._." syntax used in the CKEditor code, it's used to reduce the size of the code and replaces ".private." See this post by #AlfonsoML in the CKEditor forum:
http://cksource.com/forums/viewtopic.php?t=22982
Q3) Where can i get more info on TAB-ID.ELEMENT-ID?
A3) The Tab-ID is the id that you assign to a particular tab (pane) of a dialog. ( see below: id : 'tab1', )
The Element-ID is the id that you assign to a particular element contained in a tab in your dialog. ( see below: id : 'textareaId', )
Look at this page: http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.html#.add
It shows how you define the tabs and elements contained in a dialog window ( I added an example of a select element that fires a user defined event ):
var dialogDefinition =
contents : [
{
id : 'tab1',
label : 'Label',
title : 'Title',
expand : true,
padding : 0,
elements :
[
{
type : 'html',
html : '<p>This is some sample HTML content.</p>'
},
{
type : 'textarea',
id : 'textareaId',
rows : 4,
cols : 40
},
// Here's an example of a select element:
{
type : 'select',
id : 'sport',
label : 'Select your favourite sport',
items : [ [ 'Basketball' ], [ 'Baseball' ], [ 'Hockey' ], [ 'Football' ] ],
'default' : 'Football',
onChange : function( api ) {
// this = CKEDITOR.ui.dialog.select
alert( 'Current value: ' + this.getValue() );
// CKEditor automatically fires a "change" event here, but
// here's an example of firing your own event
this.fire( 'sportSelector', { sportSelectorPropertyOne : "propertyOneInfo" } );
}
]
}
],
Q4) Can you briefly explain what the above code is doing?
A4) See the original code, I've added comments.
You can use blur event of the editor, it is being fired whenever the window is opened.
editor.on( 'blur', function( dialogShowEvent ) {
//Add your logic here for the change event of select element
});

Categories