I'm having some trouble with this website I am building. I am modifying the existing pre-loader to have a button before continuing on to the home page. The issue is I can't point the button click to the correct function for a reason that i really can't figure out. Here is the appropriate code:
Revision: Just to clarify, I'm aiming to get this button click to replicate the function performed in the final code extract: this.parent.endLoader(); but am not having any success.
The click:
<script>
$(document).on('click', '.qLbtns', function(){
$(this).EndLoader();
});
</script>
The js bind:
$.fn.EndLoader = function(){
return this.each(function(){
this.endLoader();
});
};
The function i am trying to point to:
QueryLoader2.prototype.endLoader = function () {
this.destroyed = true;
this.onLoadComplete();
};
Which is effective within this function:
PreloadImage.prototype.completeLoading = function () {
this.parent.imageDone++;
var percentage = (this.parent.imageDone / this.parent.imageCounter) * 100;
this.parent.overlayLoader.updatePercentage(percentage);
if (this.parent.imageDone == this.parent.imageCounter || percentage >= 100) {
this.parent.endLoader();
}
};
Related
I am developing a product detail page with the plugin called Infinite Options by ShopPad.
I am trying to add HTML elements into the DOM generated by it, but it takes about 1 - 2 seconds after the page displays.
So I tried this way:
$(window).on('load', function () {
function retry() {
var $pluginHTML = $('.plugin ul');
if (!$pluginHTML.length) return setTimeout(retry, 2000);
$pluginHTML.css('fontColor','red');
}
retry();
});
It normally works well, but this is not the best solution.
Somebody knows if Infinite Options provides with callback function of JavaScript?
Infinite Options contains a callback function you can tie into that is defined at window.Shoppad.apps.infiniteoptions.ready.
For example:
<script>
window.Shoppad = window.Shoppad || {},
window.Shoppad.apps = window.Shoppad.apps || {},
window.Shoppad.apps.infiniteoptions = window.Shoppad.apps.infiniteoptions || {},
window.Shoppad.apps.infiniteoptions.ready = function() {
console.log('app loaded');
};
</script>
Thank you for the previous (deleted by moderator) explanation and the simple implementation but it does not work out for me. The 'holdit' function works but it is not is not steady probably because there is an 'onmouseup' in the 'holdit' function too, Even if I disable the onmouseup at the HTML button it's not very steady. Maybe it's better to use an addEventListener- onmousedown-interval function but again I don't know how to implement it in the simplest possible way. Here's the complete function that shows a pressed button and increases the timeSeconds var by one. For safety the var. number is within a limit.
Please help.
HTML:
<img id="but4" class="button" src= "//:0" onmousedown="timesecPlus();"onmouseup="timesecPlsUp();"/>
JAVASCRIPT:
function timesecPlus() {
var pmknop = document.getElementById('but5');
pmknop.src = secminBtndwn; //inline Base64 data: button image down (pressed)
timeSeconds = ((timeSeconds>wedstrijdperiode.seconden-6)?(timeSeconds):(++timeSeconds)); //You can ++ chase-back the timeseconds until 5 sec's from period start-time
displayTime( timeSeconds );
};
function timesecPlsUp() {
var pmknop = document.getElementById('but5');
pmknop.src = secminBtn; //inline Base64 data: button image up (normal)
};
// Things I tried:
//holdit(pmknop, function () { ++timeSeconds ; displayTime( timeSeconds );}, 2000, 2);
//pmknop = pmknop.addEventListener('mousedown', function() { interval = setInterval(timesecPlus (), 2000); });
function holdit(btn, action, start, speedup) {
var t;
var repeat = function () {
action();
t = setTimeout(repeat, start);
start = start / speedup;
}
btn.onmousedown = function() {
repeat();
}
btn.onmouseup = function () {
clearTimeout(t);
}
};
The holdit function is taking four variables. The first: btn, is the button id. This is used to determine the action performed whenever the mouse is clicked.
The second variable is a reference to a function. Its called a callback function, since you will be passing a function that will be Caaalleed whenever you call holdit.
The last two variables simply determine when and how long to delay the execution of the repetition and and by how much each repetition will speed up by.
var repeat = function () {
action();
t = setTimeout(repeat, start);
start = start / speedup;
}
Repeat is a recursive function that will be called after 'start' number of milliseconds and be repeated more frequently after each iteration.
Simple implementation:
var btn = document.getElementsByClassName('button')[0];
holdit(btn, function () { timeSeconds++ ; displayTime( timeSeconds );}, 1000, 2);
Implementation without holdit:
var btn = document.getElementsByClassName('button')[0];
var couterFunc, couter=0;
btn.addEventListener('mousedown',function(){couterFunc = setInterval(update,1000); update()})
btn.addEventListener('mouseup',function(){clearInterval(couterFunc)})
/* function that will fire when button press*/
function update(){console.log(++couter)};
Since people are misunderstanding my wording, I will rewrite it, I want "with the following code below" to ignore the function which i have commented on below in my jquery if it happened in the last "X" seconds.
Here is my code.
EDIT:: Please write answers in reference to this, example. "the script ignores the change in class and the delay wont work" http://www.w3schools.com/code/tryit.asp?filename=FBC4LK96GO6H
Sorry for confusing everyone including myself.
Edited due to author's post update.
You can create custon event. By this function you will define: "delayedClick" event on the selected objects.
function delayedClickable(selector, delayTime){
$(document).ready(function(){
$(selector).each(function () {
var lastTimeFired = 0;
$(this).click(function(){
if(Date.now() - delayTime > lastTimeFired) {
lastTimeFired = Date.now();
$(this).trigger('delayedClick');
}
});
});
});
}
Remeber that you should define delayTime and this event on selected elements by:
var delayTime = 3 * 1000; // 3 sec delay between firing action
delayedClickable('.Img2', delayTime);
And then just use your event on elements. For example click event can be used in that way:
$element.on('click', function () {
// ...
});
And your custom delayedClick event should be used in that way:
$element.on('delayedEvent', function () {
// ...
});
Full example:
http://www.w3schools.com/code/tryit.asp?filename=FBC56VJ9JCA5
#UPDATE
I've found some another tricky way to keep using click function and makes it works as expected:
function delayedClickable(selector, delayTime){
$(document).ready(function(){
$(selector).each(function () {
var scope = this;
$(this).click(function(){
scope.style.pointerEvents = 'none';
setTimeout(function () {
scope.style.pointerEvents = 'auto';
}, delayTime);
});
});
});
}
And then
var delayTime = 3 * 1000; // 3 sec delay between firing action
delayedClickable('.Img2', delayTime);
That's all.
The key of second way is that we are disabling any pointer event on element when clicked and then after timeout we're turning these events back to work.
https://developer.mozilla.org/en/docs/Web/CSS/pointer-events
And full example:
http://www.w3schools.com/code/tryit.asp?filename=FBC678H21H5F
Can use setTimeout() to change a flag variable and a conditional to check flag in the event handler
var allowClick = true,
delaySeconds = 5;
$(".element1").click(function(){
if(!allowClick){
return; // do nothing and don't proceed
}
allowClick = false;
setTimeout(function(){
allowClick = true;
}, delaySeconds * 1000 );
// other element operations
})
I asked this question yesterday hopefully this one is clearer as I've now provided a working example of my store.
I'm developing a Shopify Theme. I've been using Timber as my base and I'm currently having a problem with my Quick Cart and Quick Shop/View drawers.
I have 2 drawers on the right of my site, 1 for the cart and 1 for the product quick view option. The drawers currently slide open - #PageContainer moves to the left on click to reveal each drawer.
As they are currently sitting on top of each other I need to alter the JS so that on click the z-index changes so that the correct drawer being called is highest in the stack.
I'm not great with JS so not sure if this is a simple task?
Here is a link to my Dev Store
JS:
timber.Drawers = (function () {
var Drawer = function (id, position, options) {
var defaults = {
close: '.js-drawer-close',
open: '.js-drawer-open-' + position,
openClass: 'js-drawer-open',
dirOpenClass: 'js-drawer-open-' + position
};
this.$nodes = {
parent: $('body, html'),
page: $('#PageContainer'),
moved: $('.is-moved-by-drawer')
};
this.config = $.extend(defaults, options);
this.position = position;
this.$drawer = $('#' + id);
if (!this.$drawer.length) {
return false;
}
this.drawerIsOpen = false;
this.init();
};
Drawer.prototype.init = function () {
$(this.config.open).on('click', $.proxy(this.open, this));
this.$drawer.find(this.config.close).on('click', $.proxy(this.close, this));
};
Drawer.prototype.open = function (evt) {
// Keep track if drawer was opened from a click, or called by another function
var externalCall = false;
// Prevent following href if link is clicked
if (evt) {
evt.preventDefault();
} else {
externalCall = true;
}
// Without this, the drawer opens, the click event bubbles up to $nodes.page
// which closes the drawer.
if (evt && evt.stopPropagation) {
evt.stopPropagation();
// save the source of the click, we'll focus to this on close
this.$activeSource = $(evt.currentTarget);
}
if (this.drawerIsOpen && !externalCall) {
return this.close();
}
// Add is-transitioning class to moved elements on open so drawer can have
// transition for close animation
this.$nodes.moved.addClass('is-transitioning');
this.$drawer.prepareTransition();
this.$nodes.parent.addClass(this.config.openClass + ' ' + this.config.dirOpenClass);
this.drawerIsOpen = true;
// Run function when draw opens if set
if (this.config.onDrawerOpen && typeof(this.config.onDrawerOpen) == 'function') {
if (!externalCall) {
this.config.onDrawerOpen();
}
}
if (this.$activeSource && this.$activeSource.attr('aria-expanded')) {
this.$activeSource.attr('aria-expanded', 'true');
}
// Lock scrolling on mobile
this.$nodes.page.on('touchmove.drawer', function () {
return false;
});
this.$nodes.page.on('click.drawer', $.proxy(function () {
this.close();
return false;
}, this));
};
Drawer.prototype.close = function () {
if (!this.drawerIsOpen) { // don't close a closed drawer
return;
}
// deselect any focused form elements
$(document.activeElement).trigger('blur');
// Ensure closing transition is applied to moved elements, like the nav
this.$nodes.moved.prepareTransition({ disableExisting: true });
this.$drawer.prepareTransition({ disableExisting: true });
this.$nodes.parent.removeClass(this.config.dirOpenClass + ' ' + this.config.openClass);
this.drawerIsOpen = false;
this.$nodes.page.off('.drawer');
};
return Drawer;
})();
Update
As instructed by Ciprian I have placed the following in my JS which is making the #CartDrawer have a higher z-index. I'm now unsure how I adapt this so that it knows which one to have higher dependant on which button is clicked. This is what I've tried:
...
Drawer.prototype.init = function () {
$(this.config.open).on('click', $.proxy(this.open, this));
$('.js-drawer-open-right-two').click(function(){
$(this).data('clicked', true);
});
if($('.js-drawer-open-right-two').data('clicked')) {
//clicked element, do-some-stuff
$('#QuickShopDrawer').css('z-index', '999');
} else {
//run function 2
$('#CartDrawer').css('z-index', '999');
}
this.$drawer.find(this.config.close).on('click', $.proxy(this.close, this));
};
...
The approach would be like this:
$('.yourselector').css('z-index', '999');
Add it (and adapt it to your needs) inside your onclick() function.
if you need to modify the z-index of your div when clicking a buton, you shoud put in this code on your onclick() function, else if you need to activate it when you looding the page you shoud put it on a $( document ).ready() function , the code is :
$('#yourID').css('z-index', '10');
You can use:
document.getElementById("your-element-id").style.zIndex = 5;
It's pure Javascript and sets the z-index to 5. Just bind this to onClick event!
I have a responsive template that I am trying to use with my Angularjs app. This is also my first Angular app so I know I have many mistakes and re-factoring in my future.
I have read enough about angular that I know DOM manipulations are suppose to go inside a directive.
I have a javascript object responsible for template re-sizes the side menu and basically the outer shell of the template. I moved all of this code into a directive and named it responsive-theme.
First I added all the methods that are being used and then I defined the App object at the bottom. I removed the function bodies to shorten the code.
Basically the object at the bottom is a helper object to use with all the methods.
var directive = angular.module('bac.directive-manager');
directive.directive('responsiveTheme', function() {
return {
restrict: "A",
link: function($scope, element, attrs) {
// IE mode
var isRTL = false;
var isIE8 = false;
var isIE9 = false;
var isIE10 = false;
var sidebarWidth = 225;
var sidebarCollapsedWidth = 35;
var responsiveHandlers = [];
// theme layout color set
var layoutColorCodes = {
};
// last popep popover
var lastPopedPopover;
var handleInit = function() {
};
var handleDesktopTabletContents = function () {
};
var handleSidebarState = function () {
};
var runResponsiveHandlers = function () {
};
var handleResponsive = function () {
};
var handleResponsiveOnInit = function () {
};
var handleResponsiveOnResize = function () {
};
var handleSidebarAndContentHeight = function () {
};
var handleSidebarMenu = function () {
};
var _calculateFixedSidebarViewportHeight = function () {
};
var handleFixedSidebar = function () {
};
var handleFixedSidebarHoverable = function () {
};
var handleSidebarToggler = function () {
};
var handleHorizontalMenu = function () {
};
var handleGoTop = function () {
};
var handlePortletTools = function () {
};
var handleUniform = function () {
};
var handleAccordions = function () {
};
var handleTabs = function () {
};
var handleScrollers = function () {
};
var handleTooltips = function () {
};
var handleDropdowns = function () {
};
var handleModal = function () {
};
var handlePopovers = function () {
};
var handleChoosenSelect = function () {
};
var handleFancybox = function () {
};
var handleTheme = function () {
};
var handleFixInputPlaceholderForIE = function () {
};
var handleFullScreenMode = function() {
};
$scope.App = {
//main function to initiate template pages
init: function () {
//IMPORTANT!!!: Do not modify the core handlers call order.
//core handlers
handleInit();
handleResponsiveOnResize(); // set and handle responsive
handleUniform();
handleScrollers(); // handles slim scrolling contents
handleResponsiveOnInit(); // handler responsive elements on page load
//layout handlers
handleFixedSidebar(); // handles fixed sidebar menu
handleFixedSidebarHoverable(); // handles fixed sidebar on hover effect
handleSidebarMenu(); // handles main menu
handleHorizontalMenu(); // handles horizontal menu
handleSidebarToggler(); // handles sidebar hide/show
handleFixInputPlaceholderForIE(); // fixes/enables html5 placeholder attribute for IE9, IE8
handleGoTop(); //handles scroll to top functionality in the footer
handleTheme(); // handles style customer tool
//ui component handlers
handlePortletTools(); // handles portlet action bar functionality(refresh, configure, toggle, remove)
handleDropdowns(); // handle dropdowns
handleTabs(); // handle tabs
handleTooltips(); // handle bootstrap tooltips
handlePopovers(); // handles bootstrap popovers
handleAccordions(); //handles accordions
handleChoosenSelect(); // handles bootstrap chosen dropdowns
handleModal();
$scope.App.addResponsiveHandler(handleChoosenSelect); // reinitiate chosen dropdown on main content resize. disable this line if you don't really use chosen dropdowns.
handleFullScreenMode(); // handles full screen
},
fixContentHeight: function () {
handleSidebarAndContentHeight();
},
setLastPopedPopover: function (el) {
lastPopedPopover = el;
},
addResponsiveHandler: function (func) {
responsiveHandlers.push(func);
},
// useful function to make equal height for contacts stand side by side
setEqualHeight: function (els) {
var tallestEl = 0;
els = jQuery(els);
els.each(function () {
var currentHeight = $(this).height();
if (currentHeight > tallestEl) {
tallestColumn = currentHeight;
}
});
els.height(tallestEl);
},
// wrapper function to scroll to an element
scrollTo: function (el, offeset) {
pos = el ? el.offset().top : 0;
jQuery('html,body').animate({
scrollTop: pos + (offeset ? offeset : 0)
}, 'slow');
},
scrollTop: function () {
App.scrollTo();
},
// wrapper function to block element(indicate loading)
blockUI: function (ele, centerY) {
var el = jQuery(ele);
el.block({
message: '<img src="./assets/img/ajax-loading.gif" align="">',
centerY: centerY !== undefined ? centerY : true,
css: {
top: '10%',
border: 'none',
padding: '2px',
backgroundColor: 'none'
},
overlayCSS: {
backgroundColor: '#000',
opacity: 0.05,
cursor: 'wait'
}
});
},
// wrapper function to un-block element(finish loading)
unblockUI: function (el) {
jQuery(el).unblock({
onUnblock: function () {
jQuery(el).removeAttr("style");
}
});
},
// initializes uniform elements
initUniform: function (els) {
if (els) {
jQuery(els).each(function () {
if ($(this).parents(".checker").size() === 0) {
$(this).show();
$(this).uniform();
}
});
} else {
handleUniform();
}
},
updateUniform : function(els) {
$.uniform.update(els);
},
// initializes choosen dropdowns
initChosenSelect: function (els) {
$(els).chosen({
allow_single_deselect: true
});
},
initFancybox: function () {
handleFancybox();
},
getActualVal: function (ele) {
var el = jQuery(ele);
if (el.val() === el.attr("placeholder")) {
return "";
}
return el.val();
},
getURLParameter: function (paramName) {
var searchString = window.location.search.substring(1),
i, val, params = searchString.split("&");
for (i = 0; i < params.length; i++) {
val = params[i].split("=");
if (val[0] == paramName) {
return unescape(val[1]);
}
}
return null;
},
// check for device touch support
isTouchDevice: function () {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
},
isIE8: function () {
return isIE8;
},
isRTL: function () {
return isRTL;
},
getLayoutColorCode: function (name) {
if (layoutColorCodes[name]) {
return layoutColorCodes[name];
} else {
return '';
}
}
};
}
};
});
Originally the App.init() object method would be called at the bottom of any regular html page, and I have others that do certain things also that would be used on specific pages like Login.init() for the login page and so forth.
I did read that stackoverflow post
"Thinking in AngularJS" if I have a jQuery background? and realize that I am trying to go backwards in a sense, but I want to use this template that I have so I need to retro fit this solution.
I am trying to use this directive on my body tag.
<body ui-view="dashboard-shell" responsive-theme>
<div class="page-container">
<div class="page-sidebar nav-collapse collapse" ng-controller="SidemenuController">
<sidemenu></sidemenu>
</div>
<div class="page-content" ui-view="dashboard">
</div>
</div>
</body>
So here is my problem. This kinda sorta works. I don't get any console errors but when I try to use my side menu which the javascript for it is in the directive it doesn't work until I go inside the console and type App.init(). After that all of the template javascript works. I want to know how to do responsive theme stuff in these directives. I have tried using it both in the compile and link sections. I have tried putting the code in compile and link and calling the $scope.App.init() from a controller and also at the bottom after defining everything. I also tried putting this in jsfiddle but can't show a true example without having the console to call App.init().
My end design would be having some way to switch the pages through ui-router and when a route gets switched it calls the appropriate methods or re-runs the directive or something. The only method that will run on every page is the App.init() method and everything else is really page specific. And technically since this is a single page app the App.init() only needs to run once for the application. I have it tied to a parent template inside ui-router and the pages that will switch all use this shell template. There are some objects that need to access other to call their methods.
Im sorry in advance for maybe a confusing post. I am struggling right now trying to put together some of the ways that you do things from an angular perspective. I will continue to edit the post as I get responses to give further examples.
You said I have read enough about angular that I know DOM manipulations are suppose to go inside a directive but it sounds like you missed the point of a directive. A directive should handle DOM manipulation, yes, but not one directive for the entire page. Each element (or segment) of the page should have its own directive (assuming DOM manip needs to be done on that element) and then the $controller should handle the interactions between those elements and your data (or model).
You've created one gigantic directive and are trying to have it do way too much. Thankfully, you've kinda sorta designed your code in such a way that it shouldn't be too hard to break it up into several directives. Basically, each of your handle functions should be its own directive.
So you'd have something like:
.directive('sidebarMenu', function(){
return {
template: 'path/to/sidebar/partial.html',
link: function(scope, elem, attrs){
// insert the code for your 'handleSidebarMenu()' function here
}
};
})
.directive('horizontalMenu', function(){
return {
template: 'path/to/horizontal/partial.html',
link: function(scope, elem, attrs){
// insert the code for your 'handleHorizontalMenu()' function here
}
};
})
and then your view would look something like:
<body ui-view="dashboard-shell" responsive-theme>
<div class="page-container">
<div class="page-sidebar nav-collapse collapse">
<horizontal-menu></horizontal-menu>
<sidebar-menu></sidebar-menu>
</div>
<div class="page-content" ui-view="dashboard">
</div>
</div>
</body>
And then you don't need a SidebarmenuController because your controller functions shouldn't be handling DOM elements like the sidebar. The controller should just handling the data that you're going to display in your view, and then the view (or .html file) will handle the displaying and manipulation of that data by its use of the directives you've written.
Does that make sense? Just try breaking that huge directive up into many smaller directives that handle specific elements or specific tasks in the DOM.