Issues with parallax/translate3d performance on safari & firefox? - javascript

For days I've been trying to figure out how get a nice, smooth, hardware accelerated parallax effect working.
I'm using this repository: https://github.com/GianlucaGuarini/parallax
I've tried throttling with underscores, using css3 transitions to smooth things out, nuking the image quality, but no luck, still jank. It's very smooth in Chrome though. Other repositories I've found either have performance issues, don't work on iOS, or require jQuery.
Any similar experiences or tips with debugging?
The Squarespace team has done an awesome job with their Marquee theme. Not sure how they got it so performant.
Here is a link to the code:
https://jsfiddle.net/oh3xwgk1/3/
Edit:
One last note. I've done testing with safari and chrome dev tools. Both show durations that are a fraction of a millisecond, so I don't think its related to that?
Edit2:
By "jank" I mean jitter or a drop of frames.
HTML
<section class="relative height overflow-hidden fill-black">
<img class="parallax" src="https://placeimg.com/1000/1000/nature" alt="">
</section>
JS
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define('Parallax', ['module'], factory);
} else if (typeof exports !== "undefined") {
factory(module);
} else {
var mod = {
exports: {}
};
factory(mod);
global.Parallax = mod.exports;
}
})(this, function (module) {
'use strict';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function $$(selector, ctx) {
var els;
if (typeof selector == 'string') els = (ctx || document).querySelectorAll(selector);else els = selector;
return Array.prototype.slice.call(els);
}
function extend(src) {
var obj,
args = arguments;
for (var i = 1; i < args.length; ++i) {
if (obj = args[i]) {
for (var key in obj) {
src[key] = obj[key];
}
}
}
return src;
}
function isUndefined(val) {
return typeof val == 'undefined';
}
function elementData(el, attr) {
if (attr) return el.dataset[attr] || el.getAttribute('data-' + attr);else return el.dataset || Array.prototype.slice.call(el.attributes).reduce(function (ret, attribute) {
if (/data-/.test(attribute.name)) ret[attribute.name] = attribute.value;
return ret;
}, {});
}
function prefix(obj, prop, value) {
var prefixes = ['ms', 'o', 'Moz', 'webkit', ''],
i = prefixes.length;
while (i--) {
var prefix = prefixes[i],
p = prefix ? prefix + prop[0].toUpperCase() + prop.substr(1) : prop.toLowerCase() + prop.substr(1);
if (p in obj) {
obj[p] = value;
return true;
}
}
return false;
}
var observable = function observable(el) {
el = el || {};
var callbacks = {},
slice = Array.prototype.slice,
onEachEvent = function onEachEvent(e, fn) {
e.replace(/\S+/g, fn);
},
defineProperty = function defineProperty(key, value) {
Object.defineProperty(el, key, {
value: value,
enumerable: false,
writable: false,
configurable: false
});
};
defineProperty('on', function (events, fn) {
if (typeof fn != 'function') return el;
onEachEvent(events, function (name, pos) {
(callbacks[name] = callbacks[name] || []).push(fn);
fn.typed = pos > 0;
});
return el;
});
defineProperty('off', function (events, fn) {
if (events == '*' && !fn) callbacks = {};else {
onEachEvent(events, function (name) {
if (fn) {
var arr = callbacks[name];
for (var i = 0, cb; cb = arr && arr[i]; ++i) {
if (cb == fn) arr.splice(i--, 1);
}
} else delete callbacks[name];
});
}
return el;
});
defineProperty('one', function (events, fn) {
function on() {
el.off(events, on);
fn.apply(el, arguments);
}
return el.on(events, on);
});
defineProperty('trigger', function (events) {
var args = slice.call(arguments, 1),
fns;
onEachEvent(events, function (name) {
fns = slice.call(callbacks[name] || [], 0);
for (var i = 0, fn; fn = fns[i]; ++i) {
if (fn.busy) return;
fn.busy = 1;
fn.apply(el, fn.typed ? [name].concat(args) : args);
if (fns[i] !== fn) {
i--;
}
fn.busy = 0;
}
if (callbacks['*'] && name != '*') el.trigger.apply(el, ['*', name].concat(args));
});
return el;
});
return el;
};
var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function (cb) {
setTimeout(cb, 1000 / 60);
};
var RESIZE_DELAY = 20;
var Stage = function () {
function Stage() {
_classCallCheck(this, Stage);
observable(this);
this.resizeTimer = null;
this.tick = false;
this.bind();
}
_createClass(Stage, [{
key: 'bind',
value: function bind() {
var _this = this;
window.addEventListener('scroll', function () {
return _this.scroll();
}, true);
window.addEventListener('mousewheel', function () {
return _this.scroll();
}, true);
window.addEventListener('touchmove', function () {
return _this.scroll();
}, true);
window.addEventListener('resize', function () {
return _this.resize();
}, true);
window.addEventListener('orientationchange', function () {
return _this.resize();
}, true);
window.onload = function () {
return _this.scroll();
};
return this;
}
}, {
key: 'scroll',
value: function scroll() {
var _this2 = this;
if (this.tick) return this;
this.tick = !this.tick;
rAF(function () {
return _this2.update();
});
return this;
}
}, {
key: 'update',
value: function update() {
this.trigger('scroll', this.scrollTop);
this.tick = !this.tick;
return this;
}
}, {
key: 'resize',
value: function resize() {
var _this3 = this;
if (this.resizeTimer) clearTimeout(this.resizeTimer);
this.resizeTimer = setTimeout(function () {
return _this3.trigger('resize', _this3.size);
}, RESIZE_DELAY);
return this;
}
}, {
key: 'scrollTop',
get: function get() {
var top = (window.pageYOffset || document.scrollTop) - (document.clientTop || 0);
return window.isNaN(top) ? 0 : top;
}
}, {
key: 'height',
get: function get() {
return window.innerHeight;
}
}, {
key: 'width',
get: function get() {
return window.innerWidth;
}
}, {
key: 'size',
get: function get() {
return {
width: this.width,
height: this.height
};
}
}]);
return Stage;
}();
var HAS_TRANSLATE_3D = function (div) {
prefix(div.style, 'transform', 'translate3d(0, 0, 0)');
return (/translate3d/g.test(div.style.cssText)
);
}(document.createElement('div'));
var Canvas = function () {
function Canvas(img, opts) {
_classCallCheck(this, Canvas);
observable(this);
this.opts = opts;
this.img = img;
this.wrapper = img.parentNode;
this.isLoaded = false;
}
_createClass(Canvas, [{
key: 'load',
value: function load() {
var _this4 = this;
if (!this.img.width || !this.img.height || !this.img.complete) this.img.onload = function () {
return _this4.onImageLoaded();
};else this.onImageLoaded();
return this;
}
}, {
key: 'onImageLoaded',
value: function onImageLoaded() {
this.isLoaded = true;
this.update();
this.trigger('loaded', this.img);
return this;
}
}, {
key: 'update',
value: function update() {
var iw = this.img.naturalWidth || this.img.width,
ih = this.img.naturalHeight || this.img.height,
ratio = iw / ih,
size = this.size;
if (size.width / ratio <= size.height) {
this.img.height = size.height;
this.img.width = size.height * ratio;
} else {
this.img.width = size.width;
this.img.height = size.width / ratio;
}
this.img.style.top = - ~ ~((this.img.height - size.height) / 2) + 'px';
this.img.style.left = - ~ ~((this.img.width - size.width) / 2) + 'px';
return this;
}
}, {
key: 'draw',
value: function draw(stage) {
var size = this.size,
perc = (this.offset.top + size.height * this.opts.center + stage.height / 2 - stage.scrollTop) / stage.height - 1;
perc *= this.img.height / size.height / 2 * this.opts.intensity;
if (HAS_TRANSLATE_3D) prefix(this.img.style, 'transform', 'translate3d(0, ' + -perc.toFixed(4) + '%, 0)');else prefix(this.img.style, 'transform', 'translate(0, ' + -perc + '%, 0)');
return this;
}
}, {
key: 'bounds',
get: function get() {
return this.wrapper.getBoundingClientRect();
}
}, {
key: 'offset',
get: function get() {
return {
top: this.wrapper.offsetTop,
left: this.wrapper.offsetLeft
};
}
}, {
key: 'size',
get: function get() {
var props = this.bounds;
return {
height: props.height | 0,
width: props.width | 0
};
}
}]);
return Canvas;
}();
var stage;
var Parallax = function () {
function Parallax(selector) {
var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
_classCallCheck(this, Parallax);
observable(this);
this.opts = opts;
this.selector = selector;
this.canvases = [];
this.add(selector);
if (!stage) stage = new Stage();
return this;
}
_createClass(Parallax, [{
key: 'init',
value: function init() {
if (!this.canvases.length) {
console.warn('No images were found with the selector "' + this.selector + '"');
} else {
this.imagesLoaded = 0;
this.bind();
}
return this;
}
}, {
key: 'bind',
value: function bind() {
var _this5 = this;
this._onResize = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _this5.resize.apply(_this5, args);
};
this._onScroll = function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return _this5.scroll.apply(_this5, args);
};
stage.on('resize', this._onResize);
stage.on('scroll', this._onScroll);
this.canvases.forEach(function (canvas) {
canvas.one('loaded', function () {
return _this5.onCanvasLoaded(canvas);
});
canvas.load();
});
return this;
}
}, {
key: 'refresh',
value: function refresh() {
this.onResize(stage.size).onScroll(stage.scrollTop);
return this;
}
}, {
key: 'onCanvasLoaded',
value: function onCanvasLoaded(canvas) {
this.trigger('image:loaded', canvas.img, canvas);
this.imagesLoaded++;
canvas.draw(stage);
if (this.imagesLoaded == this.canvases.length) this.trigger('images:loaded');
return this;
}
}, {
key: 'scroll',
value: function scroll(scrollTop) {
var i = this.canvases.length,
offsetYBounds = this.opts.offsetYBounds,
stageScrollTop = stage.scrollTop;
while (i--) {
var canvas = this.canvases[i],
canvasHeight = canvas.size.height,
canvasOffset = canvas.offset,
canvasScrollDelta = canvasOffset.top + canvasHeight - stageScrollTop;
if (canvas.isLoaded && canvasScrollDelta + offsetYBounds > 0 && canvasScrollDelta - offsetYBounds < stageScrollTop + stage.height) {
canvas.draw(stage);
this.trigger('draw', canvas.img);
}
}
this.trigger('update', stageScrollTop);
return this;
}
}, {
key: 'add',
value: function add(els) {
this.canvases = this.canvases.concat(this.createCanvases($$(els)));
return this;
}
}, {
key: 'remove',
value: function remove(els) {
var _this6 = this;
$$(els).forEach(function (el) {
var i = _this6.canvases.length;
while (i--) {
if (el == _this6.canvases[i].img) {
_this6.canvases.splice(i, 1);
break;
}
}
});
return this;
}
}, {
key: 'destroy',
value: function destroy() {
this.off('*');
this.canvases = [];
stage.off('resize', this._onResize).off('scroll', this._onScroll);
return this;
}
}, {
key: 'resize',
value: function resize(size) {
var i = this.canvases.length;
while (i--) {
var canvas = this.canvases[i];
if (!canvas.isLoaded) return;
canvas.update().draw(stage);
}
this.trigger('resize');
return this;
}
}, {
key: 'createCanvases',
value: function createCanvases(els) {
var _this7 = this;
return els.map(function (el) {
var data = elementData(el);
return new Canvas(el, {
intensity: !isUndefined(data.intensity) ? +data.intensity : _this7.opts.intensity,
center: !isUndefined(data.center) ? +data.center : _this7.opts.center
});
});
}
}, {
key: 'opts',
set: function set(opts) {
this._defaults = {
offsetYBounds: 50,
intensity: 30,
center: 0.5
};
extend(this._defaults, opts);
},
get: function get() {
return this._defaults;
}
}]);
return Parallax;
}();
module.exports = Parallax;
});
var parallax = new Parallax('.parallax', {
offsetYBounds: 50,
intensity: 50,
center: .75
}).init();

