implementing a callback in TimelineJS - javascript

In TimelineJS I want to implement a callback that would be fired every time the slide (the main panel in the center) changes whether that change happens by clicking on the "right" or "left" buttons on the sides, or by clicking on an event in the timeline in the bottom time panel. I could not find any information on such a callback other than a reference to it in Issue 82 from a year ago.
Suggestions on how to start with this? (In other words, I have no idea even where to begin).

Timeline JS fires an event whenever it is updated, the code is at line 5274 of the latest version:
function upDate() {
config.current_slide = current_slide;
VMM.fireEvent(layout, "UPDATE");
};
The code for fireEvent is:
VMM.fireEvent = function(element, the_event_type, the_data) {
var e;
var _event_type = "click";
var _data = [];
if (the_event_type != null && the_event_type != "") {
_event_type = the_event_type;
}
if (the_data != null && the_data != "") {
_data = the_data;
}
if( typeof( jQuery ) != 'undefined' ){
jQuery(element).trigger(_event_type, _data);
//return e;
}
};
Then important part there is:
jQuery(element).trigger(_event_type, _data);
So, all you need to do is figure out what element layout is, so I would temporatily edit the upDate function to:
function upDate() {
console.log($(layout).attr('id') + ' : ' + $(layout).attr('class'));
config.current_slide = current_slide;
VMM.fireEvent(layout, "UPDATE");
};
And see what it logs for the class / id of the element. Then, say it comes back with the class being 'timeline', for example, you would write something like this:
$('.timeline').on("UPDATE", function() {
your_function_that_does_whatever_you_need();
});

Related

Javascript: managing clicks from one instance to the next

I am very new to Javascript.
I am trying to write this baby jQuery plugin that I will use to make dropdown lists. What I am failing to achieve (beyond things that I do not notice) is to neatly exit or deactivate my active instance as I click on another instance. I tried to illustrate my problem in the following fiddle (keeping the structure I am using):
https://jsfiddle.net/andinse/m0kwfj9d/23/
What the Javascript looks like:
$(document).ready(function() {
$.fn.activator = function() {
var Activator = function(el) {
this.html = $('html');
this.el = el;
this.is_active = false;
this.initialize();
};
Activator.prototype.initialize = function() {
var self = this;
self.el.on('click', function(e) {
if (self.is_active === false) {
self.toggle('activate');
} else {
self.toggle('deactivate');
}
});
};
Activator.prototype.toggle = function(action) {
var self = this;
if (action === 'activate') {
console.log('activating ' + self.el[0].className);
self.is_active = true;
self.el.addClass('red');
self.html.on('click', function(e) {
if (e.target != self.el[0]) {
self.toggle('deactivate');
}
});
}
if (action === 'deactivate') {
console.log('deactivating ' + self.el[0].className);
self.is_active = false;
self.el.removeClass('red');
self.html.off('click');
}
};
if (typeof this !== 'undefined') {
var activator = new Activator(this);
}
return this;
};
$('.a').activator();
$('.b').activator();
$('.c').activator();
});
My idea was:
To watch for clicks on html as soon as the instance is active (thus ready to be deactivated). On click, to check if the event.target is the same as the active instance. If not, to deactivate this instance.
To stop watching for clicks as soon as the instance is inactive. So that we're not doing unnecessary work.
When it is set like this, it seems to work for only one cycle (click on A activates A then click on B activates B and deactivates A then click on C activates C but doesn't deactivate B).
If I get rid of the "self.html.off('click')" it seems to work kind of ok but if I look at the log I can see the "toggle" function is sometimes triggered multiple times per click. There must be a cleaner way.
Any piece of help greatly appreciated.
With your logic, when clicking any element you should deactivate any current activated element. Either do it globally:
$('.your_activation_class').removeClass('.your_activation_class');
or in some parent scope
$('some_parent_selector .your_activation_class').removeClass('.your_activation_class');

How to execute a function when clicking an area inside an object?

I created an object with map Areas by using DOM-Elements. Now I want to execute a function when clicked on an area(coordinates). I think I also Need to check the area if it is clicked or not ? Also I think I'm missing something on the DOM-Element.
var _images = { //Object-MapArea
start: {
path: 'start.jpg',
areas: [{
coords: '18,131,113,140',
text: 'Homepage',
onclick: doSomething, // ???
}]
},
}
// ..... there is more code not shown here
//Creating DOM-Elements
var areaElem = document.createElement('AREA');
// Set attributes
areaElem.coords = area.coords;
areaElem.setAttribute('link', area.goto);
areaElem.setAttribute("title", area.text);
areaElem.setAttribute("shape", "rect");
areaElem.onclick = doSomething; ? ? ?
if (element.captureEvents) element.captureEvents(Event.CLICK); ? ? ?
areaElem.addEventListener('click', onArea_click);
_map.appendChild(areaElem);
function doSomething(e) {
if (!e) var e = window.event
e.target = ... ? ?
var r = confirm("Data will get lost!");
if (r == true) {
window.open("homepage.html", "_parent");
} else {
window.open(" ", "_parent"); // here I want to stay in the current pictures. I mean the current object map area. But how can I refer to it so it stays there ?
}
}
See the comments I added to your code ;)
var _images = { //Object-MapArea
start: {
path: 'start.jpg',
areas: [{
coords: '18,131,113,140',
text: 'Homepage',
clickHandler: doSomething // I changed the name to avoid confusion but you can keep onclick
}]
},
}
// ..... there is more code not shown here
//Creating DOM-Elements
var areaElem = document.createElement('AREA');
// Set attributes
areaElem.coords = area.coords;
areaElem.setAttribute('link', area.goto);
areaElem.setAttribute("title", area.text);
areaElem.setAttribute("shape", "rect");
// Add a listener on click event (using the function you defined in the area object above)
areaElem.addEventListener('click', area.clickHandler);
// Add your other click handler
areaElem.addEventListener('click', onArea_click);
_map.appendChild(areaElem);
function doSomething(e) {
// Get the area clicked
var areaClicked = e.target;
// I dont understand the following code...
var r = confirm("Data will get lost!");
if (r == true) {
window.open("homepage.html", "_parent");
} else {
window.open(" ", "_parent"); // here I want to stay in the current pictures. I mean the current object map area. But how can I refer to it so it stays there ?
}
}
Hope it helps ;)
I think I also Need to check the area if it is clicked or not
You are creating an element areaElem and attaching event to the same dom.
So there may not be need of any more check
You may not need to add both onclick & addEventListner on same element and for same event. Either onclick function or addEventListener will be sufficient to handle the event.
areaElem.onclick = function(event){
// Rest of the code
// put an alert to validate if this function is responding onclick
}
areaElem.addEventListener('click', onArea_click);
function onArea_click(){
// Rest of the code
}

