I am new to jquery. I have found this code for getting touch events. but it shows this. I don't know how to solve this problem.
error message
Uncaught SyntaxError: Unexpected token < in dev_touch.js
My code :
dev_touch.js
;(function($) {
'use strict'
var $html = $('html');
mainBody = main.find('body');
main.addClass("dev_toucher");
mainBody.append("<div></div>").attr("class", "dev_ui_toucher");
if (typeof $html.createEvent !== 'function') return false // no tap events here
// helpers
var useJquery = typeof jQuery !== 'undefined',
msPointerEnabled = !!navigator.pointerEnabled || navigator.msPointerEnabled,
isTouch = (!!('ontouchstart' in win) && navigator.userAgent.indexOf('PhantomJS') < 0) || msPointerEnabled,
msEventType = function(type) {
var lo = type.toLowerCase(),
ms = 'MS' + type
return navigator.msPointerEnabled ? ms : lo
},
touchevents = {
touchstart: msEventType('PointerDown') + ' touchstart',
touchend: msEventType('PointerUp') + ' touchend',
touchmove: msEventType('PointerMove') + ' touchmove'
},
setListener = function(elm, events, callback) {
var eventsArray = events.split(' '),
i = eventsArray.length
while (i--) {
elm.addEventListener(eventsArray[i], callback, false)
}
},
getPointerEvent = function(event) {
return event.targetTouches ? event.targetTouches[0] : event
},
getTimestamp = function () {
return new Date().getTime()
},
sendEvent = function(elm, eventName, originalEvent, data) {
var customEvent = $html.createEvent('Event')
customEvent.originalEvent = originalEvent
data = data || {}
data.x = currX
data.y = currY
data.distance = data.distance
// jquery
if (useJquery) {
customEvent = $.Event(eventName, {originalEvent: originalEvent})
jQuery(elm).trigger(customEvent, data)
}
// addEventListener
if (customEvent.initEvent) {
for (var key in data) {
customEvent[key] = data[key]
}
customEvent.initEvent(eventName, true, true)
elm.dispatchEvent(customEvent)
}
// inline
if (elm['on' + eventName])
elm['on' + eventName](customEvent)
},
onTouchStart = function(e) {
var pointer = getPointerEvent(e)
// caching the current x
cachedX = currX = pointer.pageX
// caching the current y
cachedY = currY = pointer.pageY
timestamp = getTimestamp()
tapNum++
// we will use these variables on the touchend events
},
onTouchEnd = function(e) {
var eventsArr = [],
now = getTimestamp(),
deltaY = cachedY - currY,
deltaX = cachedX - currX
// clear the previous timer in case it was set
clearTimeout(tapTimer)
if (deltaX <= -swipeThreshold)
eventsArr.push('swiperight')
if (deltaX >= swipeThreshold)
eventsArr.push('swipeleft')
if (deltaY <= -swipeThreshold)
eventsArr.push('swipedown')
if (deltaY >= swipeThreshold)
eventsArr.push('swipeup')
if (eventsArr.length) {
for (var i = 0; i < eventsArr.length; i++) {
var eventName = eventsArr[i]
sendEvent(e.target, eventName, e, {
distance: {
x: Math.abs(deltaX),
y: Math.abs(deltaY)
}
})
}
} else {
if (
cachedX >= currX - tapPrecision &&
cachedX <= currX + tapPrecision &&
cachedY >= currY - tapPrecision &&
cachedY <= currY + tapPrecision
){
if((timestamp + tapThreshold) - now >= 0){
// Here you get the Tap event
sendEvent(e.target, (tapNum === 2) && (target === e.target) ? 'dbltap' : 'tap', e)
target= e.target
}
else if((timestamp + longtapThreshold) - now <= 0){
// Here you get the Tap event
sendEvent(e.target,'longtap', e)
target= e.target
}
}
// reset the tap counter
tapTimer = setTimeout(function() {
tapNum = 0
}, dbltapThreshold)
}
},
onTouchMove = function(e) {
var pointer = getPointerEvent(e)
currX = pointer.pageX
currY = pointer.pageY
},
swipeThreshold = win.SWIPE_THRESHOLD || 100,
tapThreshold = win.TAP_THRESHOLD || 150, // range of time where a tap event could be detected
dbltapThreshold = win.DBL_TAP_THRESHOLD || 200, // delay needed to detect a double tap
longtapThreshold = win.LONG_TAP_THRESHOLD || 1000, // delay needed to detect a long tap
tapPrecision = win.TAP_PRECISION / 2 || 60 / 2, // touch events boundaries ( 60px by default )
justTouchEvents = win.JUST_ON_TOUCH_DEVICES || isTouch,
tapNum = 0,
currX, currY, cachedX, cachedY, tapTimer, timestamp, target
//setting the events listeners
setListener($html, touchevents.touchstart + (justTouchEvents ? '' : ' mousedown'), onTouchStart)
setListener($html, touchevents.touchend + (justTouchEvents ? '' : ' mouseup'), onTouchEnd)
setListener($html, touchevents.touchmove + (justTouchEvents ? '' : ' mousemove'), onTouchMove)
//test.on('tap',updateHtml);
//test.on('dbltap',updateHtml);
//test.on('longtap',updateHtml);
//test.on('swipeup',updateHtml);
//test.on('swipedown',updateHtml);
//test.on('swipeleft',updateHtml);
//test.on('swiperight',updateHtml);
}(document, window))
Can anyone help ?
I would be willing to be that you're being served an HTML file instead of your JavaScript file. Here's how to check:
Right-click anywhere on the page
Select 'Inspect Element'
Find your JS file and examine the contents.
See the picture for a pictorial representation with Firefox.
Related
I have some code that I've used to create controls for a long time, and it works well, in that it properly captures and releases the mouse (at least in chrome).
function createSlider(slider, width, height)
{
slider.width = width;
slider.height = height;
slider.style.display = 'inline';
//
slider.onchange = new Event('onchange');
//
slider.addEventListener('mousedown', function(e)
{
var e = window.event || e;
if (e.button == 0)
{
e.preventDefault();
if (slider.setCapture)
slider.setCapture();
slider.mouseDown0 = true;
slider.sx = e.clientX;
slider.sv = slider.value;
}
});
slider.addEventListener('losecapture', function()
{
slider.mouseDown0 = false;
});
document.addEventListener('mouseup', function(e)
{
var e = window.event || e;
if (e.button == 0 && slider.mouseDown0)
slider.mouseDown0 = false;
}, true);
(slider.setCapture ? slider : document).addEventListener('mousemove', function(e)
{
if (slider.mouseDown0)
{
var dx = slider.sx - e.clientX;
var adaptive = 10 * Math.pow(Math.abs(dx), slider.acc);
slider.value = Math.min(Math.max(slider.min, slider.sv - dx*slider.scale*adaptive), slider.max);
//TODO: if (log) do log scaling
slider.paint();
slider.dispatchEvent(slider.onchange);
}
}, true);
slider.onmousewheel = function(e)
{
e.preventDefault();
var s = e.target;
s.value = Math.min(Math.max(s.min, s.value + (e.wheelDeltaY > 0 ? 1 : -1) * s.scale), s.max);
s.dispatchEvent(s.onchange);
s.paint();
};
slider.paint = function()
{
//...
};
//
slider.paint();
}
But when I tried using this code inside of a Figma plugin window, it loses mouse capture as soon as the mouse leaves the window. Is there something that I need to adjust for this to work?
Apparently you cannot, but you can use pointer lock to solve the issue for some situations.
I have a website that uses smooth scroll which works great.. But once I added the following code:
var $ = jQuery.noConflict();
$(document).ready(function() {
$(function() {
var $ticker = $('#news-ticker'),
$first = $('.news-ticket-class li:first-child', $ticker);
// put an empty space between each letter so we can
// use break word
$('.news-ticket-class li', $ticker).each(function() {
var $this = $(this),
text = $this.text();
$this.html(text.split('').join(''));
});
// begin the animation
function tick($el) {
$el.addClass('tick')
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function() {
$el.removeClass('tick');
var $next = $el.next('li');
$next = $next.length > 0 ? $next : $first;
tick($next);
});
}
tick($first);
});
});
It breaks the smooth scroll. I have tried using the noconflict and that doesn't help as you can see.
The template I use is here that has the smooth scrolling option.
I am stuck with either the above code or my menus working. If you have any other suggestions that mimic someone typing, like this website, please send over my way.
EDIT: This is the smooth scroll script:
//
// SmoothScroll for websites v1.4.0 (Balazs Galambosi)
// http://www.smoothscroll.net/
//
// Licensed under the terms of the MIT license.
//
// You may use it in your theme if you credit me.
// It is also free to use on any individual website.
//
// Exception:
// The only restriction is to not publish any
// extension for browsers or native application
// without getting a written permission first.
//
(function () {
// Scroll Variables (tweakable)
var defaultOptions = {
// Scrolling Core
frameRate : 150, // [Hz]
animationTime : 500, // [ms]
stepSize : 100, // [px]
// Pulse (less tweakable)
// ratio of "tail" to "acceleration"
pulseAlgorithm : true,
pulseScale : 4,
pulseNormalize : 1,
// Acceleration
accelerationDelta : 50, // 50
accelerationMax : 3, // 3
// Keyboard Settings
keyboardSupport : true, // option
arrowScroll : 50, // [px]
// Other
touchpadSupport : false, // ignore touchpad by default
fixedBackground : true,
excluded : ''
};
var options = defaultOptions;
// Other Variables
var isExcluded = false;
var isFrame = false;
var direction = { x: 0, y: 0 };
var initDone = false;
var root = document.documentElement;
var activeElement;
var observer;
var refreshSize;
var deltaBuffer = [];
var isMac = /^Mac/.test(navigator.platform);
var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32,
pageup: 33, pagedown: 34, end: 35, home: 36 };
/***********************************************
* INITIALIZE
***********************************************/
/**
* Tests if smooth scrolling is allowed. Shuts down everything if not.
*/
function initTest() {
if (options.keyboardSupport) {
addEvent('keydown', keydown);
}
}
/**
* Sets up scrolls array, determines if frames are involved.
*/
function init() {
if (initDone || !document.body) return;
initDone = true;
var body = document.body;
var html = document.documentElement;
var windowHeight = window.innerHeight;
var scrollHeight = body.scrollHeight;
// check compat mode for root element
root = (document.compatMode.indexOf('CSS') >= 0) ? html : body;
activeElement = body;
initTest();
// Checks if this script is running in a frame
if (top != self) {
isFrame = true;
}
/**
* Please duplicate this radar for a Safari fix!
* rdar://22376037
* https://openradar.appspot.com/radar?id=4965070979203072
*
* Only applies to Safari now, Chrome fixed it in v45:
* This fixes a bug where the areas left and right to
* the content does not trigger the onmousewheel event
* on some pages. e.g.: html, body { height: 100% }
*/
else if (scrollHeight > windowHeight &&
(body.offsetHeight <= windowHeight ||
html.offsetHeight <= windowHeight)) {
var fullPageElem = document.createElement('div');
fullPageElem.style.cssText = 'position:absolute; z-index:-10000; ' +
'top:0; left:0; right:0; height:' +
root.scrollHeight + 'px';
document.body.appendChild(fullPageElem);
// DOM changed (throttled) to fix height
var pendingRefresh;
refreshSize = function () {
if (pendingRefresh) return; // could also be: clearTimeout(pendingRefresh);
pendingRefresh = setTimeout(function () {
if (isExcluded) return; // could be running after cleanup
fullPageElem.style.height = '0';
fullPageElem.style.height = root.scrollHeight + 'px';
pendingRefresh = null;
}, 500); // act rarely to stay fast
};
setTimeout(refreshSize, 10);
addEvent('resize', refreshSize);
// TODO: attributeFilter?
var config = {
attributes: true,
childList: true,
characterData: false
// subtree: true
};
observer = new MutationObserver(refreshSize);
observer.observe(body, config);
if (root.offsetHeight <= windowHeight) {
var clearfix = document.createElement('div');
clearfix.style.clear = 'both';
body.appendChild(clearfix);
}
}
// disable fixed background
if (!options.fixedBackground && !isExcluded) {
body.style.backgroundAttachment = 'scroll';
html.style.backgroundAttachment = 'scroll';
}
}
/**
* Removes event listeners and other traces left on the page.
*/
function cleanup() {
observer && observer.disconnect();
removeEvent(wheelEvent, wheel);
removeEvent('mousedown', mousedown);
removeEvent('keydown', keydown);
removeEvent('resize', refreshSize);
removeEvent('load', init);
}
/************************************************
* SCROLLING
************************************************/
var que = [];
var pending = false;
var lastScroll = Date.now();
/**
* Pushes scroll actions to the scrolling queue.
*/
function scrollArray(elem, left, top) {
directionCheck(left, top);
if (options.accelerationMax != 1) {
var now = Date.now();
var elapsed = now - lastScroll;
if (elapsed < options.accelerationDelta) {
var factor = (1 + (50 / elapsed)) / 2;
if (factor > 1) {
factor = Math.min(factor, options.accelerationMax);
left *= factor;
top *= factor;
}
}
lastScroll = Date.now();
}
// push a scroll command
que.push({
x: left,
y: top,
lastX: (left < 0) ? 0.99 : -0.99,
lastY: (top < 0) ? 0.99 : -0.99,
start: Date.now()
});
// don't act if there's a pending queue
if (pending) {
return;
}
var scrollWindow = (elem === document.body);
var step = function (time) {
var now = Date.now();
var scrollX = 0;
var scrollY = 0;
for (var i = 0; i < que.length; i++) {
var item = que[i];
var elapsed = now - item.start;
var finished = (elapsed >= options.animationTime);
// scroll position: [0, 1]
var position = (finished) ? 1 : elapsed / options.animationTime;
// easing [optional]
if (options.pulseAlgorithm) {
position = pulse(position);
}
// only need the difference
var x = (item.x * position - item.lastX) >> 0;
var y = (item.y * position - item.lastY) >> 0;
// add this to the total scrolling
scrollX += x;
scrollY += y;
// update last values
item.lastX += x;
item.lastY += y;
// delete and step back if it's over
if (finished) {
que.splice(i, 1); i--;
}
}
// scroll left and top
if (scrollWindow) {
window.scrollBy(scrollX, scrollY);
}
else {
if (scrollX) elem.scrollLeft += scrollX;
if (scrollY) elem.scrollTop += scrollY;
}
// clean up if there's nothing left to do
if (!left && !top) {
que = [];
}
if (que.length) {
requestFrame(step, elem, (1000 / options.frameRate + 1));
} else {
pending = false;
}
};
// start a new queue of actions
requestFrame(step, elem, 0);
pending = true;
}
/***********************************************
* EVENTS
***********************************************/
/**
* Mouse wheel handler.
* #param {Object} event
*/
function wheel(event) {
if (!initDone) {
init();
}
var target = event.target;
var overflowing = overflowingAncestor(target);
// use default if there's no overflowing
// element or default action is prevented
// or it's a zooming event with CTRL
if (!overflowing || event.defaultPrevented || event.ctrlKey) {
return true;
}
// leave embedded content alone (flash & pdf)
if (isNodeName(activeElement, 'embed') ||
(isNodeName(target, 'embed') && /\.pdf/i.test(target.src)) ||
isNodeName(activeElement, 'object')) {
return true;
}
var deltaX = -event.wheelDeltaX || event.deltaX || 0;
var deltaY = -event.wheelDeltaY || event.deltaY || 0;
if (isMac) {
if (event.wheelDeltaX && isDivisible(event.wheelDeltaX, 120)) {
deltaX = -120 * (event.wheelDeltaX / Math.abs(event.wheelDeltaX));
}
if (event.wheelDeltaY && isDivisible(event.wheelDeltaY, 120)) {
deltaY = -120 * (event.wheelDeltaY / Math.abs(event.wheelDeltaY));
}
}
// use wheelDelta if deltaX/Y is not available
if (!deltaX && !deltaY) {
deltaY = -event.wheelDelta || 0;
}
// line based scrolling (Firefox mostly)
if (event.deltaMode === 1) {
deltaX *= 40;
deltaY *= 40;
}
// check if it's a touchpad scroll that should be ignored
if (!options.touchpadSupport && isTouchpad(deltaY)) {
return true;
}
// scale by step size
// delta is 120 most of the time
// synaptics seems to send 1 sometimes
if (Math.abs(deltaX) > 1.2) {
deltaX *= options.stepSize / 120;
}
if (Math.abs(deltaY) > 1.2) {
deltaY *= options.stepSize / 120;
}
scrollArray(overflowing, deltaX, deltaY);
event.preventDefault();
scheduleClearCache();
}
/**
* Keydown event handler.
* #param {Object} event
*/
function keydown(event) {
var target = event.target;
var modifier = event.ctrlKey || event.altKey || event.metaKey ||
(event.shiftKey && event.keyCode !== key.spacebar);
// our own tracked active element could've been removed from the DOM
if (!document.body.contains(activeElement)) {
activeElement = document.activeElement;
}
// do nothing if user is editing text
// or using a modifier key (except shift)
// or in a dropdown
// or inside interactive elements
var inputNodeNames = /^(textarea|select|embed|object)$/i;
var buttonTypes = /^(button|submit|radio|checkbox|file|color|image)$/i;
if ( inputNodeNames.test(target.nodeName) ||
isNodeName(target, 'input') && !buttonTypes.test(target.type) ||
isNodeName(activeElement, 'video') ||
isInsideYoutubeVideo(event) ||
target.isContentEditable ||
event.defaultPrevented ||
modifier ) {
return true;
}
// spacebar should trigger button press
if ((isNodeName(target, 'button') ||
isNodeName(target, 'input') && buttonTypes.test(target.type)) &&
event.keyCode === key.spacebar) {
return true;
}
var shift, x = 0, y = 0;
var elem = overflowingAncestor(activeElement);
var clientHeight = elem.clientHeight;
if (elem == document.body) {
clientHeight = window.innerHeight;
}
switch (event.keyCode) {
case key.up:
y = -options.arrowScroll;
break;
case key.down:
y = options.arrowScroll;
break;
case key.spacebar: // (+ shift)
shift = event.shiftKey ? 1 : -1;
y = -shift * clientHeight * 0.9;
break;
case key.pageup:
y = -clientHeight * 0.9;
break;
case key.pagedown:
y = clientHeight * 0.9;
break;
case key.home:
y = -elem.scrollTop;
break;
case key.end:
var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
y = (damt > 0) ? damt+10 : 0;
break;
case key.left:
x = -options.arrowScroll;
break;
case key.right:
x = options.arrowScroll;
break;
default:
return true; // a key we don't care about
}
scrollArray(elem, x, y);
event.preventDefault();
scheduleClearCache();
}
/**
* Mousedown event only for updating activeElement
*/
function mousedown(event) {
activeElement = event.target;
}
/***********************************************
* OVERFLOW
***********************************************/
var uniqueID = (function () {
var i = 0;
return function (el) {
return el.uniqueID || (el.uniqueID = i++);
};
})();
var cache = {}; // cleared out after a scrolling session
var clearCacheTimer;
//setInterval(function () { cache = {}; }, 10 * 1000);
function scheduleClearCache() {
clearTimeout(clearCacheTimer);
clearCacheTimer = setInterval(function () { cache = {}; }, 1*1000);
}
function setCache(elems, overflowing) {
for (var i = elems.length; i--;)
cache[uniqueID(elems[i])] = overflowing;
return overflowing;
}
// (body) (root)
// | hidden | visible | scroll | auto |
// hidden | no | no | YES | YES |
// visible | no | YES | YES | YES |
// scroll | no | YES | YES | YES |
// auto | no | YES | YES | YES |
function overflowingAncestor(el) {
var elems = [];
var body = document.body;
var rootScrollHeight = root.scrollHeight;
do {
var cached = cache[uniqueID(el)];
if (cached) {
return setCache(elems, cached);
}
elems.push(el);
if (rootScrollHeight === el.scrollHeight) {
var topOverflowsNotHidden = overflowNotHidden(root) && overflowNotHidden(body);
var isOverflowCSS = topOverflowsNotHidden || overflowAutoOrScroll(root);
if (isFrame && isContentOverflowing(root) ||
!isFrame && isOverflowCSS) {
return setCache(elems, getScrollRoot());
}
} else if (isContentOverflowing(el) && overflowAutoOrScroll(el)) {
return setCache(elems, el);
}
} while (el = el.parentElement);
}
function isContentOverflowing(el) {
return (el.clientHeight + 10 < el.scrollHeight);
}
// typically for <body> and <html>
function overflowNotHidden(el) {
var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
return (overflow !== 'hidden');
}
// for all other elements
function overflowAutoOrScroll(el) {
var overflow = getComputedStyle(el, '').getPropertyValue('overflow-y');
return (overflow === 'scroll' || overflow === 'auto');
}
/***********************************************
* HELPERS
***********************************************/
function addEvent(type, fn) {
window.addEventListener(type, fn, false);
}
function removeEvent(type, fn) {
window.removeEventListener(type, fn, false);
}
function isNodeName(el, tag) {
return (el.nodeName||'').toLowerCase() === tag.toLowerCase();
}
function directionCheck(x, y) {
x = (x > 0) ? 1 : -1;
y = (y > 0) ? 1 : -1;
if (direction.x !== x || direction.y !== y) {
direction.x = x;
direction.y = y;
que = [];
lastScroll = 0;
}
}
var deltaBufferTimer;
if (window.localStorage && localStorage.SS_deltaBuffer) {
deltaBuffer = localStorage.SS_deltaBuffer.split(',');
}
function isTouchpad(deltaY) {
if (!deltaY) return;
if (!deltaBuffer.length) {
deltaBuffer = [deltaY, deltaY, deltaY];
}
deltaY = Math.abs(deltaY)
deltaBuffer.push(deltaY);
deltaBuffer.shift();
clearTimeout(deltaBufferTimer);
deltaBufferTimer = setTimeout(function () {
if (window.localStorage) {
localStorage.SS_deltaBuffer = deltaBuffer.join(',');
}
}, 1000);
return !allDeltasDivisableBy(120) && !allDeltasDivisableBy(100);
}
function isDivisible(n, divisor) {
return (Math.floor(n / divisor) == n / divisor);
}
function allDeltasDivisableBy(divisor) {
return (isDivisible(deltaBuffer[0], divisor) &&
isDivisible(deltaBuffer[1], divisor) &&
isDivisible(deltaBuffer[2], divisor));
}
function isInsideYoutubeVideo(event) {
var elem = event.target;
var isControl = false;
if (document.URL.indexOf ('www.youtube.com/watch') != -1) {
do {
isControl = (elem.classList &&
elem.classList.contains('html5-video-controls'));
if (isControl) break;
} while (elem = elem.parentNode);
}
return isControl;
}
var requestFrame = (function () {
return (window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback, element, delay) {
window.setTimeout(callback, delay || (1000/60));
});
})();
var MutationObserver = (window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver);
var getScrollRoot = (function() {
var SCROLL_ROOT;
return function() {
if (!SCROLL_ROOT) {
var dummy = document.createElement('div');
dummy.style.cssText = 'height:10000px;width:1px;';
document.body.appendChild(dummy);
var bodyScrollTop = document.body.scrollTop;
var docElScrollTop = document.documentElement.scrollTop;
window.scrollBy(0, 3);
if (document.body.scrollTop != bodyScrollTop)
(SCROLL_ROOT = document.body);
else
(SCROLL_ROOT = document.documentElement);
window.scrollBy(0, -3);
document.body.removeChild(dummy);
}
return SCROLL_ROOT;
};
})();
/***********************************************
* PULSE (by Michael Herf)
***********************************************/
/**
* Viscous fluid with a pulse for part and decay for the rest.
* - Applies a fixed force over an interval (a damped acceleration), and
* - Lets the exponential bleed away the velocity over a longer interval
* - Michael Herf, http://stereopsis.com/stopping/
*/
function pulse_(x) {
var val, start, expx;
// test
x = x * options.pulseScale;
if (x < 1) { // acceleartion
val = x - (1 - Math.exp(-x));
} else { // tail
// the previous animation ended here:
start = Math.exp(-1);
// simple viscous drag
x -= 1;
expx = 1 - Math.exp(-x);
val = start + (expx * (1 - start));
}
return val * options.pulseNormalize;
}
function pulse(x) {
if (x >= 1) return 1;
if (x <= 0) return 0;
if (options.pulseNormalize == 1) {
options.pulseNormalize /= pulse_(1);
}
return pulse_(x);
}
/***********************************************
* FIRST RUN
***********************************************/
var userAgent = window.navigator.userAgent;
var isEdge = /Edge/.test(userAgent); // thank you MS
var isChrome = /chrome/i.test(userAgent) && !isEdge;
var isSafari = /safari/i.test(userAgent) && !isEdge;
var isMobile = /mobile/i.test(userAgent);
var isIEWin7 = /Windows NT 6.1/i.test(userAgent) && /rv:11/i.test(userAgent);
var isEnabledForBrowser = (isChrome || isSafari || isIEWin7) && !isMobile;
var wheelEvent;
if ('onwheel' in document.createElement('div'))
wheelEvent = 'wheel';
else if ('onmousewheel' in document.createElement('div'))
wheelEvent = 'mousewheel';
if (wheelEvent && isEnabledForBrowser) {
addEvent(wheelEvent, wheel);
addEvent('mousedown', mousedown);
addEvent('load', init);
}
/***********************************************
* PUBLIC INTERFACE
***********************************************/
function SmoothScroll(optionsToSet) {
for (var key in optionsToSet)
if (defaultOptions.hasOwnProperty(key))
options[key] = optionsToSet[key];
}
SmoothScroll.destroy = cleanup;
if (window.SmoothScrollOptions) // async API
SmoothScroll(window.SmoothScrollOptions)
if (typeof define === 'function' && define.amd)
define(function() {
return SmoothScroll;
});
else if ('object' == typeof exports)
module.exports = SmoothScroll;
else
window.SmoothScroll = SmoothScroll;
})();
I believe the purpose of noConflict is to relinquish control of the $ global variable for external libraries, so doing var $ = jQuery.noConflict(); just sets the global $ to what noConflict returns, which is the jQuery object. In other words, it doesn't buy you anything - it's simply setting $ to what $ would be, even without the noConflict() method.
Change the $ to $j like the following:
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j(function() {
var $ticker = $j('#news-ticker'),
$first = $j('.news-ticket-class li:first-child', $ticker);
// put an empty space between each letter so we can
// use break word
$j('.news-ticket-class li', $ticker).each(function() {
var $this = $j(this),
text = $this.text();
$this.html(text.split('').join(''));
});
// begin the animation
function tick($el) {
$el.addClass('tick')
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function() {
$el.removeClass('tick');
var $next = $el.next('li');
$next = $next.length > 0 ? $next : $first;
tick($next);
});
}
tick($first);
});
});
I have a watch looking at my sliders model and when I want to set one of the properties to visible or enabled it doesn't seem to want to fire the watch changed event. If I click the button it should hide or disable the handle and it does not. If I drag another handle the updateDOM is called and the handle is then hidden or disabled. Not sure what I am doing incorrectly here.
scope.$watch('sliders', function(oldValue, newValue) {
console.log('sliders Update: ', oldValue, ' : ', newValue);
updateDOM();
});
Here is a working plunk: http://plnkr.co/edit/I3A9H8qTs0z4CVaYnyJZ?p=preview
'use strict';
angular.module('angularMultiSlider', [])
.directive('multiSliderKey', function($compile) {
return {
restrict: 'EA',
transclude: true,
scope: {
displayFilter: '#',
sliders : '=ngModel'
},
link: function(scope, element) {
var sliderStr = '';
if (scope.displayFilter === undefined) scope.displayFilter = '';
var filterExpression = scope.displayFilter === '' ? '' : ' | ' + scope.displayFilter;
angular.forEach(scope.sliders, function(slider, key){
var colorKey = slider.color ? '<span style="background-color:' + slider.color + ';"></span> ' : '';
sliderStr += '<div class="key">' + colorKey + '{{ sliders[' + key.toString() + '].title }} <strong>{{ sliders[' + key.toString() + '].value ' + filterExpression + '}}</strong></div>';
});
var sliderControls = angular.element('<div class="angular-multi-slider-key">' + sliderStr + '</div>');
element.append(sliderControls);
$compile(sliderControls)(scope);
}
}
})
.directive('multiSlider', function($compile, $filter) {
var events = {
mouse: {
start: 'mousedown',
move: 'mousemove',
end: 'mouseup'
},
touch: {
start: 'touchstart',
move: 'touchmove',
end: 'touchend'
}
};
function roundStep(value, precision, step, floor) {
var remainder = (value - floor) % step;
var steppedValue = remainder > (step / 2) ? value + step - remainder : value - remainder;
var decimals = Math.pow(10, precision);
var roundedValue = steppedValue * decimals / decimals;
return parseFloat(roundedValue.toFixed(precision));
}
function offset(element, position) {
return element.css({
left: position
});
}
function pixelize(position) {
return parseInt(position) + 'px';
}
function contain(value) {
if (isNaN(value)) return value;
return Math.min(Math.max(0, value), 100);
}
function overlaps(b1, b2, offsetTop) {
function comparePositions(p1, p2) {
var r1 = p1[0] < p2[0] ? p1 : p2;
var r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
var posB1 = [[ b1.offsetLeft, b1.offsetLeft + b1.offsetWidth ], [ offsetTop, offsetTop - b1.scrollTop + b1.offsetHeight ]],
posB2 = [[ b2.offsetLeft, b2.offsetLeft + b2.offsetWidth ], [ b2.offsetTop, b2.offsetTop - b2.scrollTop + b2.offsetHeight ]];
return comparePositions( posB1[0], posB2[0] ) && comparePositions( posB1[1], posB2[1] );
}
return {
restrict: 'EA',
require: '?ngModel',
scope: {
floor: '#',
ceiling: '#',
step: '#',
precision: '#',
bubbles: '#',
displayFilter: '#',
sliders: '=ngModel'
},
template :
'<div class="bar"></div>',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return; // do nothing if no ng-model
//base copy to see if sliders returned to original
var original;
ngModel.$render = function() {
original = angular.copy(scope.sliders);
};
element.addClass('angular-multi-slider');
// DOM Components
if (scope.displayFilter === undefined) scope.displayFilter = '';
var filterExpression = scope.displayFilter === '' ? '' : ' | ' + scope.displayFilter;
var sliderStr = '<div class="limit floor">{{ floor ' + filterExpression + ' }}</div>' +
'<div class="limit ceiling">{{ ceiling ' + filterExpression + '}}</div>';
angular.forEach(scope.sliders, function(slider, key){
sliderStr += '<div class="handle"></div><div class="bubble">{{ sliders[' + key.toString() + '].title }}{{ sliders[' + key.toString() + '].value ' + filterExpression + ' }}</div>';
});
var sliderControls = angular.element(sliderStr);
element.append(sliderControls);
$compile(sliderControls)(scope);
var children = element.children();
var bar = angular.element(children[0]),
ngDocument = angular.element(document),
floorBubble = angular.element(children[1]),
ceilBubble = angular.element(children[2]),
bubbles = [],
handles = [];
angular.forEach(scope.sliders, function(slider, key) {
handles.push(angular.element(children[(key * 2) + 3]));
bubbles.push(angular.element(children[(key * 2) + 4]));
});
// Control Dimensions Used for Calculations
var handleHalfWidth = 0,
barWidth = 0,
minOffset = 0,
maxOffset = 0,
minValue = 0,
maxValue = 0,
valueRange = 0,
offsetRange = 0,
bubbleTop = undefined,
bubbleHeight = undefined,
handleTop = undefined,
handleHeight = undefined;
if (scope.step === undefined) scope.step = 10;
if (scope.floor === undefined) scope.floor = 0;
if (scope.ceiling === undefined) scope.ceiling = 500;
if (scope.precision === undefined) scope.precision = 2;
if (scope.bubbles === undefined) scope.bubbles = false;
var bindingsSet = false;
var updateCalculations = function() {
scope.floor = roundStep(parseFloat(scope.floor), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
scope.ceiling = roundStep(parseFloat(scope.ceiling), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
angular.forEach(scope.sliders, function(slider) {
slider.value = roundStep(parseFloat(slider.value), parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
});
handleHalfWidth = handles[0][0].offsetWidth / 2;
barWidth = bar[0].offsetWidth;
minOffset = 0;
maxOffset = barWidth - handles[0][0].offsetWidth;
minValue = parseFloat(scope.floor);
maxValue = parseFloat(scope.ceiling);
valueRange = maxValue - minValue;
offsetRange = maxOffset - minOffset;
};
var updateDOM = function () {
updateCalculations();
var percentOffset = function (offset) {
return contain(((offset - minOffset) / offsetRange) * 100);
};
var percentValue = function (value) {
return contain(((value - minValue) / valueRange) * 100);
};
var pixelsToOffset = function (percent) {
return pixelize(percent * offsetRange / 100);
};
var setHandles = function () {
offset(ceilBubble, pixelize(barWidth - ceilBubble[0].offsetWidth));
angular.forEach(scope.sliders, function(slider,key){
if (slider.color) {
handles[key].css({'background-color': slider.color});
}
if (slider.value >= minValue && slider.value <= maxValue) {
offset(handles[key], pixelsToOffset(percentValue(slider.value)));
offset(bubbles[key], pixelize(handles[key][0].offsetLeft - (bubbles[key][0].offsetWidth / 2) + handleHalfWidth));
handles[key].css({'display': 'block'});
if ('' + scope.bubbles === 'true') {
bubbles[key].css({'display': 'block'});
}
} else {
handles[key].css({'display': 'none'});
bubbles[key].css({'display': 'none'});
}
if (slider.hasOwnProperty("visible") && slider.visible === false) {
handles[key].css({'display': 'none'});
bubbles[key].css({'display': 'none'});
}
if (slider.hasOwnProperty("enabled") && slider.enabled === false) {
handles[key].addClass('disabled');
bubbles[key].addClass('disabled');
} else {
handles[key].removeClass('disabled');
bubbles[key].removeClass('disabled');
}
});
};
var resetBubbles = function() {
if (scope.sliders.length > 1) {
//timeout must be longer than css animation for proper bubble collision detection
for (var i = 0; i < scope.sliders.length; i++) {
(function (index) {
setTimeout(function () {
overlapCheck(index);
}, i * 150);
})(i);
}
}
};
var overlapCheck = function(currentRef) {
var safeAtLevel = function(cRef, level) {
for (var x = 0; x < scope.sliders.length; x++) {
if (x != cRef && overlaps(bubbles[cRef][0], bubbles[x][0], (bubbleTop * level))) {
return safeAtLevel(cRef, level + 1);
}
}
return level;
};
if (scope.sliders.length > 1) {
var safeLevel = safeAtLevel(currentRef, 1) - 1;
handles[currentRef].css({top: pixelize((-1 * (safeLevel * bubbleHeight)) + handleTop), height: pixelize(handleHeight + (bubbleHeight * safeLevel)), 'z-index': 99-safeLevel});
bubbles[currentRef].css({top: pixelize(bubbleTop - (bubbleHeight * safeLevel))});
}
};
var bind = function (handle, bubble, currentRef, events) {
var onEnd = function () {
handle.removeClass('grab');
bubble.removeClass('grab');
if (!(''+scope.bubbles === 'true')) {
bubble.removeClass('active');
}
ngDocument.unbind(events.move);
ngDocument.unbind(events.end);
if (angular.equals(scope.sliders, original)) {
ngModel.$setPristine();
}
//Move possible elevated bubbles back down if one below it moved.
resetBubbles();
scope.$apply();
};
var onMove = function (event) {
// Suss out which event type we are capturing and get the x value
var eventX = 0;
if (event.clientX !== undefined) {
eventX = event.clientX;
}
else if ( event.touches !== undefined && event.touches.length) {
eventX = event.touches[0].clientX;
}
else if ( event.originalEvent !== undefined &&
event.originalEvent.changedTouches !== undefined &&
event.originalEvent.changedTouches.length) {
eventX = event.originalEvent.changedTouches[0].clientX;
}
var newOffset = Math.max(Math.min((eventX - element[0].getBoundingClientRect().left - handleHalfWidth), maxOffset), minOffset),
newPercent = percentOffset(newOffset),
newValue = minValue + (valueRange * newPercent / 100.0);
newValue = roundStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor));
scope.sliders[currentRef].value = newValue;
setHandles();
overlapCheck(currentRef);
ngModel.$setDirty();
scope.$apply();
};
var onStart = function (event) {
if (scope.sliders[currentRef].hasOwnProperty("enabled") && scope.sliders[currentRef].enabled === false) {
bubble.addClass('disabled');
handle.addClass('disabled');
return;
}
updateCalculations();
bubble.addClass('active grab');
handle.addClass('active grab');
setHandles();
event.stopPropagation();
event.preventDefault();
ngDocument.bind(events.move, onMove);
return ngDocument.bind(events.end, onEnd);
};
handle.bind(events.start, onStart);
};
var setBindings = function () {
var method, i;
var inputTypes = ['touch', 'mouse'];
for (i = 0; i < inputTypes.length; i++) {
method = inputTypes[i];
angular.forEach(scope.sliders, function(slider, key){
bind(handles[key], bubbles[key], key, events[method]);
if (scope.sliders[key].hasOwnProperty("enabled") && scope.sliders[key].enabled === false) {
handles[key].addClass('disabled');
bubbles[key].addClass('disabled');
}
});
}
bindingsSet = true;
};
if (!bindingsSet) {
setBindings();
// Timeout needed because bubbles offsetWidth is incorrect during initial rendering of html elements
setTimeout( function() {
if ('' + scope.bubbles === 'true') {
angular.forEach(bubbles, function (bubble) {
bubble.addClass('active');
});
}
updateCalculations();
setHandles();
//Get Default sizes of bubbles and handles, assuming each are equal, calculated from css
handleTop = handleTop === undefined ? handles[0][0].offsetTop : handleTop;
handleHeight = handleHeight === undefined ? handles[0][0].offsetHeight : handleHeight;
bubbleTop = bubbleTop === undefined ? bubbles[0][0].offsetTop : bubbleTop;
bubbleHeight = bubbleHeight === undefined ? bubbles[0][0].offsetHeight + 7 : bubbleHeight ; //add 7px bottom margin to the bubble offset for handle
resetBubbles();
}, 10);
}
};
// Watch Models based on mode
scope.$watch('sliders', function(oldValue, newValue) {
console.log('sliders Update: ', oldValue, ' : ', newValue);
updateDOM();
});
scope.$watch('ceiling', function() {
bindingsSet = false;
updateDOM();
});
scope.$watch('floor', function() {
bindingsSet = false;
updateDOM();
});
// Update on Window resize
window.addEventListener('resize', updateDOM);
}
}
});
I found the solution here: How to deep watch an array in angularjs? Deep watch /property watch.
$scope.$watch('columns', function() {
// some value in the array has changed
}, true); // watching properties
I am using this custom JavaScript range slider, and I want to be able to get and set the sliders value. I already implemented the set function. (If you have a better way of doing it, please let me know.) I'm having trouble implementing the getValue function
I tried doing the following:
function getValue() {
if (value) {
return value;
}
return;
}
And when I call that function, I get the following error:
Uncaught ReferenceError: getValue is not defined
Creating a global variable, is not an option. How can I get the sliders value?
To set or get the sliders value, I want to be able to do the following:
mySlider.Value = 17; // Set Value
var currentValue = mySlider.Value // Get Value
JSFiddle
function rangeSlider(elem, config, update) {
if (typeof update != "undefined" && update) {
var dragger = elem.getElementsByTagName('span')[0];
var range = elem.getElementsByTagName('div')[0];
var isVertical = config.vertical;
var rangeWidth = range[!isVertical ? 'offsetWidth' : 'offsetHeight'];
var rangeOffset = range[!isVertical ? 'offsetLeft' : 'offsetTop'];
var draggerWidth = dragger[!isVertical ? 'offsetWidth' : 'offsetHeight'];
dragger.style[!isVertical ? 'left' : 'top'] = (config.value / 100 * rangeWidth - (draggerWidth / 2)) + 'px';
return;
}
function getValue() {
if (value) {
return value;
}
return;
}
var html = document.documentElement,
range = document.createElement('div'),
dragger = document.createElement('span'),
down = false,
rangeWidth, rangeOffset, draggerWidth, cachePosition;
var defaults = {
value: 0, // set default value on initiation from `0` to `100` (percentage based)
vertical: false, // vertical or horizontal?
rangeClass: "", // add extra custom class for the range slider track
draggerClass: "", // add extra custom class for the range slider dragger
drag: function(v) { /* console.log(v); */ } // function to return the range slider value into something
};
for (var i in defaults) {
if (typeof config[i] == "undefined") config[i] = defaults[i];
}
function addEventTo(el, ev, fn) {
if (el.addEventListener) {
el.addEventListener(ev, fn, false);
} else if (el.attachEvent) {
el.attachEvent('on' + ev, fn);
} else {
el['on' + ev] = fn;
}
}
var isVertical = config.vertical;
elem.className = (elem.className + ' range-slider ' + (isVertical ? 'range-slider-vertical' : 'range-slider-horizontal')).replace(/^ +/, "");
range.className = ('range-slider-track ' + config.rangeClass).replace(/ +$/, "");
dragger.className = ('dragger ' + config.draggerClass).replace(/ +$/, "");
addEventTo(range, "mousedown", function(e) {
html.className = (html.className + ' no-select').replace(/^ +/, "");
rangeWidth = range[!isVertical ? 'offsetWidth' : 'offsetHeight'];
rangeOffset = range[!isVertical ? 'offsetLeft' : 'offsetTop'];
draggerWidth = dragger[!isVertical ? 'offsetWidth' : 'offsetHeight'];
down = true;
updateDragger(e);
return false;
});
addEventTo(document, "mousemove", function(e) {
updateDragger(e);
});
addEventTo(document, "mouseup", function(e) {
html.className = html.className.replace(/(^| )no-select( |$)/g, "");
down = false;
});
addEventTo(window, "resize", function(e) {
var woh = dragger[!isVertical ? 'offsetWidth' : 'offsetHeight'];
dragger.style[!isVertical ? 'left' : 'top'] = (((cachePosition / 100) * range[!isVertical ? 'offsetWidth' : 'offsetHeight']) - (woh / 2)) + 'px';
down = false;
});
function updateDragger(e) {
e = e || window.event;
var pos = !isVertical ? e.pageX : e.pageY;
if (!pos) {
pos = !isVertical ? e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft : e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
if (down && pos >= rangeOffset && pos <= (rangeOffset + rangeWidth)) {
dragger.style[!isVertical ? 'left' : 'top'] = (pos - rangeOffset - (draggerWidth / 2)) + 'px';
cachePosition = Math.round(((pos - rangeOffset) / rangeWidth) * 100);
config.drag(cachePosition);
}
}
function initDragger() {
var woh = dragger[!isVertical ? 'offsetWidth' : 'offsetHeight'];
cachePosition = ((config.value / 100) * range[!isVertical ? 'offsetWidth' : 'offsetHeight']);
dragger.style[!isVertical ? 'left' : 'top'] = (cachePosition - (woh / 2)) + 'px';
config.drag(config.value);
}
range.appendChild(dragger);
elem.appendChild(range);
initDragger();
}
var slid1 = document.getElementById('range-slider-1');
var btn = document.getElementById('btn');
var anotherBtn = document.getElementById('anotherBtn');
var resultP = document.getElementById('results');
rangeSlider(slid1, {
value: 10,
});
btn.onclick = function() {
rangeSlider(slid1, {
value: 50
}, 1);
}
anotherBtn.onclick = function() {
document.getElementById('results').innerHTML = "Your Current Value is: " + getValue();
}
.range-slider-track {
height: 20px;
}
.range-slider-track:before {
content: "";
display: block;
width: 100%;
height: 2px;
background-color: black;
}
.range-slider-track .dragger {
display: block;
width: 10px;
height: inherit;
position: relative;
background-color: red;
}
<div id="range-slider-1"></div>
<button id="btn">Set Value</button>
<button id="anotherBtn">Get Value</button>
<p id="results"></p>
The function "rangeSlider()" should be handled as an object, not as a function...
You have to create an object:
var mySlider = new rangeSlider(slid1, { value: 10,});
And you can obtain its value as:
mySlider.getValue()
Take a look at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
Paste this javascript into the original fiddle and sett it working:
function rangeSlider(elem, config, update) {
var this_ = this;
this.setValue = function(value) {
var dragger = this.config.elem.getElementsByTagName('span')[0];
var range = this.config.elem.getElementsByTagName('div')[0];
var rangeWidth = range[!this.config.vertical ? 'offsetWidth' : 'offsetHeight'];
var draggerWidth = dragger[!this.config.vertical ? 'offsetWidth' : 'offsetHeight'];
dragger.style[!this.config.vertical ? 'left' : 'top'] = (value / 100 * rangeWidth - (draggerWidth / 2)) + 'px';
this.config.value = value;
};
this.getValue = function() {
return this.config.value;
};
var html = document.documentElement,
range = document.createElement('div'),
dragger = document.createElement('span'),
down = false,
rangeWidth, rangeOffset, draggerWidth, cachePosition;
this.config = {
value: (config.value || 0), // set default value on initiation from `0` to `100` (percentage based)
vertical: (config.vertical || false), // vertical or horizontal?
rangeClass: "", // add extra custom class for the range slider track
draggerClass: "", // add extra custom class for the range slider dragger
drag: function(v) { /* console.log(v); */ }, // function to return the range slider value into something
elem: elem
};
addEventTo = function(el, ev, fn) {
if (el.addEventListener) {
el.addEventListener(ev, fn, false);
} else if (el.attachEvent) {
el.attachEvent('on' + ev, fn);
} else {
el['on' + ev] = fn;
}
}
elem.className = (elem.className + ' range-slider ' + (this.config.vertical ? 'range-slider-vertical' : 'range-slider-horizontal')).replace(/^ +/, "");
range.className = ('range-slider-track ' + config.rangeClass).replace(/ +$/, "");
dragger.className = ('dragger ' + config.draggerClass).replace(/ +$/, "");
addEventTo(range, "mousedown", function(e) {
html.className = (html.className + ' no-select').replace(/^ +/, "");
rangeWidth = range[!this_.config.vertical ? 'offsetWidth' : 'offsetHeight'];
rangeOffset = range[!this_.config.vertical ? 'offsetLeft' : 'offsetTop'];
draggerWidth = dragger[!this_.config.vertical ? 'offsetWidth' : 'offsetHeight'];
down = true;
updateDragger(e);
return false;
});
addEventTo(document, "mousemove", function(e) {
updateDragger(e);
});
addEventTo(document, "mouseup", function(e) {
html.className = html.className.replace(/(^| )no-select( |$)/g, "");
down = false;
});
addEventTo(window, "resize", function(e) {
var woh = dragger[!this.config.vertical ? 'offsetWidth' : 'offsetHeight'];
dragger.style[!this.config.vertical ? 'left' : 'top'] = (((cachePosition / 100) * range[!this.config.vertical ? 'offsetWidth' : 'offsetHeight']) - (woh / 2)) + 'px';
down = false;
});
function updateDragger(e) {
e = e || window.event;
var pos = !this_.config.vertical ? e.pageX : e.pageY;
if (!pos) {
pos = !this_.config.vertical ? e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft : e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
if (down && pos >= rangeOffset && pos <= (rangeOffset + rangeWidth)) {
dragger.style[!this_.config.vertical ? 'left' : 'top'] = (pos - rangeOffset - (draggerWidth / 2)) + 'px';
cachePosition = Math.round(((pos - rangeOffset) / rangeWidth) * 100);
this_.config.value = cachePosition;
this_.config.drag(cachePosition);
}
};
this.initDragger = function() {
var woh = dragger[!this.config.vertical ? 'offsetWidth' : 'offsetHeight'];
cachePosition = ((config.value / 100) * range[!this.config.vertical ? 'offsetWidth' : 'offsetHeight']);
dragger.style[!this.config.vertical ? 'left' : 'top'] = (cachePosition - (woh / 2)) + 'px';
this.config.drag(this.config.value);
};
range.appendChild(dragger);
elem.appendChild(range);
this.initDragger();
}
var slid1 = document.getElementById('range-slider-1');
var btn = document.getElementById('btn');
var anotherBtn = document.getElementById('anotherBtn');
var resultP = document.getElementById('results');
var rs = new rangeSlider(slid1, {
value: 10,
});
var slid2 = document.getElementById('range-slider-2');
var rs2 = new rangeSlider(slid2, {
value: 20,
});
btn.onclick = function() {
rs.setValue(50);
}
anotherBtn.onclick = function() {
document.getElementById('results').innerHTML = "Range 1: " + rs.getValue() + '<br/>Range2: ' + rs2.getValue();
}
And this html also:
<div id="range-slider-1"></div>
<button id="btn">Set Value</button>
<button id="anotherBtn">Get Value</button>
<div id="range-slider-2"></div>
<p id="results"></p>
Like some of the other posters said, you need to fix your function a bit.
I don't have time to clean up the new code, but I'm sure you'll get the idea.
Here are a few things to keep in mind:
You want to create a new object by calling new rangeSlider.
You can assign the new object to a variable so you can use that variable to set or get values.
Notice the var this_ = this statement so we'll have access to the object instance even certain events, because the this in those events may be the actual elements in the DOM.
This new approach supports the multiple sliders in the document, as with your original code, but it is a lot more simpler and cleaner to get and set values.
I'm sure we can clean this code a lot more, so enjoy.
Current best solution i have found:
ko.bindingHandlers.clickedIn = (function () {
function getBounds(element) {
var pos = element.offset();
return {
x: pos.left,
x2: pos.left + element.outerWidth(),
y: pos.top,
y2: pos.top + element.outerHeight()
};
}
function hitTest(o, l) {
function getOffset(o) {
for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight };
o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
return r.r += r.l, r.b += r.t, r;
}
for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i;
b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r))
&& (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i]));
return j ? !!r.length : r;
}
return {
init: function (element, valueAccessor) {
var target = valueAccessor();
$(document).click(function (e) {
if (element._clickedInElementShowing === false && target()) {
var $element = $(element);
var bounds = getBounds($element);
var possibleOverlays = $("[style*=z-index],[style*=absolute]").not(":hidden");
$.each(possibleOverlays, function () {
if (hitTest(element, this)) {
var b = getBounds($(this));
bounds.x = Math.min(bounds.x, b.x);
bounds.x2 = Math.max(bounds.x2, b.x2);
bounds.y = Math.min(bounds.y, b.y);
bounds.y2 = Math.max(bounds.y2, b.y2);
}
});
if (e.clientX < bounds.x || e.clientX > bounds.x2 ||
e.clientY < bounds.y || e.clientY > bounds.y2) {
target(false);
}
}
element._clickedInElementShowing = false;
});
$(element).click(function (e) {
e.stopPropagation();
});
},
update: function (element, valueAccessor) {
var showing = ko.utils.unwrapObservable(valueAccessor());
if (showing) {
element._clickedInElementShowing = true;
}
}
};
})();
It works by first query for all elements with either z-index or absolute position that are visible. It then hit tests those elemnts against the elemnet I want to hide if click outside. If its a hit I calculate a new bound retacle which takes into acount the overlay bounds.
Its not rock solid, but works. Please feel free to comment if you see problems with above approuch
Old question
I'm using Knockout but this applies to DOM/Javascript in general
Im trying to find a reliable way if detecting of you click outside of a element. My code looks like this
ko.bindingHandlers.clickedIn = {
init: function (element, valueAccessor) {
var target = valueAccessor();
var clickedIn = false;
ko.utils.registerEventHandler(document, "click", function (e) {
if (!clickedIn && element._clickedInElementShowing === false) {
target(e.target == element);
}
clickedIn = false;
element._clickedInElementShowing = false;
});
ko.utils.registerEventHandler(element, "click", function (e) {
clickedIn = true;
});
},
update: function (element, valueAccessor) {
var showing = ko.utils.unwrapObservable(valueAccessor());
if (showing) {
element._clickedInElementShowing = true;
}
}
};
It works by both listening to click on target element and document. If you click on document but not target element you click outside of it. This works, but, not for overlay items like datepickers etc. This is because these are not inside the target element but in the body. Can I fix this? Are there better way of determine if clicking outside of element?
edit: This kind of works, but only if the overlay is smaller than the element i want to monitor
ko.bindingHandlers.clickedIn = {
init: function (element, valueAccessor) {
var target = valueAccessor();
$(document).click(function (e) {
if (element._clickedInElementShowing === false) {
var $element = $(element);
var pos = $element.offset();
if (e.clientX < pos.left || e.clientX > (pos.left + $element.width()) ||
e.clientY < pos.top || e.clientY > (pos.top + $element.height())) {
target(false);
}
}
element._clickedInElementShowing = false;
});
$(element).click(function (e) {
e.stopPropagation();
});
},
update: function (element, valueAccessor) {
var showing = ko.utils.unwrapObservable(valueAccessor());
if (showing) {
element._clickedInElementShowing = true;
}
}
};
I would like a more rock solid approuch
This is how I usually solve it:
http://jsfiddle.net/jonigiuro/KLxnV/
$('.container').on('click', function(e) {
alert('hide the child');
});
$('.child').on('click', function(e) {
alert('do nothing');
e.stopPropagation(); //THIS IS THE IMPORTANT PART
});
I don't know how your overlay items are generated, but you could always check if the click target is a child of the element you want to constrain your clicks to.