A good solution I found for this was to create a fixed position div and placing it behind the main content. Parallax performance is tricky for big images when you're using parallax so your best case scenario is to use CSS's positioning and javascript to cleverly hide & show. At least in my opinion.

Related

How to avoid collapse menubar and cover carousel in website?

first of all im sorry for taking your time. I used album cover slider and superfish in my first site and they collapsed. I can use slider perfectly but i cant use my menu. Submenus and everything shows when i take my cursor to there. I want to learn how to avoid click collapse in js projects, little explanation would help me big time.
Here are the JS's.
for menu
* jQuery Superfish Menu Plugin - v1.7.9
* Copyright (c) 2016 Joel Birch
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
;(function ($, w) {
"use strict";
var methods = (function () {
// private properties and methods go here
var c = {
bcClass: 'sf-breadcrumb',
menuClass: 'sf-js-enabled',
anchorClass: 'sf-with-ul',
menuArrowClass: 'sf-arrows'
},
ios = (function () {
var ios = /^(?![\w\W]*Windows Phone)[\w\W]*(iPhone|iPad|iPod)/i.test(navigator.userAgent);
if (ios) {
// tap anywhere on iOS to unfocus a submenu
$('html').css('cursor', 'pointer').on('click', $.noop);
}
return ios;
})(),
wp7 = (function () {
var style = document.documentElement.style;
return ('behavior' in style && 'fill' in style && /iemobile/i.test(navigator.userAgent));
})(),
unprefixedPointerEvents = (function () {
return (!!w.PointerEvent);
})(),
toggleMenuClasses = function ($menu, o, add) {
var classes = c.menuClass,
method;
if (o.cssArrows) {
classes += ' ' + c.menuArrowClass;
}
method = (add) ? 'addClass' : 'removeClass';
$menu[method](classes);
},
setPathToCurrent = function ($menu, o) {
return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
.addClass(o.hoverClass + ' ' + c.bcClass)
.filter(function () {
return ($(this).children(o.popUpSelector).hide().show().length);
}).removeClass(o.pathClass);
},
toggleAnchorClass = function ($li, add) {
var method = (add) ? 'addClass' : 'removeClass';
$li.children('a')[method](c.anchorClass);
},
toggleTouchAction = function ($menu) {
var msTouchAction = $menu.css('ms-touch-action');
var touchAction = $menu.css('touch-action');
touchAction = touchAction || msTouchAction;
touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
$menu.css({
'ms-touch-action': touchAction,
'touch-action': touchAction
});
},
getMenu = function ($el) {
return $el.closest('.' + c.menuClass);
},
getOptions = function ($el) {
return getMenu($el).data('sfOptions');
},
over = function () {
var $this = $(this),
o = getOptions($this);
clearTimeout(o.sfTimer);
$this.siblings().superfish('hide').end().superfish('show');
},
close = function (o) {
o.retainPath = ($.inArray(this[0], o.$path) > -1);
this.superfish('hide');
if (!this.parents('.' + o.hoverClass).length) {
o.onIdle.call(getMenu(this));
if (o.$path.length) {
$.proxy(over, o.$path)();
}
}
},
out = function () {
var $this = $(this),
o = getOptions($this);
if (ios) {
$.proxy(close, $this, o)();
}
else {
clearTimeout(o.sfTimer);
o.sfTimer = setTimeout($.proxy(close, $this, o), o.delay);
}
},
touchHandler = function (e) {
var $this = $(this),
o = getOptions($this),
$ul = $this.siblings(e.data.popUpSelector);
if (o.onHandleTouch.call($ul) === false) {
return this;
}
if ($ul.length > 0 && $ul.is(':hidden')) {
$this.one('click.superfish', false);
if (e.type === 'MSPointerDown' || e.type === 'pointerdown') {
$this.trigger('focus');
} else {
$.proxy(over, $this.parent('li'))();
}
}
},
applyHandlers = function ($menu, o) {
var targets = 'li:has(' + o.popUpSelector + ')';
if ($.fn.hoverIntent && !o.disableHI) {
$menu.hoverIntent(over, out, targets);
}
else {
$menu
.on('mouseenter.superfish', targets, over)
.on('mouseleave.superfish', targets, out);
}
var touchevent = 'MSPointerDown.superfish';
if (unprefixedPointerEvents) {
touchevent = 'pointerdown.superfish';
}
if (!ios) {
touchevent += ' touchend.superfish';
}
if (wp7) {
touchevent += ' mousedown.superfish';
}
$menu
.on('focusin.superfish', 'li', over)
.on('focusout.superfish', 'li', out)
.on(touchevent, 'a', o, touchHandler);
};
return {
// public methods
hide: function (instant) {
if (this.length) {
var $this = this,
o = getOptions($this);
if (!o) {
return this;
}
var not = (o.retainPath === true) ? o.$path : '',
$ul = $this.find('li.' + o.hoverClass).add(this).not(not).removeClass(o.hoverClass).children(o.popUpSelector),
speed = o.speedOut;
if (instant) {
$ul.show();
speed = 0;
}
o.retainPath = false;
if (o.onBeforeHide.call($ul) === false) {
return this;
}
$ul.stop(true, true).animate(o.animationOut, speed, function () {
var $this = $(this);
o.onHide.call($this);
});
}
return this;
},
show: function () {
var o = getOptions(this);
if (!o) {
return this;
}
var $this = this.addClass(o.hoverClass),
$ul = $this.children(o.popUpSelector);
if (o.onBeforeShow.call($ul) === false) {
return this;
}
$ul.stop(true, true).animate(o.animation, o.speed, function () {
o.onShow.call($ul);
});
return this;
},
destroy: function () {
return this.each(function () {
var $this = $(this),
o = $this.data('sfOptions'),
$hasPopUp;
if (!o) {
return false;
}
$hasPopUp = $this.find(o.popUpSelector).parent('li');
clearTimeout(o.sfTimer);
toggleMenuClasses($this, o);
toggleAnchorClass($hasPopUp);
toggleTouchAction($this);
// remove event handlers
$this.off('.superfish').off('.hoverIntent');
// clear animation's inline display style
$hasPopUp.children(o.popUpSelector).attr('style', function (i, style) {
return style.replace(/display[^;]+;?/g, '');
});
// reset 'current' path classes
o.$path.removeClass(o.hoverClass + ' ' + c.bcClass).addClass(o.pathClass);
$this.find('.' + o.hoverClass).removeClass(o.hoverClass);
o.onDestroy.call($this);
$this.removeData('sfOptions');
});
},
init: function (op) {
return this.each(function () {
var $this = $(this);
if ($this.data('sfOptions')) {
return false;
}
var o = $.extend({}, $.fn.superfish.defaults, op),
$hasPopUp = $this.find(o.popUpSelector).parent('li');
o.$path = setPathToCurrent($this, o);
$this.data('sfOptions', o);
toggleMenuClasses($this, o, true);
toggleAnchorClass($hasPopUp, true);
toggleTouchAction($this);
applyHandlers($this, o);
$hasPopUp.not('.' + c.bcClass).superfish('hide', true);
o.onInit.call(this);
});
}
};
})();
$.fn.superfish = function (method, args) {
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 {
return $.error('Method ' + method + ' does not exist on jQuery.fn.superfish');
}
};
$.fn.superfish.defaults = {
popUpSelector: 'ul,.sf-mega', // within menu context
hoverClass: 'sfHover',
pathClass: 'overrideThisToUse',
pathLevels: 1,
delay: 800,
animation: {opacity: 'show'},
animationOut: {opacity: 'hide'},
speed: 'normal',
speedOut: 'fast',
cssArrows: true,
disableHI: false,
onInit: $.noop,
onBeforeShow: $.noop,
onShow: $.noop,
onBeforeHide: $.noop,
onHide: $.noop,
onIdle: $.noop,
onDestroy: $.noop,
onHandleTouch: $.noop
};
})(jQuery, window);
Album Cover Slider
--------------------------------*/
//start added by Chase
var a = document.getElementsByTagName("a");
var cfImg = document.getElementsByClassName("coverflow__image")
var scaleI = 0;
for (scaleI; scaleI < a.length; scaleI++) {
if (scaleI === 3) {
continue;
} else {
a[scaleI].style.cursor = "default";
a[scaleI].addEventListener("click", prevDef);
}
}
function prevDef(e) {
e.preventDefault();
}
function forScale(coverflowPos) {
for (scaleI = 0; scaleI < a.length; scaleI++) {
a[scaleI].style.cursor = "default";
a[scaleI].addEventListener("click", prevDef);
}
for (scaleI = 0; scaleI < cfImg.length; scaleI++) {
if (cfImg[scaleI].getAttribute("data-coverflow-index") == coverflowPos) {
cfImg[scaleI].parentElement.style.cursor = "pointer";
cfImg[scaleI].parentElement.removeEventListener("click", prevDef);
}
}
}
//end added by Chase
function setupCoverflow(coverflowContainer) {
var coverflowContainers;
if (typeof coverflowContainer !== "undefined") {
if (Array.isArray(coverflowContainer)) {
coverflowContainers = coverflowContainer;
} else {
coverflowContainers = [coverflowContainer];
}
} else {
coverflowContainers = Array.prototype.slice.apply(document.getElementsByClassName('coverflow'));
}
coverflowContainers.forEach(function(containerElement) {
var coverflow = {};
var prevArrows, nextArrows;
//capture coverflow elements
coverflow.container = containerElement;
coverflow.images = Array.prototype.slice.apply(containerElement.getElementsByClassName('coverflow__image'));
coverflow.position = Math.floor(coverflow.images.length / 2) + 1;
//set indicies on images
coverflow.images.forEach(function(coverflowImage, i) {
coverflowImage.dataset.coverflowIndex = i + 1;
});
//set initial position
coverflow.container.dataset.coverflowPosition = coverflow.position;
//get prev/next arrows
prevArrows = Array.prototype.slice.apply(coverflow.container.getElementsByClassName("prev-arrow"));
nextArrows = Array.prototype.slice.apply(coverflow.container.getElementsByClassName("next-arrow"));
//add event handlers
function setPrevImage() {
coverflow.position = Math.max(1, coverflow.position - 1);
coverflow.container.dataset.coverflowPosition = coverflow.position;
//call the functin forScale added
forScale(coverflow.position);
}
function setNextImage() {
coverflow.position = Math.min(coverflow.images.length, coverflow.position + 1);
coverflow.container.dataset.coverflowPosition = coverflow.position;
//call the function Chase added
forScale(coverflow.position);
}
function jumpToImage(evt) {
coverflow.position = Math.min(coverflow.images.length, Math.max(1, evt.target.dataset.coverflowIndex));
coverflow.container.dataset.coverflowPosition = coverflow.position;
//start added by Chase
setTimeout(function() {
forScale(coverflow.position);
}, 1);
//end added by Chase
}
function onKeyPress(evt) {
switch (evt.which) {
case 37: //left arrow
setPrevImage();
break;
case 39: //right arrow
setNextImage();
break;
}
}
prevArrows.forEach(function(prevArrow) {
prevArrow.addEventListener('click', setPrevImage);
});
nextArrows.forEach(function(nextArrow) {
nextArrow.addEventListener('click', setNextImage);
});
coverflow.images.forEach(function(image) {
image.addEventListener('click', jumpToImage);
});
window.addEventListener('keyup', onKeyPress);
});
}
setupCoverflow(); ```

How to call function of JS added in header?

I have following JS which is added in header. I have button in page. I want to call "FulfillOrder" function of JS.
I don't know how to call it.
Can anybody please suggest me how can I call?
JS:
/// <reference path='../../../../ClientCommon/Sales_ClientCommon.d.ts' />
/// <reference path="../../../../../../TypeDefinitions/CRM/ClientUtility.d.ts" />
/// <reference path='../../../../CommandBarActions/SalesCommandBarActions.d.ts' />
var Sales;
(function (Sales) {
var SalesOrderRibbonActionsLibrary = (function () {
function SalesOrderRibbonActionsLibrary() {
var _this = this;
this.CloseOrFulfillOrder = function (closedState) {
var options = { height: 350, width: 475, position: 1 /* center */ };
options.width = 330;
options.height = 400;
var dialogParams = {};
dialogParams[Sales.MetadataDrivenDialogConstantsOrderClose.SalesId] = Xrm.Page.data.entity.getId();
dialogParams[Sales.MetadataDrivenDialogConstantsOrderClose.ClosedState] = closedState;
Xrm.Navigation.openDialog(Sales.DialogName.CloseOrder, options, dialogParams).then(_this.salesOrderDialogCloseCallback);
};
this.salesOrderDialogCloseCallback = function (response) {
var parameters = response.parameters;
var lastButtonClicked = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.LastButtonClicked];
if (ClientUtility.DataUtil.isNullOrUndefined(lastButtonClicked) || lastButtonClicked.toString() !== ClientUtility.MetadataDrivenDialogConstants.DialogOkId) {
return;
}
var salesOrderId = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.SalesId];
var date = new Date(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Date]);
var closedState = parseInt(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.ClosedState]);
var reason = parseInt(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Reason]);
var description = null;
if (!ClientUtility.DataUtil.isNullOrUndefined(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Description])) {
description = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Description].toString();
}
if (!ClientUtility.DataUtil.isNullOrUndefined(date) && !ClientUtility.DataUtil.isNullOrUndefined(date)) {
_this.commandBarActions.PerformActionAfterCloseOrder(reason, date, description, closedState, salesOrderId);
}
};
/**
* Processes the sales order.
*/
this.ProcessOrder = function () {
if (Xrm.Page.ui.getFormType() !== 4 /* Disabled */ && Xrm.Page.ui.getFormType() !== 3 /* ReadOnly */) {
Xrm.Page.data.save().then(function (successResponse) {
_this.processOrderSuccessResponse();
}, ClientUtility.ActionFailedHandler.actionFailedCallback);
}
else {
_this.processOrderSuccessResponse();
}
};
this.processOrderSuccessResponse = function () {
var columns = new ODataContract.ColumnSet(false, ["invoiceid"]);
if (!_this.IsBackOfficeInstalled()) {
var convertSalesOrderToInvoiceRequest = new ODataContract.ConvertSalesOrderToInvoiceRequest();
convertSalesOrderToInvoiceRequest.SalesOrderId = { guid: Xrm.Page.data.entity.getId() };
convertSalesOrderToInvoiceRequest.ColumnSet = columns;
Xrm.WebApi.online.execute(convertSalesOrderToInvoiceRequest).then(function (response) {
response.json().then(function (jsonResponse) {
var invoiceId = jsonResponse.invoiceid;
Xrm.Utility.openEntityForm(Sales.EntityNames.Invoice, invoiceId, null);
});
}, ClientUtility.ActionFailedHandler.actionFailedCallback);
}
else {
var defaultStatusCode = -1;
XrmCore.Commands.Common.setState(Xrm.Page.data.entity.getId(), Xrm.Page.data.entity.getEntityName(), Sales.SalesOrderState.Submitted, defaultStatusCode);
}
};
this.IsBackOfficeInstalled = function () {
// var isBackOfficeInstalled: string = Xrm.Internal.getResourceString("IS_BACKOFFICE_INSTALLED");
// if (ClientUtility.DataUtil.isNullOrEmptyString(isBackOfficeInstalled)) {
// return false;
// }
// return isBackOfficeInstalled === "1";
//TODO: investigate backoffice.
return false;
};
this.GetProductsForOrder = function () {
_this.commandBarActions.getProducts();
};
this.LockSalesOrder = function () {
debugger;
_this.commandBarActions.lock();
};
this.UnlockSalesOrder = function () {
debugger;
_this.commandBarActions.unlock();
};
this.CloseOrder = function () {
_this.CloseOrFulfillOrder(Sales.SalesOrderState.Canceled);
};
this.FulfillOrder = function () {
_this.CloseOrFulfillOrder(Sales.SalesOrderState.Fulfilled);
};
this.IsSalesOrderActive = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Active);
};
this.IsSalesOrderFulfilled = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Fulfilled);
};
this.IsSalesOrderSubmitted = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Submitted);
};
this.IsSalesOrderState = function (state) {
var stateCodeControl = Xrm.Page.data.entity.attributes.get("statecode");
var orderState = stateCodeControl ? stateCodeControl.getValue() : null;
var returnValue = false;
if (ClientUtility.DataUtil.isNullOrUndefined(orderState)) {
return returnValue;
}
switch (state) {
case 0:
if (orderState === 0) {
returnValue = true;
}
break;
case Sales.SalesOrderState.Submitted:
if (orderState === Sales.SalesOrderState.Submitted) {
returnValue = true;
}
break;
case Sales.SalesOrderState.Fulfilled:
if (orderState === Sales.SalesOrderState.Fulfilled) {
returnValue = true;
}
break;
case Sales.SalesOrderState.FulfilledOrActive:
if (orderState === Sales.SalesOrderState.Fulfilled || orderState === 0) {
returnValue = true;
}
break;
default:
returnValue = false;
break;
}
return returnValue;
};
}
Object.defineProperty(SalesOrderRibbonActionsLibrary.prototype, "commandBarActions", {
get: function () {
if (ClientUtility.DataUtil.isNullOrUndefined(this._commandBarActions)) {
this._commandBarActions = new Sales.SalesCommandBarActions();
}
return this._commandBarActions;
},
enumerable: true,
configurable: true
});
return SalesOrderRibbonActionsLibrary;
}());
Sales.SalesOrderRibbonActionsLibrary = SalesOrderRibbonActionsLibrary;
})(Sales || (Sales = {}));
/**
* #license Copyright (c) Microsoft Corporation. All rights reserved.
*/
/// <reference path="../../../../../TypeDefinitions/CRM/ClientUtility.d.ts" />
/// <reference path="UCI/SalesOrderRibbonActionsLibrary.ts" />
/// <reference path="../../../../../../references/internal/TypeDefinitions/XrmClientApi/XrmClassicWebClientApi.d.ts" />
var Sales;
(function (Sales) {
var SalesOrderRibbonActions = (function () {
function SalesOrderRibbonActions() {
}
return SalesOrderRibbonActions;
}());
SalesOrderRibbonActions.Instance = new Sales.SalesOrderRibbonActionsLibrary();
Sales.SalesOrderRibbonActions = SalesOrderRibbonActions;
})(Sales || (Sales = {}));
//# sourceMappingURL=SalesOrderRibbonActions.js.map
Previous version of this JS have function "fulfillOrder" and it was working properly. But in this version, they updated a lot. I don't know how to call it.
Please suggest.
Thank you.
If you are calling the methods outside then create an instance and call that FulfillOrder method,
var obj = new Sales.SalesOrderRibbonActionsLibrary();
obj.FulfillOrder(); // now call the methods
You need to call in the way mention below.
Sales.SalesOrderRibbonActionsLibrary.FulfillOrder();

Prestadhop 1.6 superfish menu hover to click

Hello i'm working with presta 1.6 and i want change the hover of sub menu to click and still hovering in the menu(mother menu) but i try many time with any success result the problem in superfish-modified.js .. any one can help and thnx
this the superfish-modified.js
(function ($) {
"use strict";
var methods = (function () {
// private properties and methods go here
var c = {
bcClass: 'sf-breadcrumb',
menuClass: 'sf-js-enabled',
anchorClass: 'sf-with-ul',
menuArrowClass: 'sf-arrows'
},
ios = (function () {
var ios = /iPhone|iPad|iPod/i.test(navigator.userAgent);
if (ios) {
// iOS clicks only bubble as far as body children
$(window).load(function () {
$('body').children().on('click', $.noop);
});
}
return ios;
})(),
wp7 = (function () {
var style = document.documentElement.style;
return ('behavior' in style && 'fill' in style && /iemobile/i.test(navigator.userAgent));
})(),
toggleMenuClasses = function ($menu, o) {
var classes = c.menuClass;
if (o.cssArrows) {
classes += ' ' + c.menuArrowClass;
}
$menu.toggleClass(classes);
},
setPathToCurrent = function ($menu, o) {
return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
.addClass(o.hoverClass + ' ' + c.bcClass)
.filter(function () {
return ($(this).children(o.popUpSelector).hide().show().length);
}).removeClass(o.pathClass);
},
toggleAnchorClass = function ($li) {
$li.children('a').toggleClass(c.anchorClass);
},
toggleTouchAction = function ($menu) {
var touchAction = $menu.css('ms-touch-action');
touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
$menu.css('ms-touch-action', touchAction);
},
applyHandlers = function ($menu, o) {
var targets = 'li:has(' + o.popUpSelector + ')';
if ($.fn.hoverIntent && !o.disableHI) {
$menu.hoverIntent(over, out, targets);
}
else {
$menu
.on('mouseenter.superfish', targets, over)
.on('mouseleave.superfish', targets, out);
}
var touchevent = 'MSPointerDown.superfish';
if (!ios) {
touchevent += ' touchend.superfish';
}
if (wp7) {
touchevent += ' mousedown.superfish';
}
$menu
.on('focusin.superfish', 'li', over)
.on('focusout.superfish', 'li', out)
.on(touchevent, 'a', o, touchHandler);
},
touchHandler = function (e) {
var $this = $(this),
$ul = $this.siblings(e.data.popUpSelector);
if ($ul.length > 0 && $ul.is(':hidden')) {
$this.one('click.superfish', false);
if (e.type === 'MSPointerDown') {
$this.trigger('focus');
} else {
$.proxy(over, $this.parent('li'))();
}
}
},
over = function () {
var $this = $(this),
o = getOptions($this);
clearTimeout(o.sfTimer);
$this.siblings().superfish('hide').end().superfish('show');
},
out = function () {
var $this = $(this),
o = getOptions($this);
if (ios) {
$.proxy(close, $this, o)();
}
else {
clearTimeout(o.sfTimer);
o.sfTimer = setTimeout($.proxy(close, $this, o), o.delay);
}
},
close = function (o) {
o.retainPath = ($.inArray(this[0], o.$path) > -1);
this.superfish('hide');
if (!this.parents('.' + o.hoverClass).length) {
o.onIdle.call(getMenu(this));
if (o.$path.length) {
$.proxy(over, o.$path)();
}
}
},
getMenu = function ($el) {
return $el.closest('.' + c.menuClass);
},
getOptions = function ($el) {
return getMenu($el).data('sf-options');
};
return {
// public methods
hide: function (instant) {
if (this.length) {
var $this = this,
o = getOptions($this);
if (!o) {
return this;
}
var not = (o.retainPath === true) ? o.$path : '',
$ul = $this.find('li.' + o.hoverClass).add(this).not(not).removeClass(o.hoverClass).children(o.popUpSelector),
speed = o.speedOut;
if (instant) {
$ul.show();
speed = 0;
}
o.retainPath = false;
o.onBeforeHide.call($ul);
$ul.stop(true, true).animate(o.animationOut, speed, function () {
var $this = $(this);
o.onHide.call($this);
});
}
return this;
},
show: function () {
var o = getOptions(this);
if (!o) {
return this;
}
var $this = this.addClass(o.hoverClass),
$ul = $this.children(o.popUpSelector);
o.onBeforeShow.call($ul);
$ul.stop(true, true).animate(o.animation, o.speed, function () {
o.onShow.call($ul);
});
return this;
},
destroy: function () {
return this.each(function () {
var $this = $(this),
o = $this.data('sf-options'),
$hasPopUp;
if (!o) {
return false;
}
$hasPopUp = $this.find(o.popUpSelector).parent('li');
clearTimeout(o.sfTimer);
toggleMenuClasses($this, o);
toggleAnchorClass($hasPopUp);
toggleTouchAction($this);
// remove event handlers
$this.off('.superfish').off('.hoverIntent');
// clear animation's inline display style
$hasPopUp.children(o.popUpSelector).attr('style', function (i, style) {
return style.replace(/display[^;]+;?/g, '');
});
// reset 'current' path classes
o.$path.removeClass(o.hoverClass + ' ' + c.bcClass).addClass(o.pathClass);
$this.find('.' + o.hoverClass).removeClass(o.hoverClass);
o.onDestroy.call($this);
$this.removeData('sf-options');
});
},
init: function (op) {
return this.each(function () {
var $this = $(this);
if ($this.data('sf-options')) {
return false;
}
var o = $.extend({}, $.fn.superfish.defaults, op),
$hasPopUp = $this.find(o.popUpSelector).parent('li');
o.$path = setPathToCurrent($this, o);
$this.data('sf-options', o);
toggleMenuClasses($this, o);
toggleAnchorClass($hasPopUp);
toggleTouchAction($this);
applyHandlers($this, o);
$hasPopUp.not('.' + c.bcClass).superfish('hide', true);
o.onInit.call(this);
});
}
};
})();
$.fn.superfish = function (method, args) {
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 {
return $.error('Method ' + method + ' does not exist on jQuery.fn.superfish');
}
};
$.fn.superfish.defaults = {
popUpSelector: 'ul,.sf-mega', // within menu context
hoverClass: 'sfHover',
pathClass: 'overrideThisToUse',
pathLevels:1 ,
delay: 800,
animation: {opacity: 'show'},
animationOut: {opacity: 'hide'},
speed: 'normal',
speedOut: 'fast',
cssArrows: true,
disableHI: false,
onInit: $.noop,
onBeforeShow: $.noop,
onShow: $.noop,
onBeforeHide: $.noop,
onHide: $.noop,
onIdle: $.noop,
onDestroy: $.noop
};
// soon to be deprecated
$.fn.extend({
hideSuperfishUl: methods.hide,
showSuperfishUl: methods.show
});
})(jQuery);
Default values for the menu are defined in superfish-modified.js (/themes/default-bootstrap/js/modules/blocktopmenu/js/superfish-modified.js) file around line 230.
There is a default value for hoverClass as well:
hoverClass: 'sfHover',
Try replacing it with:
hoverClass: '',

jQuery Taggd plugin (Edit mode) get back value in input fields

Im using the jQuery taggd plugin, so far so good.
I modified a small bit, im using it in edit mode. So when a user types in a value in the textbox it checks if it is a URL or or string, if its a URL it runs a ajax call to a php file which scrapes some data from the url. Url title, description and image. I have created 3 hidden input fields which get populated once the ajax call is finished. Once you click on the SAVE icon it saves the data to the DOM. But i want it to display again once a user clicks on the tag again. At the moment its only displaying the value of the standard input field.
This is the taggd plugin with some small modifications:
/*!
* jQuery Taggd
* A helpful plugin that helps you adding 'tags' on images.
*
* License: MIT
*/
(function($) {
'use strict';
var defaults = {
edit: false,
align: {
x: 'center',
y: 'center'
},
handlers: {},
offset: {
left: 0,
top: 0
},
strings: {
save: '✓',
delete: '×'
}
};
var methods = {
show: function() {
var $this = $(this),
$label = $this.next();
$this.addClass('active');
$label.addClass('show').find('input').focus();
},
hide: function() {
var $this = $(this);
$this.removeClass('active');
$this.next().removeClass('show');
},
toggle: function() {
var $hover = $(this).next();
if($hover.hasClass('show')) {
methods.hide.call(this);
} else {
methods.show.call(this);
}
}
};
/****************************************************************
* TAGGD
****************************************************************/
var Taggd = function(element, options, data) {
var _this = this;
if(options.edit) {
options.handlers = {
click: function() {
_this.hide();
methods.show.call(this);
}
};
}
this.element = $(element);
this.options = $.extend(true, {}, defaults, options);
this.data = data;
this.initialized = false;
if(!this.element.height() || !this.element.width()) {
this.element.on('load', _this.initialize.bind(this));
} else this.initialize();
};
/****************************************************************
* INITIALISATION
****************************************************************/
Taggd.prototype.initialize = function() {
var _this = this;
this.initialized = true;
this.initWrapper();
this.addDOM();
if(this.options.edit) {
this.element.on('click', function(e) {
var poffset = $(this).parent().offset(),
x = (e.pageX - poffset.left) / _this.element.width(),
y = (e.pageY - poffset.top) / _this.element.height();
_this.addData({
x: x,
y: y,
text: '',
url: '',
url_title: '',
url_description: '',
url_image: ''
});
_this.show(_this.data.length - 1);
});
}
$(window).resize(function() {
_this.updateDOM();
});
};
Taggd.prototype.initWrapper = function() {
var wrapper = $('<div class="taggd-wrapper" />');
this.element.wrap(wrapper);
this.wrapper = this.element.parent('.taggd-wrapper');
};
Taggd.prototype.alterDOM = function() {
var _this = this;
this.wrapper.find('.taggd-item-hover').each(function() {
var $e = $(this),
$input = $('<input id="url" type="text" size="16" />')
.val($e.text()),
$url_title = $('<input type="text" id="url_title" class="url_title" />'),
$button_ok = $('<button />')
.html(_this.options.strings.save),
$url_description = $('<input type="text" class="url_description" id="url_description" />'),
$url_image = $('<input type="text" class="url_img" id="url_img" />'),
$url_preview = $('<div id="content"></div>'),
$button_delete = $('<button />')
.html(_this.options.strings.delete);
$button_delete.on('click', function() {
var x = $e.attr('data-x'),
y = $e.attr('data-y');
_this.data = $.grep(_this.data, function(v) {
return v.x != x || v.y != y;
});
_this.addDOM();
_this.element.triggerHandler('change');
});
// Typing URL timer
var typingTimer;
var doneTypingInterval = 2000;
$input.keyup(function() {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});
$input.keydown(function() {
clearTimeout(typingTimer);
$url_preview.empty();
});
// Process URL scrape request
function doneTyping() {
var getUrl = $input.val();
if(isURL(getUrl)) {
console.log('Typed text is a URL');
$url_preview.append('<img src="images/loader.gif" style="width:24px; padding-top:10px; height:24px; margin:0 auto;">');
// Get url data by ajax
$.post('ajax/Crawl.php', {
'url' : getUrl
},function(data) {
$url_preview.empty();
var content = '<h3 class="url_title">' + data.title + '</h3><p class="url_description" style="font-size:11px;">' + data.description + '</p><img class="url_image" src="' + data.images + '" style="width:100%; height:auto;">';
$url_preview.append(content);
$url_title.val(data.title);
$url_description.val(data.description);
$url_image.val(data.images);
console.log(content);
}, 'json');
} else {
console.log('Typed text is a string');
}
};
function isURL(url) {
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
if(!pattern.test(url)) {
return false;
} else {
if(!/^(https?|ftp):\/\//i.test(url)) {
url = 'http://'+url;
$input.val(url);
}
return true;
}
};
$button_ok.on('click', function() {
var x = $e.attr('data-x'),
y = $e.attr('data-y'),
item = $.grep(_this.data, function(v) {
return v.x == x && v.y == y;
}).pop();
if(item) item.text = $input.val();
if(isURL(item.text)) {
if(item) item.url = item.text;
} else {
if(item) item.url = null;
}
if(item) item.url_title = $url_title.val();
if(item) item.url_description = $url_description.val();
if(item) item.url_image = $url_image.val();
_this.addDOM();
_this.element.triggerHandler('change');
//_this.hide();
});
/*$input.on('change', function() {
var x = $e.attr('data-x'),
y = $e.attr('data-y'),
item = $.grep(_this.data, function(v) {
return v.x == x && v.y == y;
}).pop();
if(item) item.text = $input.val();
_this.addDOM();
_this.element.triggerHandler('change');
});
*/
$e.empty().append($input, $button_ok, $button_delete, $url_preview, $url_title, $url_description, $url_image);
});
_this.updateDOM();
};
/****************************************************************
* DATA MANAGEMENT
****************************************************************/
Taggd.prototype.addData = function(data) {
if($.isArray(data)) {
this.data = $.merge(this.data, data);
} else {
this.data.push(data);
}
if(this.initialized) {
this.addDOM();
this.element.triggerHandler('change');
}
};
Taggd.prototype.setData = function(data) {
this.data = data;
if(this.initialized) {
this.addDOM();
}
};
Taggd.prototype.clear = function() {
if(!this.initialized) return;
this.wrapper.find('.taggd-item, .taggd-item-hover').remove();
};
/****************************************************************
* EVENTS
****************************************************************/
Taggd.prototype.on = function(event, handler) {
if(
typeof event !== 'string' ||
typeof handler !== 'function'
) return;
this.element.on(event, handler);
};
/****************************************************************
* TAGS MANAGEMENT
****************************************************************/
Taggd.prototype.iterateTags = function(a, yep) {
var func;
if($.isNumeric(a)) {
func = function(i, e) { return a === i; };
} else if(typeof a === 'string') {
func = function(i, e) { return $(e).is(a); }
} else if($.isArray(a)) {
func = function(i, e) {
var $e = $(e);
var result = false;
$.each(a, function(ai, ae) {
if(
i === ai ||
e === ae ||
$e.is(ae)
) {
result = true;
return false;
}
});
return result;
}
} else if(typeof a === 'object') {
func = function(i, e) {
var $e = $(e);
return $e.is(a);
};
} else if($.isFunction(a)) {
func = a;
} else if(!a) {
func = function() { return true; }
} else return this;
this.wrapper.find('.taggd-item').each(function(i, e) {
if(typeof yep === 'function' && func.call(this, i, e)) {
yep.call(this, i, e);
}
});
return this;
};
Taggd.prototype.show = function(a) {
return this.iterateTags(a, methods.show);
};
Taggd.prototype.hide = function(a) {
return this.iterateTags(a, methods.hide);
};
Taggd.prototype.toggle = function(a) {
return this.iterateTags(a, methods.toggle);
};
/****************************************************************
* CLEANING UP
****************************************************************/
Taggd.prototype.dispose = function() {
this.clear();
this.element.unwrap(this.wrapper);
};
/****************************************************************
* SEMI-PRIVATE
****************************************************************/
Taggd.prototype.addDOM = function() {
var _this = this;
this.clear();
this.element.css({ height: 'auto', width: 'auto' });
var height = this.element.height();
var width = this.element.width();
$.each(this.data, function(i, v) {
var $item = $('<span />');
var $hover;
if(
v.x > 1 && v.x % 1 === 0 &&
v.y > 1 && v.y % 1 === 0
) {
v.x = v.x / width;
v.y = v.y / height;
}
if(typeof v.attributes === 'object') {
$item.attr(v.attributes);
}
$item.attr({
'data-x': v.x,
'data-y': v.y
});
$item.css('position', 'absolute');
$item.addClass('taggd-item');
_this.wrapper.append($item);
if(typeof v.text === 'string' && (v.text.length > 0 || _this.options.edit)) {
$hover = $('<span class="taggd-item-hover" style="position: absolute;" />').html(v.text);
$hover.attr({
'data-x': v.x,
'data-y': v.y
});
_this.wrapper.append($hover);
}
if(typeof _this.options.handlers === 'object') {
$.each(_this.options.handlers, function(event, func) {
var handler;
if(typeof func === 'string' && methods[func]) {
handler = methods[func];
} else if(typeof func === 'function') {
handler = func;
}
$item.on(event, function(e) {
if(!handler) return;
handler.call($item, e, _this.data[i]);
});
});
}
});
this.element.removeAttr('style');
if(this.options.edit) {
this.alterDOM();
}
this.updateDOM();
};
Taggd.prototype.updateDOM = function() {
var _this = this;
this.wrapper.removeAttr('style').css({
height: this.element.height(),
width: this.element.width()
});
this.wrapper.find('span').each(function(i, e) {
var $el = $(e);
var left = $el.attr('data-x') * _this.element.width();
var top = $el.attr('data-y') * _this.element.height();
if($el.hasClass('taggd-item')) {
$el.css({
left: left - $el.outerWidth(true) / 2,
top: top - $el.outerHeight(true) / 2
});
} else if($el.hasClass('taggd-item-hover')) {
if(_this.options.align.x === 'center') {
left -= $el.outerWidth(true) / 2;
} else if(_this.options.align.x === 'right') {
left -= $el.outerWidth(true);
}
if(_this.options.align.y === 'center') {
top -= $el.outerHeight(true) / 2;
} else if(_this.options.align.y === 'bottom') {
top -= $el.outerHeight(true);
}
$el.attr('data-align', $el.outerWidth(true));
$el.css({
left: left + _this.options.offset.left,
top: top + _this.options.offset.top
});
}
});
};
/****************************************************************
* JQUERY LINK
****************************************************************/
$.fn.taggd = function(options, data) {
return new Taggd(this, options, data);
};
})(jQuery);
I thought this would do what i want, since it works with the standard text input box, using .val($e.text()), works fine but as soon as i do the same to the url_title box, for example .val($e.url_title()), i get the error below.
$input = $('<input id="url" type="text" size="16" />')
.val($e.text()),
$url_title = $('<input type="text" id="url_title" class="url_title" />'),
$button_ok = $('<button />')
.html(_this.options.strings.save),
$url_description = $('<input type="text" class="url_description" id="url_description" />'),
$url_image = $('<input type="text" class="url_img" id="url_img" />'),
$url_preview = $('<div id="content"></div>'),
$button_delete = $('<button />')
.html(_this.options.strings.delete);
But if for example i change the $url_title to
$url_title = $('<input type="text" id="url_title" class="url_title" />').val($e.url_title()),
I get a error back in the console:
Uncaught TypeError: undefined is not a function
This is the init code on the main page:
$(document).ready(function() {
var options = {
edit: true,
align: {
y: 'top'
},
offset: {
top: 15
},
handlers: {
//mouseenter: 'show',
click: 'toggle'
}
};
/*var data = [
{ x: 0.22870478413068845, y: 0.41821946169772256, text: 'Eye' },
{ x: 0.51, y: 0.5, text: 'Bird' },
{ x: 0.40, y: 0.3, text: 'Water, obviously' }
];*/
var data = [];
var taggd = $('.taggd').taggd( options, data );
taggd.on('change', function() {
console.log(taggd.data);
});
});
In the console log it logs the values fine:
[Object]0: Objecttext: "http://stackoverflow.com"url: "http://stackoverflow.com"url_description: "Q&A for professional and enthusiast programmers"url_image: "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon#2.png?v=ea71a5211a91&a"url_title: "Stack Overflow"x: 0.41141586360266863y: 0.19444444444444445
I hope someone can shine a light on it and point me in the right direction of what i'm doing wrong.
To simplify it, i want to be able to have a title input and a description input for my tags, how would i achieve this?
Thank you.
I suspect $e.url_title() is causing the error, as far as I know, url_title() isn't a method you can call on jQuery instances.
Presumably you meant to access a variable instead.
I couldn’t find an issue in your scripts, other than the undefined function call, so I basically rewrote the whole thing myself, which seems to work: http://jsbin.com/nexujuhefo/2/edit?js,console,output
I think the problem is Taggd weird logic ;)
Fields now remember data: http://jsbin.com/hosipiyuqa/1/edit?js,console,output

Scoping issue for nested class

I cannot manage to access the method of the nested class. This is what I have tried so far. The main issue is calling TimerTask.execute(). The error states that the task is undefined.
Uncaught TypeError: undefined is not a function
The program should display an increment number for ten runs on a timer.
var TimerTask = new Class({
initalize: function (options) {
this.counter = options.counter;
this.run = options.run;
this.onComplete = options.complete;
this.done = false;
},
execute : function() {
var me = this;
this.counter--;
if (this.done === false || this.counter <= 0) {
this.done = true;
me.onComplete.call(me);
} else {
me.run.call(me);
}
}
});
var Timer = new Class({
initialize: function (options) {
this.id = 0;
this.running = true;
this.count = 0;
this.delay = options.delay || 1000;
this.tasks = options.tasks || [];
},
start: function () {
var me = this;
me.id = setInterval(function tick() {
if (!me.running) return;
for (var i = 0; i < me.tasks.length; i++) {
me.tasks[i].execute();
}
me.count++;
}, this.delay);
},
pause: function pause() {
this.running = false;
return this;
},
run: function run() {
this.running = true;
return this;
},
stop: function stop() {
clearInterval(this.id);
this.stopped = true;
return this;
},
schedule: function (task) {
this.tasks.push(task);
}
});
var i = 0;
var t1 = new Timer({
delay: 1000,
tasks: [
new TimerTask({
run: function () {
document.getElementById('output').innerHTML = parseInt(i++, 10);
},
onComplete: function () {
alert('DONE!');
},
counter: 10
})]
});
t1.start();
<script src="//cdnjs.cloudflare.com/ajax/libs/mootools/1.5.0/mootools-core-full-compat.min.js"></script>
<div id="output"></div>
Oh, wow. Cannot believe that no one caught the typo in TimerTask. No wonder I kept getting the prototype instead of the instance. I spelled "initialize" without the 3rd "i"...
Anyways, I fixed the issue and the code is glorious.
Note: I was using this as the basis for my timer -- https://gist.github.com/NV/363465
var TimerTask = new Class({
initialize: function (options) {
this.counter = options.counter || 0;
this.run = options.run;
this.onComplete = options.onComplete;
this.active = true;
this.isInfinite = this.counter === 0;
},
execute: function () {
if (!this.isInfinite && this.counter === 0) {
this.active = false;
if (this.onComplete !== undefined) {
this.onComplete();
}
} else {
this.run();
if (!this.isInfinite) {
this.counter--;
}
}
},
isActive: function () {
return this.active;
}
});
var Timer = new Class({
initialize: function (options) {
this.id = 0;
this.running = true;
this.count = 0;
this.delay = options.delay || 1000;
this.tasks = options.tasks || [];
Timer.all.push(this);
},
start: function () {
var me = this;
me.id = setInterval(function tick() {
if (!me.running) return;
for (var i = 0; i < me.tasks.length; i++) {
var task = me.tasks[i];
if (task.isActive()) {
task.execute();
} else {
console.log('Task is complete...');
}
}
me.count++;
}, this.delay);
},
pause: function pause() {
this.running = false;
return this;
},
run: function run() {
this.running = true;
return this;
},
stop: function stop() {
clearInterval(this.id);
this.stopped = true;
return this;
},
schedule: function (task) {
this.tasks.push(task);
}
});
Timer.extend({
all : [],
pause : function pause() {
var all = Timer.all;
for (var i = 0; i < all.length; i++) {
all[i].pause();
}
return all;
},
run : function run() {
var all = Timer.all;
for (var i = 0; i < all.length; i++) {
all[i].run();
}
return all;
},
stop : function stop() {
var all = Timer.all;
for (var i = 0; i < all.length; i++) {
all[i].stop();
}
return all;
}
});
function print(id, value) {
document.getElementById(id).innerHTML = value;
}
var i = 0;
var t1 = new Timer({
delay: 100,
tasks: [
new TimerTask({
run: function () {
print('output1', String.fromCharCode(65 + i));
},
onComplete: function () {
console.log('Task 1 complete...');
},
counter: 26
}),
new TimerTask({
run: function () {
print('output2', parseInt(i++, 10));
}
})]
});
t1.start();
// After 4 seconds, stop all timers.
setTimeout(function() {
Timer.stop();
}, 4000);
<script src="//cdnjs.cloudflare.com/ajax/libs/mootools/1.5.0/mootools-core-full-compat.min.js"></script>
<div id="output1"></div>
<div id="output2"></div>

Categories

Resources