Template.onRendered() called too early

I have hit a strange problem. I am using hammer.js to configure long-press events, and attaching the event watcher within the Template.onRendered() callback. This works perfectly on my local development machine. However, when I deploy to a server, it seems that onRendered() is being fired before the template is finished rendering in the browser. The jQuery selector is empty. I've had to resort to setting a timer to make sure the template is rendered before configuring the event handler. Alternatively, I've tried configuring the event handler within a Tracker.afterFlush() in place of setTimeout(), but the template is still not rendered when this fires.
It seems that I shouldn't have to use setTimeout() here. Am I doing something wrong or out of order?
Template.CATEGORIES.onRendered(function () {
Meteor.setTimeout(function () {
console.log('setting up hammer object', this.$('.collapsible'));
var h = this.$('.collapsible').hammer({domEvents:true});
h.on('tap press swipe pan', '.collapsible-header', function (ev) {
// get the ID of the shopping list item object
var target = ev.target;
var $target = $(target);
var type = ev.type;
var $header = $target;
if (Collapse.isChildrenOfPanelHeader($target)) {
$header = Collapse.getPanelHeader($target);
}
console.log('Firing ', type, ' on ', $header);
Kadira.trackError('debug', 'Firing ' + type + ' on ' + $header);
// handler for checkbox
if (type === 'tap' && $target.is('label')) {
var data = Blaze.getData(target);
var TS = data.checkedTS;
ev.preventDefault();
data.checked = !data.checked;
console.log('Checkbox handler', data);
if (data.checked && !TS) {
TS = new Date()
} else if (!data.checked) {
TS = null
}
// Set the checked property to the opposite of its current value
ShoppingList.update(data._id, {
$set: {checked: data.checked, checkedTS: TS}
});
} else if (type === 'tap' && $target.has('.badge')) {
// if the user taps anywhere else on an item that has a child with .badge class
// this item has deals. Toggle the expand.
console.log('badge handler');
$header.toggleClass('active');
Collapse.toggleOpen($header);
} else if (type === 'press' || type === 'swipe' || type === 'pan') {
// remove any selected deals
var itemID, item;
var $label = $header.find('label');
console.log('long press handler');
if ($label) {
itemID = $label.attr('for');
item = ShoppingList.findOne(itemID);
if (item && item.deal) {
Deals.update(item.deal._id, {$set: {'showOnItem': false}});
ShoppingList.update(itemID, {$set: {'deal': null}});
}
}
}
})
}, 2000);
});
Someone answered this the other day but must have withdrawn their answer. They suggested that the template was actually rendered, but that the data subscription had not finished replicating yet. They were right.
I was able to validate that I need to wait until the data subscription finishes prior to setting up my java script events.

Jquery bind not working while within a javascript recursive loop

I am writing a piece of code that changes some lights on a screen from red to green randomly and waits for the user to hit the key that corresponds to the light lit.
When I run this code you are able to hit the a,d,j or l key and an alert will pop up. However, as soon as I click the start button no keys are recognised. And when the loop has finished the bind still seems to become disabled. I have tried moving the bind to other places but I have had no joy. Your help is much appreciated.
$( function() {
$('#start').bind('click', function() { main(); });
$(document).bind('keypress', function(e) { keyPress(e); } );
} );
function getRand(val) {
return Math.floor(Math.random()*val)+1;
}
function main() {
preD = new Date;
preDs = preD.getTime();
randTime=Math.floor(Math.random()*1001)+1500;
playSound();
flash();
}
function flash() {
zone = getZone();
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_grn.jpg)");
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_red.jpg)");
if(cond[1] < 8) {
main();
}
} , 200);
} , randTime);
}
function getZone() {
if(condition==1) {
zone = getRand(2);
if( test[1][zone] < 8 ) {
test[1][zone] += 1;
cond[1] += 1;
return zone;
} else {
getZone();
}
}
}
function keyPress(e) {
var evtobj=window.event? event : e //distinguish between IE's explicit event object (window.event) and Firefox's implicit.
var unicode=evtobj.charCode? evtobj.charCode : evtobj.keyCode
var actualkey=String.fromCharCode(unicode)
if (actualkey=="a" || actualkey=="d" || actualkey=="j" || actualkey=="l" ) {
dd = new Date;
reat = dd.getTime();
alert(1);
//keypressed[condition][zone]['k']=actualkey;
//keypressed[condition][zone]['t']=(reat-preDs);
}
}
The reason that this could be happening is, when you generate code dynamically or alter any existing code the bind needs to be done again, because the function to bind just runs once and only for the members already created. So when you create dynamically code, you are forced to run the binding function to recognize the new elements.
this ways is not very recommended, instead of this, you could bind a container like 'div' or something and inside of this validate which element is calling you. This will work because your container is created once and the binding is properly assigned and doesn't matter if the content of your container changes, the binding always work.
Regards
Using a jquery sound plugin was the answer.
Fixed it with this : plugins.jquery.com/project/sound_plugin

AsyncFileUpload has logic error in AjaxControlToolkit, when component in a different tab, so not displayed

I am using the Nov version of the AjaxControlToolkit, and I found a logic error, but I am trying to figure out the best way to fix this, by Saturday, so that the program will work on IE.
This problem only has an error on IE, it works on Firefox3.5.
I have a AsyncFileUpload component on a tab that appears to not be visible when this function runs, and so the offset width is zero.
The problem is in the file AsyncFileUpload.pre.js, in function _app_onload, and this line:
this._innerTB.style.width = (this._inputFile.offsetWidth - 107) + "px";
I don't want to compile it from the source, but this may end up being my best option, so I can fix the error.
But, this is probably going to be my fix:
this._innerTB.style.width = ((this._inputFile.offsetWidth == 0) ? 200 : this._inputFile.offsetWidth) - 107) + "px";
But, I don't know if there is a better solution.
I could just write a new prototype function in my javascript class and just fix the logic error, which is better than recompiling. If I fix it in the code, then whenever I do an update I will need to keep replacing that line, until it gets fixed in the codebase.
But, I am trying to figure out if there is a way for an element to know that it has just become visible, as anytime you need to know the actual width of an element then you can't really set it up until it is displayed. I can't think of a way to know that, so what I tend to do is fix the elements on the tab the first time the tab is selected, but, for a generic library that is not a possible solution.
Location of the main question
So, before I send in a bug report about this I am curious if there is a better way to do it, rather than having it done when the page has been loaded, and assuming a minimum width that is probably wrong. <-- Question located here
I am using the follow code to create the element:
<cc1:AsyncFileUpload ID="AsyncFileUpload1" runat="server"
OnClientUploadError="uploadError" OnClientUploadStarted="StartUpload"
OnClientUploadComplete="UploadComplete"
CompleteBackColor="Lime" UploaderStyle="Modern" Width="400px"
ErrorBackColor="Red" ThrobberID="Throbber"
onuploadedcomplete="AsyncFileUpload1_UploadedComplete"
UploadingBackColor="#66CCFF" />
And if it makes any difference I am using this as the ToolkitScriptManager seemed to introduce other errors, but that may have been my error:
<ajax:AjaxScriptManager ID="scriptmanager1" runat="server" EnablePartialRendering="true" ></ajax:AjaxScriptManager>
I am not certain if LoadScriptsBeforeUI would be useful, but I believe that I want the UI done before the scripts are loaded actually.
I find it interesting that the width I set isn't actually set when the dom tree is completed.
try add this attribute to your scriptmanager
LoadScriptsBeforeUI="true"
I have download the source code and fix the codeline,but it still not working,
then I add this attr to the scriptmanager,it works !!
check this page for detail if U wanna change the source code
http://ajaxcontroltoolkit.codeplex.com/SourceControl/network/Forks/keyoke/AyncFileUploadFix/changeset/changes/30da4b8d1c6d
This is the solution that's worked for me:
Apply CssClass on ajaxToolkit:AsyncFileUpload like "imageUploaderField"
Write Css .imageUploaderField input{width:100%!important;}
Source: http://ajaxcontroltoolkit.codeplex.com/workitem/27429
This isn't the ideal solution, but it does work, hopefully someone will have a better solution, as this is something I cannot submit to fix the bug. I added this to a javascript file of mine, but it is a hack, not a good solution. I had to replace the second function because of the line I commented out.
$(document).ready(function() {
Sys.Extended.UI.AsyncFileUpload.prototype._app_onload = function(sender, e) {
this.setThrobber(false);
if (this._inputFile != null) {
if (this._onchange$delegate == null) {
this._onchange$delegate = Function.createDelegate(this, this._onchange);
$addHandlers(this._inputFile, {
change: this._onchange$delegate
});
}
if (Sys.Browser.agent == Sys.Browser.Firefox) {
this._inputFile.size = 0;
var width = this._inputFile.offsetWidth;
this._inputFile.style.width = "";
while (this._inputFile.offsetWidth < width) {
this._inputFile.size++;
}
}
if (this._innerTB != null) {
this._inputFile.blur();
var inputFile = this._inputFile;
setTimeout(function() { inputFile.blur(); }, 0);
this._innerTB.style.width = ((this._inputFile.offsetWidth == 0 ? 200 : this._inputFile.offsetWidth) - 107) + "px";
this._inputFile.parentNode.style.width = this._inputFile.offsetWidth + "px";
if (Sys.Browser.agent == Sys.Browser.InternetExplorer) {
this._onmouseup$delegate = Function.createDelegate(this, this._onmouseup);
$addHandlers(this._inputFile, {
mouseup: this._onmouseup$delegate
});
}
}
}
};
Sys.UI.DomEvent.prototype._removeHandler = function (elements, eventName, handler) {
Sys._queryAll(elements, function(element) {
var browserHandler = null;
// if ((typeof (element._events) !== 'object') || !element._events) throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
var cache = element._events[eventName];
if (!(cache instanceof Array)) throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
for (var i = 0, l = cache.length; i < l; i++) {
if (cache[i].handler === handler) {
browserHandler = cache[i].browserHandler;
break;
}
}
if (typeof (browserHandler) !== 'function') throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
if (element.removeEventListener) {
element.removeEventListener(eventName, browserHandler, false);
}
else if (element.detachEvent) {
element.detachEvent('on' + eventName, browserHandler);
}
cache.splice(i, 1);
});
}
My Solution... probably not the best but works.
_app_onload: function(sender, e) {
this.setThrobber(false);
if (this._inputFile != null) {
if (this._onchange$delegate == null) {
this._onchange$delegate = Function.createDelegate(this, this._onchange);
$addHandlers(this._inputFile, {
change: this._onchange$delegate
});
}
if (Sys.Browser.agent == Sys.Browser.Firefox) {
this._inputFile.size = 0;
var width = this._inputFile.offsetWidth;
this._inputFile.style.width = "";
while (this._inputFile.offsetWidth < width) {
this._inputFile.size++;
}
}
if (this._innerTB != null) {
this._inputFile.blur();
var inputFile = this._inputFile;
setTimeout(function() { inputFile.blur(); }, 0);
if ((this._inputFile.offsetWidth - 107) >= 1) {
this._innerTB.style.width = (this._inputFile.offsetWidth - 107) + "px";
this._inputFile.parentNode.style.width = this._inputFile.offsetWidth + "px";
}
if (Sys.Browser.agent == Sys.Browser.InternetExplorer) {
this._onmouseup$delegate = Function.createDelegate(this, this._onmouseup);
$addHandlers(this._inputFile, {
mouseup: this._onmouseup$delegate
});
}
}
}
},
have forked at http://ajaxcontroltoolkit.codeplex.com/SourceControl/network/Forks/keyoke/AyncFileUploadFix

Categories

Resources