Anchor link don't work in dreamweaver CC 2015 - html

This is the part code, where the anchor doesn't seem to work, When i click Move P,L,C, pick&place or Approach & depart in the Lessons section, it won't move to the section i want it to go.
<div class="bb-item" id="item2">
<div class="content">
<div class="scroller">
<h2>Lessons</h2>
<p><a href="#item3" class="button" >Move P, L, C</a></p>
<p> Pick and place </p>
<p>Approach and depart</p>
</div>
</div>
</div>
<div class="bb-item" id="item3">
<div class="content">
<div class="scroller">
<a name="item3"></a>
<h2> Move P, L, C</h2>
</div>
</div>
</div>
This is the javascript
(function() {
var event = jQuery.event,
//helper that finds handlers by type and calls back a function, this is basically handle
// events - the events object
// types - an array of event types to look for
// callback(type, handlerFunc, selector) - a callback
// selector - an optional selector to filter with, if there, matches by selector
// if null, matches anything, otherwise, matches with no selector
findHelper = function( events, types, callback, selector ) {
var t, type, typeHandlers, all, h, handle,
namespaces, namespace,
match;
for ( t = 0; t < types.length; t++ ) {
type = types[t];
all = type.indexOf(".") < 0;
if (!all ) {
namespaces = type.split(".");
type = namespaces.shift();
namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
}
typeHandlers = (events[type] || []).slice(0);
for ( h = 0; h < typeHandlers.length; h++ ) {
handle = typeHandlers[h];
match = (all || namespace.test(handle.namespace));
if(match){
if(selector){
if (handle.selector === selector ) {
callback(type, handle.origHandler || handle.handler);
}
} else if (selector === null){
callback(type, handle.origHandler || handle.handler, handle.selector);
}
else if (!handle.selector ) {
callback(type, handle.origHandler || handle.handler);
}
}
}
}
};
/**
* Finds event handlers of a given type on an element.
* #param {HTMLElement} el
* #param {Array} types an array of event names
* #param {String} [selector] optional selector
* #return {Array} an array of event handlers
*/
event.find = function( el, types, selector ) {
var events = ( $._data(el) || {} ).events,
handlers = [],
t, liver, live;
if (!events ) {
return handlers;
}
findHelper(events, types, function( type, handler ) {
handlers.push(handler);
}, selector);
return handlers;
};
/**
* Finds all events. Group by selector.
* #param {HTMLElement} el the element
* #param {Array} types event types
*/
event.findBySelector = function( el, types ) {
var events = $._data(el).events,
selectors = {},
//adds a handler for a given selector and event
add = function( selector, event, handler ) {
var select = selectors[selector] || (selectors[selector] = {}),
events = select[event] || (select[event] = []);
events.push(handler);
};
if (!events ) {
return selectors;
}
//first check live:
/*$.each(events.live || [], function( i, live ) {
if ( $.inArray(live.origType, types) !== -1 ) {
add(live.selector, live.origType, live.origHandler || live.handler);
}
});*/
//then check straight binds
findHelper(events, types, function( type, handler, selector ) {
add(selector || "", type, handler);
}, null);
return selectors;
};
event.supportTouch = "ontouchend" in document;
$.fn.respondsTo = function( events ) {
if (!this.length ) {
return false;
} else {
//add default ?
return event.find(this[0], $.isArray(events) ? events : [events]).length > 0;
}
};
$.fn.triggerHandled = function( event, data ) {
event = (typeof event == "string" ? $.Event(event) : event);
this.trigger(event, data);
return event.handled;
};
/**
* Only attaches one event handler for all types ...
* #param {Array} types llist of types that will delegate here
* #param {Object} startingEvent the first event to start listening to
* #param {Object} onFirst a function to call
*/
event.setupHelper = function( types, startingEvent, onFirst ) {
if (!onFirst ) {
onFirst = startingEvent;
startingEvent = null;
}
var add = function( handleObj ) {
var bySelector, selector = handleObj.selector || "";
if ( selector ) {
bySelector = event.find(this, types, selector);
if (!bySelector.length ) {
$(this).delegate(selector, startingEvent, onFirst);
}
}
else {
//var bySelector = event.find(this, types, selector);
if (!event.find(this, types, selector).length ) {
event.add(this, startingEvent, onFirst, {
selector: selector,
delegate: this
});
}
}
},
remove = function( handleObj ) {
var bySelector, selector = handleObj.selector || "";
if ( selector ) {
bySelector = event.find(this, types, selector);
if (!bySelector.length ) {
$(this).undelegate(selector, startingEvent, onFirst);
}
}
else {
if (!event.find(this, types, selector).length ) {
event.remove(this, startingEvent, onFirst, {
selector: selector,
delegate: this
});
}
}
};
$.each(types, function() {
event.special[this] = {
add: add,
remove: remove,
setup: function() {},
teardown: function() {}
};
});
};
})(jQuery);
(function($){
var isPhantom = /Phantom/.test(navigator.userAgent),
supportTouch = !isPhantom && "ontouchend" in document,
scrollEvent = "touchmove scroll",
// Use touch events or map it to mouse events
touchStartEvent = supportTouch ? "touchstart" : "mousedown",
touchStopEvent = supportTouch ? "touchend" : "mouseup",
touchMoveEvent = supportTouch ? "touchmove" : "mousemove",
data = function(event){
var d = event.originalEvent.touches ?
event.originalEvent.touches[ 0 ] :
event;
return {
time: (new Date).getTime(),
coords: [ d.pageX, d.pageY ],
origin: $( event.target )
};
};
/**
* #add jQuery.event.swipe
*/
var swipe = $.event.swipe = {
/**
* #attribute delay
* Delay is the upper limit of time the swipe motion can take in milliseconds. This defaults to 500.
*
* A user must perform the swipe motion in this much time.
*/
delay : 500,
/**
* #attribute max
* The maximum distance the pointer must travel in pixels. The default is 75 pixels.
*/
max : 75,
/**
* #attribute min
* The minimum distance the pointer must travel in pixels. The default is 30 pixels.
*/
min : 30
};
$.event.setupHelper( [
/**
* #hide
* #attribute swipe
*/
"swipe",
/**
* #hide
* #attribute swipeleft
*/
'swipeleft',
/**
* #hide
* #attribute swiperight
*/
'swiperight',
/**
* #hide
* #attribute swipeup
*/
'swipeup',
/**
* #hide
* #attribute swipedown
*/
'swipedown'], touchStartEvent, function(ev){
var
// update with data when the event was started
start = data(ev),
stop,
delegate = ev.delegateTarget || ev.currentTarget,
selector = ev.handleObj.selector,
entered = this;
function moveHandler(event){
if ( !start ) {
return;
}
// update stop with the data from the current event
stop = data(event);
// prevent scrolling
if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
event.preventDefault();
}
};
// Attach to the touch move events
$(document.documentElement).bind(touchMoveEvent, moveHandler)
.one(touchStopEvent, function(event){
$(this).unbind( touchMoveEvent, moveHandler);
// if start and stop contain data figure out if we have a swipe event
if ( start && stop ) {
// calculate the distance between start and stop data
var deltaX = Math.abs(start.coords[0] - stop.coords[0]),
deltaY = Math.abs(start.coords[1] - stop.coords[1]),
distance = Math.sqrt(deltaX*deltaX+deltaY*deltaY);
// check if the delay and distance are matched
if ( stop.time - start.time < swipe.delay && distance >= swipe.min ) {
var events = ['swipe'];
// check if we moved horizontally
if( deltaX >= swipe.min && deltaY < swipe.min) {
// based on the x coordinate check if we moved left or right
events.push( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
} else
// check if we moved vertically
if(deltaY >= swipe.min && deltaX < swipe.min){
// based on the y coordinate check if we moved up or down
events.push( start.coords[1] < stop.coords[1] ? "swipedown" : "swipeup" );
}
// trigger swipe events on this guy
$.each($.event.find(delegate, events, selector), function(){
this.call(entered, ev, {start : start, end: stop})
})
}
}
// reset start and stop
start = stop = undefined;
})
});
})(jQuery)

Here is updated ans
<div class="bb-item" id="item2">
<div class="content">
<div class="scroller">
<h2>Lessons</h2>
<p>Move P, L, C</p>
<p> Pick and place </p>
<p>Approach and depart</p>
</div>
</div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="bb-item" id="item3">
<div class="content">
<div class="scroller">
<h2> Move P, L, C</h2>
</div>
</div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="bb-item" id="item4">
<div class="content">
<div class="scroller">
<h2>Pick and place</h2>
</div>
</div>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="bb-item" id="item5">
<div class="content">
<div class="scroller">
<h2>Approach and depart</h2>
</div>
</div>
</div>

Related

Anchor links stopped working in chrome

I made this website : http://lesgitesduchienvert.be 2 years ago with loads of anchor links to navigate in the pages. The problem is that suddenly the links stopped working in chrome!!
It works perfectly in Safari, Mozilla, IE, ... and on mobile it works with chrome too!
At first I thought it might be because of the smoothScroll but it actually seems they don't work at all... I have looked all over but can't seem to find someone with that exact issue. Tried a few test but no apparent changes.
Has anyone seen that issue somewhere? Any idea to fix it?
Thanks a lot for your help!
I have found the solution to this, it works across all browsers and replicates the smoothscroll effect perfectly.
Open Smoothscroll.js and replace with the following code
/*!
* smooth-scroll v9.1.1: Animate scrolling to anchor links
* (c) 2016 Chris Ferdinandi
* MIT License
* http://github.com/cferdinandi/smooth-scroll
*/
(function (root, factory) {
if ( typeof define === 'function' && define.amd ) {
define([], factory(root));
} else if ( typeof exports === 'object' ) {
module.exports = factory(root);
} else {
root.smoothScroll = factory(root);
}
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
'use strict';
//
// Variables
//
var smoothScroll = {}; // Object for public APIs
var supports = 'querySelector' in document && 'addEventListener' in root; // Feature test
var settings, eventTimeout, fixedHeader, headerHeight, animationInterval;
// Default settings
var defaults = {
selector: '[data-scroll]',
selectorHeader: '[data-scroll-header]',
speed: 500,
easing: 'easeInOutCubic',
offset: 0,
updateURL: true,
callback: function () {}
};
//
// Methods
//
/**
* Merge two or more objects. Returns a new object.
* #private
* #param {Boolean} deep If true, do a deep (or recursive) merge [optional]
* #param {Object} objects The objects to merge together
* #returns {Object} Merged values of defaults and options
*/
var extend = function () {
// Variables
var extended = {};
var deep = false;
var i = 0;
var length = arguments.length;
// Check if a deep merge
if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
deep = arguments[0];
i++;
}
// Merge the object into the extended object
var merge = function (obj) {
for ( var prop in obj ) {
if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
// If deep merge and property is an object, merge properties
if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
extended[prop] = extend( true, extended[prop], obj[prop] );
} else {
extended[prop] = obj[prop];
}
}
}
};
// Loop through each object and conduct a merge
for ( ; i < length; i++ ) {
var obj = arguments[i];
merge(obj);
}
return extended;
};
/**
* Get the height of an element.
* #private
* #param {Node} elem The element to get the height of
* #return {Number} The element's height in pixels
*/
var getHeight = function ( elem ) {
return Math.max( elem.scrollHeight, elem.offsetHeight, elem.clientHeight );
};
/**
* Get the closest matching element up the DOM tree.
* #private
* #param {Element} elem Starting element
* #param {String} selector Selector to match against (class, ID, data attribute, or tag)
* #return {Boolean|Element} Returns null if not match found
*/
var getClosest = function ( elem, selector ) {
// Variables
var firstChar = selector.charAt(0);
var supports = 'classList' in document.documentElement;
var attribute, value;
// If selector is a data attribute, split attribute from value
if ( firstChar === '[' ) {
selector = selector.substr(1, selector.length - 2);
attribute = selector.split( '=' );
if ( attribute.length > 1 ) {
value = true;
attribute[1] = attribute[1].replace( /"/g, '' ).replace( /'/g, '' );
}
}
// Get closest match
for ( ; elem && elem !== document; elem = elem.parentNode ) {
// If selector is a class
if ( firstChar === '.' ) {
if ( supports ) {
if ( elem.classList.contains( selector.substr(1) ) ) {
return elem;
}
} else {
if ( new RegExp('(^|\\s)' + selector.substr(1) + '(\\s|$)').test( elem.className ) ) {
return elem;
}
}
}
// If selector is an ID
if ( firstChar === '#' ) {
if ( elem.id === selector.substr(1) ) {
return elem;
}
}
// If selector is a data attribute
if ( firstChar === '[' ) {
if ( elem.hasAttribute( attribute[0] ) ) {
if ( value ) {
if ( elem.getAttribute( attribute[0] ) === attribute[1] ) {
return elem;
}
} else {
return elem;
}
}
}
// If selector is a tag
if ( elem.tagName.toLowerCase() === selector ) {
return elem;
}
}
return null;
};
/**
* Escape special characters for use with querySelector
* #public
* #param {String} id The anchor ID to escape
* #author Mathias Bynens
* #link https://github.com/mathiasbynens/CSS.escape
*/
smoothScroll.escapeCharacters = function ( id ) {
// Remove leading hash
if ( id.charAt(0) === '#' ) {
id = id.substr(1);
}
var string = String(id);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then throw an
// `InvalidCharacterError` exception and terminate these steps.
if (codeUnit === 0x0000) {
throw new InvalidCharacterError(
'Invalid character: the input contains U+0000.'
);
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index === 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit === 0x002D
)
) {
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit === 0x002D ||
codeUnit === 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// http://dev.w3.org/csswg/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return '#' + result;
};
/**
* Calculate the easing pattern
* #private
* #link https://gist.github.com/gre/1650294
* #param {String} type Easing pattern
* #param {Number} time Time animation should take to complete
* #returns {Number}
*/
var easingPattern = function ( type, time ) {
var pattern;
if ( type === 'easeInQuad' ) pattern = time * time; // accelerating from zero velocity
if ( type === 'easeOutQuad' ) pattern = time * (2 - time); // decelerating to zero velocity
if ( type === 'easeInOutQuad' ) pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
if ( type === 'easeInCubic' ) pattern = time * time * time; // accelerating from zero velocity
if ( type === 'easeOutCubic' ) pattern = (--time) * time * time + 1; // decelerating to zero velocity
if ( type === 'easeInOutCubic' ) pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
if ( type === 'easeInQuart' ) pattern = time * time * time * time; // accelerating from zero velocity
if ( type === 'easeOutQuart' ) pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
if ( type === 'easeInOutQuart' ) pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
if ( type === 'easeInQuint' ) pattern = time * time * time * time * time; // accelerating from zero velocity
if ( type === 'easeOutQuint' ) pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
if ( type === 'easeInOutQuint' ) pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
return pattern || time; // no easing, no acceleration
};
/**
* Calculate how far to scroll
* #private
* #param {Element} anchor The anchor element to scroll to
* #param {Number} headerHeight Height of a fixed header, if any
* #param {Number} offset Number of pixels by which to offset scroll
* #returns {Number}
*/
var getEndLocation = function ( anchor, headerHeight, offset ) {
var location = 0;
if (anchor.offsetParent) {
do {
location += anchor.offsetTop;
anchor = anchor.offsetParent;
} while (anchor);
}
location = location - headerHeight - offset;
return location >= 0 ? location : 0;
};
/**
* Determine the document's height
* #private
* #returns {Number}
*/
var getDocumentHeight = function () {
return Math.max(
root.document.body.scrollHeight, root.document.documentElement.scrollHeight,
root.document.body.offsetHeight, root.document.documentElement.offsetHeight,
root.document.body.clientHeight, root.document.documentElement.clientHeight
);
};
/**
* Convert data-options attribute into an object of key/value pairs
* #private
* #param {String} options Link-specific options as a data attribute string
* #returns {Object}
*/
var getDataOptions = function ( options ) {
return !options || !(typeof JSON === 'object' && typeof JSON.parse === 'function') ? {} : JSON.parse( options );
};
/**
* Update the URL
* #private
* #param {Element} anchor The element to scroll to
* #param {Boolean} url Whether or not to update the URL history
*/
var updateUrl = function ( anchor, url ) {
if ( root.history.pushState && (url || url === 'true') && root.location.protocol !== 'file:' ) {
root.history.pushState( null, null, [root.location.protocol, '//', root.location.host, root.location.pathname, root.location.search, anchor].join('') );
}
};
var getHeaderHeight = function ( header ) {
return header === null ? 0 : ( getHeight( header ) + header.offsetTop );
};
/**
* Start/stop the scrolling animation
* #public
* #param {Element} anchor The element to scroll to
* #param {Element} toggle The element that toggled the scroll event
* #param {Object} options
*/
smoothScroll.animateScroll = function ( anchor, toggle, options ) {
// Options and overrides
var overrides = getDataOptions( toggle ? toggle.getAttribute('data-options') : null );
var animateSettings = extend( settings || defaults, options || {}, overrides ); // Merge user options with defaults
// Selectors and variables
var isNum = Object.prototype.toString.call( anchor ) === '[object Number]' ? true : false;
var anchorElem = isNum ? null : ( anchor === '#' ? root.document.documentElement : root.document.querySelector(anchor) );
if ( !isNum && !anchorElem ) return;
var startLocation = root.pageYOffset; // Current location on the page
if ( !fixedHeader ) { fixedHeader = root.document.querySelector( animateSettings.selectorHeader ); } // Get the fixed header if not already set
if ( !headerHeight ) { headerHeight = getHeaderHeight( fixedHeader ); } // Get the height of a fixed header if one exists and not already set
var endLocation = isNum ? anchor : getEndLocation( anchorElem, headerHeight, parseInt(animateSettings.offset, 10) ); // Location to scroll to
var distance = endLocation - startLocation; // distance to travel
var documentHeight = getDocumentHeight();
var timeLapsed = 0;
var percentage, position;
// Update URL
if ( !isNum ) {
updateUrl(anchor, animateSettings.updateURL);
}
/**
* Stop the scroll animation when it reaches its target (or the bottom/top of page)
* #private
* #param {Number} position Current position on the page
* #param {Number} endLocation Scroll to location
* #param {Number} animationInterval How much to scroll on this loop
*/
var stopAnimateScroll = function (position, endLocation, animationInterval) {
var currentLocation = root.pageYOffset;
if ( position == endLocation || currentLocation == endLocation || ( (root.innerHeight + currentLocation) >= documentHeight ) ) {
clearInterval(animationInterval);
if ( !isNum ) {
anchorElem.focus();
}
animateSettings.callback( anchor, toggle ); // Run callbacks after animation complete
}
};
/**
* Loop scrolling animation
* #private
*/
var loopAnimateScroll = function () {
timeLapsed += 16;
percentage = ( timeLapsed / parseInt(animateSettings.speed, 10) );
percentage = ( percentage > 1 ) ? 1 : percentage;
position = startLocation + ( distance * easingPattern(animateSettings.easing, percentage) );
root.scrollTo( 0, Math.floor(position) );
stopAnimateScroll(position, endLocation, animationInterval);
};
/**
* Set interval timer
* #private
*/
var startAnimateScroll = function () {
clearInterval(animationInterval);
animationInterval = setInterval(loopAnimateScroll, 16);
};
/**
* Reset position to fix weird iOS bug
* #link https://github.com/cferdinandi/smooth-scroll/issues/45
*/
if ( root.pageYOffset === 0 ) {
root.scrollTo( 0, 0 );
}
// Start scrolling animation
startAnimateScroll();
};
/**
* If smooth scroll element clicked, animate scroll
* #private
*/
var eventHandler = function (event) {
// Don't run if right-click or command/control + click
if ( event.button !== 0 || event.metaKey || event.ctrlKey ) return;
// If a smooth scroll link, animate it
var toggle = getClosest( event.target, settings.selector );
if ( toggle && toggle.tagName.toLowerCase() === 'a' ) {
event.preventDefault(); // Prevent default click event
var hash = smoothScroll.escapeCharacters( toggle.hash ); // Escape hash characters
smoothScroll.animateScroll( hash, toggle, settings); // Animate scroll
}
};
/**
* On window scroll and resize, only run events at a rate of 15fps for better performance
* #private
* #param {Function} eventTimeout Timeout function
* #param {Object} settings
*/
var eventThrottler = function (event) {
if ( !eventTimeout ) {
eventTimeout = setTimeout(function() {
eventTimeout = null; // Reset timeout
headerHeight = getHeaderHeight( fixedHeader ); // Get the height of a fixed header if one exists
}, 66);
}
};
/**
* Destroy the current initialization.
* #public
*/
smoothScroll.destroy = function () {
// If plugin isn't already initialized, stop
if ( !settings ) return;
// Remove event listeners
root.document.removeEventListener( 'click', eventHandler, false );
root.removeEventListener( 'resize', eventThrottler, false );
// Reset varaibles
settings = null;
eventTimeout = null;
fixedHeader = null;
headerHeight = null;
animationInterval = null;
};
/**
* Initialize Smooth Scroll
* #public
* #param {Object} options User settings
*/
smoothScroll.init = function ( options ) {
// feature test
if ( !supports ) return;
// Destroy any existing initializations
smoothScroll.destroy();
// Selectors and variables
settings = extend( defaults, options || {} ); // Merge user options with defaults
fixedHeader = root.document.querySelector( settings.selectorHeader ); // Get the fixed header
headerHeight = getHeaderHeight( fixedHeader );
// When a toggle is clicked, run the click handler
root.document.addEventListener('click', eventHandler, false );
if ( fixedHeader ) { root.addEventListener( 'resize', eventThrottler, false ); }
};
//
// Public APIs
//
return smoothScroll;
});
Make sure the link to smoothscroll.js is called below the jquery.js, and then, beneath those, paste the following:
<script>
smoothScroll.init();
</script>
Replace any links that use the class
<a class="smoothscroll" href ="">
is replaced with date-scroll instead. Anything that uses the smoothscroll class won't work in chrome.
Try it out! It worked for all my sites affected by this issue!
I found the same issue with sites I have built running Chrome's latest version (62.0.3202.84). I took a look at your site and see that you are using SmoothScroll, that's your issue there. They are supposed to be releasing a patched version of SmoothScroll that will fix this, and I hope they do soon! I use it on just about all the sites I build! See more here and watch for updates
https://github.com/simov/simplr-smoothscroll/issues/27
And here for the latest version of SmoothScroll
https://github.com/kswedberg/jquery-smooth-scroll
Just change the class on your link to class="external"

Fixed main content and slide menu as overlap on Multi Level Push Menu

I am using this menu for my responsive website.
https://tympanus.net/codrops/2013/08/13/multi-level-push-menu/
This works great, except that I am unable to change the behavior where it pushes the main content to the right. I want to make the main content fixed and instead the menu should overlap the main content.
I had tried many things, but not sure how to achieve this. Any help is appreciated.
You must change the component.css and mlpushmenu.js files:
In component.css:
Search this:
.mp-menu {
position: absolute; /* we can't use fixed here :( */
top: 0;
left: 0;
z-index: 1;
width: 300px;
height: 100%;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
and change by this:
.mp-menu {
position: absolute; /* we can't use fixed here :( */
top: 0;
left: 0;
z-index: 1;
width: 300px;
height: 100%;
-webkit-transform: translate3d(-100%, 0, 0);
-moz-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
transition: all .5s;
}
Now change mlpushmenu.js by this:
/**
* mlpushmenu.js v1.0.0
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2013, Codrops
* http://www.codrops.com
*/
;( function( window ) {
'use strict';
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
// taken from https://github.com/inuyaksa/jquery.nicescroll/blob/master/jquery.nicescroll.js
function hasParent( e, id ) {
if (!e) return false;
var el = e.target||e.srcElement||e||false;
while (el && el.id != id) {
el = el.parentNode||false;
}
return (el!==false);
}
// returns the depth of the element "e" relative to element with id=id
// for this calculation only parents with classname = waypoint are considered
function getLevelDepth( e, id, waypoint, cnt ) {
cnt = cnt || 0;
if ( e.id.indexOf( id ) >= 0 ) return cnt;
if( classie.has( e, waypoint ) ) {
++cnt;
}
return e.parentNode && getLevelDepth( e.parentNode, id, waypoint, cnt );
}
// http://coveroverflow.com/a/11381730/989439
function mobilecheck() {
var check = false;
(function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
return check;
}
// returns the closest element to 'e' that has class "classname"
function closest( e, classname ) {
if( classie.has( e, classname ) ) {
return e;
}
return e.parentNode && closest( e.parentNode, classname );
}
function mlPushMenu( el, trigger, options ) {
this.el = el;
this.trigger = trigger;
this.options = extend( this.defaults, options );
// support 3d transforms
this.support = Modernizr.csstransforms3d;
if( this.support ) {
this._init();
}
}
mlPushMenu.prototype = {
defaults : {
// overlap: there will be a gap between open levels
// cover: the open levels will be on top of any previous open level
type : 'overlap', // overlap || cover
// space between each overlaped level
levelSpacing : 12, // Percent of sublevels
// classname for the element (if any) that when clicked closes the current level
backClass : 'mp-back'
},
_init : function() {
// if menu is open or not
this.open = false;
// level depth
this.level = 0;
// the moving wrapper
this.wrapper = this.el;
this.theconts = document.getElementById( 'mp-pusher' );
// the mp-level elements
this.levels = Array.prototype.slice.call( this.el.querySelectorAll( 'div.mp-level' ) );
// save the depth of each of these mp-level elements
var self = this;
this.levels.forEach( function( el, i ) { el.setAttribute( 'data-level', getLevelDepth( el, self.el.id, 'mp-level' ) ); } );
// the menu items
this.menuItems = Array.prototype.slice.call( this.el.querySelectorAll( 'li' ) );
// if type == "cover" these will serve as hooks to move back to the previous level
this.levelBack = Array.prototype.slice.call( this.el.querySelectorAll( '.' + this.options.backClass ) );
// event type (if mobile use touch events)
this.eventtype = mobilecheck() ? 'touchstart' : 'click';
// add the class mp-overlap or mp-cover to the main element depending on options.type
classie.add( this.el, 'mp-' + this.options.type );
// initialize / bind the necessary events
this._initEvents();
},
_initEvents : function() {
var self = this;
// the menu should close if clicking somewhere on the body
var bodyClickFn = function( el ) {
self._resetMenu();
el.removeEventListener( self.eventtype, bodyClickFn );
};
// open (or close) the menu
this.trigger.addEventListener( this.eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
if( self.open ) {
self._resetMenu();
}
else {
self._openMenu();
// the menu should close if clicking somewhere on the body (excluding clicks on the menu)
document.addEventListener( self.eventtype, function( ev ) {
if( self.open && !hasParent( ev.target, self.el.id ) ) {
bodyClickFn( this );
}
} );
}
} );
// opening a sub level menu
this.menuItems.forEach( function( el, i ) {
// check if it has a sub level
var subLevel = el.querySelector( 'div.mp-level' );
if( subLevel ) {
el.querySelector( 'a' ).addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
classie.add( closest( el, 'mp-level' ), 'mp-level-overlay' );
self._openMenu( subLevel );
}
} );
}
} );
// closing the sub levels :
// by clicking on the visible part of the level element
this.levels.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.stopPropagation();
var level = el.getAttribute( 'data-level' );
if( self.level > level ) {
self.level = level;
self._closeMenu();
}
} );
} );
// by clicking on a specific element
this.levelBack.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
self.level = closest( el, 'mp-level' ).getAttribute( 'data-level' ) - 1;
self.level === 0 ? self._resetMenu() : self._closeMenu();
}
} );
} );
},
_openMenu : function( subLevel ) {
// increment level depth
++this.level;
// move the main wrapper
var levelFactor = ( this.level - 1 ) * this.options.levelSpacing,
translateVal = this.options.type === 'overlap' ? levelFactor : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + '%,0,0)' );
if( subLevel ) {
// reset transform for sublevel
this._setTransform( '', subLevel );
// need to reset the translate value for the level menus that have the same level depth and are not open
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl != subLevel && !classie.has( levelEl, 'mp-level-open' ) ) {
this._setTransform( 'translate3d(-100%,0,0) translate3d(' + -1*levelFactor + '%,0,0)', levelEl );
}
}
}
// add class mp-pushed to main wrapper if opening the first time
if( this.level === 1 ) {
classie.add( this.theconts, 'mp-pushed' );
this.open = true;
}
// add class mp-level-open to the opening level element
classie.add( subLevel || this.levels[0], 'mp-level-open' );
},
// close the menu
_resetMenu : function() {
this._setTransform('translate3d(-100%,0,0)');
this.level = 0;
// remove class mp-pushed from main wrapper
classie.remove( this.theconts, 'mp-pushed' );
this._toggleLevels();
this.open = false;
},
// close sub menus
_closeMenu : function() {
var translateVal = this.options.type === 'overlap' ? ( this.level - 1 ) * this.options.levelSpacing : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + '%,0,0)' );
this._toggleLevels();
},
// translate the el
_setTransform : function( val, el ) {
el = el || this.wrapper;
el.style.WebkitTransform = val;
el.style.MozTransform = val;
el.style.transform = val;
},
// removes classes mp-level-open from closing levels
_toggleLevels : function() {
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl.getAttribute( 'data-level' ) >= this.level + 1 ) {
classie.remove( levelEl, 'mp-level-open' );
classie.remove( levelEl, 'mp-level-overlay' );
}
else if( Number( levelEl.getAttribute( 'data-level' ) ) == this.level ) {
classie.remove( levelEl, 'mp-level-overlay' );
}
}
}
}
// add to global namespace
window.mlPushMenu = mlPushMenu;
} )( window );
Example: https://jsfiddle.net/ihojose/6kyhdLbx/

Get All Links in a Document

Given a "normal document" in Google Docs/Drive (e.g. paragraphs, lists, tables) which contains external links scattered throughout the content, how do you compile a list of links present using Google Apps Script?
Specifically, I want to update all broken links in the document by searching for oldText in each url and replace it with newText in each url, but not the text.
I don't think the replacing text section of the Dev Documentation is what I need -- do I need to scan every element of the doc? Can I just editAsText and use an html regex? Examples would be appreciated.
This is only mostly painful! Code is available as part of a gist.
Yeah, I can't spell.
getAllLinks
Here's a utility function that scans the document for all LinkUrls, returning them in an array.
/**
* Get an array of all LinkUrls in the document. The function is
* recursive, and if no element is provided, it will default to
* the active document's Body element.
*
* #param {Element} element The document element to operate on.
* .
* #returns {Array} Array of objects, vis
* {element,
* startOffset,
* endOffsetInclusive,
* url}
*/
function getAllLinks(element) {
var links = [];
element = element || DocumentApp.getActiveDocument().getBody();
if (element.getType() === DocumentApp.ElementType.TEXT) {
var textObj = element.editAsText();
var text = element.getText();
var inUrl = false;
for (var ch=0; ch < text.length; ch++) {
var url = textObj.getLinkUrl(ch);
if (url != null) {
if (!inUrl) {
// We are now!
inUrl = true;
var curUrl = {};
curUrl.element = element;
curUrl.url = String( url ); // grab a copy
curUrl.startOffset = ch;
}
else {
curUrl.endOffsetInclusive = ch;
}
}
else {
if (inUrl) {
// Not any more, we're not.
inUrl = false;
links.push(curUrl); // add to links
curUrl = {};
}
}
}
if (inUrl) {
// in case the link ends on the same char that the element does
links.push(curUrl);
}
}
else {
var numChildren = element.getNumChildren();
for (var i=0; i<numChildren; i++) {
links = links.concat(getAllLinks(element.getChild(i)));
}
}
return links;
}
findAndReplaceLinks
This utility builds on getAllLinks to do a find & replace function.
/**
* Replace all or part of UrlLinks in the document.
*
* #param {String} searchPattern the regex pattern to search for
* #param {String} replacement the text to use as replacement
*
* #returns {Number} number of Urls changed
*/
function findAndReplaceLinks(searchPattern,replacement) {
var links = getAllLinks();
var numChanged = 0;
for (var l=0; l<links.length; l++) {
var link = links[l];
if (link.url.match(searchPattern)) {
// This link needs to be changed
var newUrl = link.url.replace(searchPattern,replacement);
link.element.setLinkUrl(link.startOffset, link.endOffsetInclusive, newUrl);
numChanged++
}
}
return numChanged;
}
Demo UI
To demonstrate the use of these utilities, here are a couple of UI extensions:
function onOpen() {
// Add a menu with some items, some separators, and a sub-menu.
DocumentApp.getUi().createMenu('Utils')
.addItem('List Links', 'sidebarLinks')
.addItem('Replace Link Text', 'searchReplaceLinks')
.addToUi();
}
function searchReplaceLinks() {
var ui = DocumentApp.getUi();
var app = UiApp.createApplication()
.setWidth(250)
.setHeight(100)
.setTitle('Change Url text');
var form = app.createFormPanel();
var flow = app.createFlowPanel();
flow.add(app.createLabel("Find: "));
flow.add(app.createTextBox().setName("searchPattern"));
flow.add(app.createLabel("Replace: "));
flow.add(app.createTextBox().setName("replacement"));
var handler = app.createServerHandler('myClickHandler');
flow.add(app.createSubmitButton("Submit").addClickHandler(handler));
form.add(flow);
app.add(form);
ui.showDialog(app);
}
// ClickHandler to close dialog
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
app.close();
return app;
}
function doPost(e) {
var numChanged = findAndReplaceLinks(e.parameter.searchPattern,e.parameter.replacement);
var ui = DocumentApp.getUi();
var app = UiApp.createApplication();
sidebarLinks(); // Update list
var result = DocumentApp.getUi().alert(
'Results',
"Changed "+numChanged+" urls.",
DocumentApp.getUi().ButtonSet.OK);
}
/**
* Shows a custom HTML user interface in a sidebar in the Google Docs editor.
*/
function sidebarLinks() {
var links = getAllLinks();
var sidebar = HtmlService
.createHtmlOutput()
.setTitle('URL Links')
.setWidth(350 /* pixels */);
// Display list of links, url only.
for (var l=0; l<links.length; l++) {
var link = links[l];
sidebar.append('<p>'+link.url);
}
DocumentApp.getUi().showSidebar(sidebar);
}
I offer another, shorter answer for your first question, concerning iterating through all links in a document's body. This instructive code returns a flat array of links in the current document's body, where each link is represented by an object with entries pointing to the text element (text), the paragraph element or list item element in which it's contained (paragraph), the offset index in the text where the link appears (startOffset) and the URL itself (url). Hopefully, you'll find it easy to suit it for your own needs.
It uses the getTextAttributeIndices() method rather than iterating over every character of the text, and is thus expected to perform much more quickly than previously written answers.
EDIT: Since originally posting this answer, I modified the function a couple of times. It now also (1) includes the endOffsetInclusive property for each link (note that it can be null for links that extend to the end of the text element - in this case one can use link.text.length-1 instead); (2) finds links in all sections of the document, not only the body, and (3) includes the section and isFirstPageSection properties to indicate where the link is located; (4) accepts the argument mergeAdjacent, which when set to true, will return only a single link entry for a continuous stretch of text linked to the same URL (which would be considered separate if, for instance, part of the text is styled differently than another part).
For the purpose of including links under all sections, a new utility function, iterateSections(), was introduced.
/**
* Returns a flat array of links which appear in the active document's body.
* Each link is represented by a simple Javascript object with the following
* keys:
* - "section": {ContainerElement} the document section in which the link is
* found.
* - "isFirstPageSection": {Boolean} whether the given section is a first-page
* header/footer section.
* - "paragraph": {ContainerElement} contains a reference to the Paragraph
* or ListItem element in which the link is found.
* - "text": the Text element in which the link is found.
* - "startOffset": {Number} the position (offset) in the link text begins.
* - "endOffsetInclusive": the position of the last character of the link
* text, or null if the link extends to the end of the text element.
* - "url": the URL of the link.
*
* #param {boolean} mergeAdjacent Whether consecutive links which carry
* different attributes (for any reason) should be returned as a single
* entry.
*
* #returns {Array} the aforementioned flat array of links.
*/
function getAllLinks(mergeAdjacent) {
var links = [];
var doc = DocumentApp.getActiveDocument();
iterateSections(doc, function(section, sectionIndex, isFirstPageSection) {
if (!("getParagraphs" in section)) {
// as we're using some undocumented API, adding this to avoid cryptic
// messages upon possible API changes.
throw new Error("An API change has caused this script to stop " +
"working.\n" +
"Section #" + sectionIndex + " of type " +
section.getType() + " has no .getParagraphs() method. " +
"Stopping script.");
}
section.getParagraphs().forEach(function(par) {
// skip empty paragraphs
if (par.getNumChildren() == 0) {
return;
}
// go over all text elements in paragraph / list-item
for (var el=par.getChild(0); el!=null; el=el.getNextSibling()) {
if (el.getType() != DocumentApp.ElementType.TEXT) {
continue;
}
// go over all styling segments in text element
var attributeIndices = el.getTextAttributeIndices();
var lastLink = null;
attributeIndices.forEach(function(startOffset, i, attributeIndices) {
var url = el.getLinkUrl(startOffset);
if (url != null) {
// we hit a link
var endOffsetInclusive = (i+1 < attributeIndices.length?
attributeIndices[i+1]-1 : null);
// check if this and the last found link are continuous
if (mergeAdjacent && lastLink != null && lastLink.url == url &&
lastLink.endOffsetInclusive == startOffset - 1) {
// this and the previous style segment are continuous
lastLink.endOffsetInclusive = endOffsetInclusive;
return;
}
lastLink = {
"section": section,
"isFirstPageSection": isFirstPageSection,
"paragraph": par,
"textEl": el,
"startOffset": startOffset,
"endOffsetInclusive": endOffsetInclusive,
"url": url
};
links.push(lastLink);
}
});
}
});
});
return links;
}
/**
* Calls the given function for each section of the document (body, header,
* etc.). Sections are children of the DocumentElement object.
*
* #param {Document} doc The Document object (such as the one obtained via
* a call to DocumentApp.getActiveDocument()) with the sections to iterate
* over.
* #param {Function} func A callback function which will be called, for each
* section, with the following arguments (in order):
* - {ContainerElement} section - the section element
* - {Number} sectionIndex - the child index of the section, such that
* doc.getBody().getParent().getChild(sectionIndex) == section.
* - {Boolean} isFirstPageSection - whether the section is a first-page
* header/footer section.
*/
function iterateSections(doc, func) {
// get the DocumentElement interface to iterate over all sections
// this bit is undocumented API
var docEl = doc.getBody().getParent();
var regularHeaderSectionIndex = (doc.getHeader() == null? -1 :
docEl.getChildIndex(doc.getHeader()));
var regularFooterSectionIndex = (doc.getFooter() == null? -1 :
docEl.getChildIndex(doc.getFooter()));
for (var i=0; i<docEl.getNumChildren(); ++i) {
var section = docEl.getChild(i);
var sectionType = section.getType();
var uniqueSectionName;
var isFirstPageSection = (
i != regularHeaderSectionIndex &&
i != regularFooterSectionIndex &&
(sectionType == DocumentApp.ElementType.HEADER_SECTION ||
sectionType == DocumentApp.ElementType.FOOTER_SECTION));
func(section, i, isFirstPageSection);
}
}
I was playing around and incorporated #Mogsdad's answer -- here's the really complicated version:
var _ = Underscorejs.load(); // loaded via http://googleappsdeveloper.blogspot.com/2012/11/using-open-source-libraries-in-apps.html, rolled my own
var ui = DocumentApp.getUi();
// #region --------------------- Utilities -----------------------------
var gDocsHelper = (function(P, un) {
// heavily based on answer https://stackoverflow.com/a/18731628/1037948
var updatedLinkText = function(link, offset) {
return function() { return 'Text: ' + link.getText().substring(offset,100) + ((link.getText().length-offset) > 100 ? '...' : ''); }
}
P.updateLink = function updateLink(link, oldText, newText, start, end) {
var oldLink = link.getLinkUrl(start);
if(0 > oldLink.indexOf(oldText)) return false;
var newLink = oldLink.replace(new RegExp(oldText, 'g'), newText);
link.setLinkUrl(start || 0, (end || oldLink.length), newLink);
log(true, "Updating Link: ", oldLink, newLink, start, end, updatedLinkText(link, start) );
return { old: oldLink, "new": newLink, getText: updatedLinkText(link, start) };
};
// moving this reused block out to 'private' fn
var updateLinkResult = function(text, oldText, newText, link, urls, sidebar, updateResult) {
// and may as well update the link while we're here
if(false !== (updateResult = P.updateLink(text, oldText, newText, link.start, link.end))) {
sidebar.append('<li>' + updateResult['old'] + ' → ' + updateResult['new'] + ' at ' + updateResult['getText']() + '</li>');
}
urls.push(link.url); // so multiple links get added to list
};
P.updateLinksMenu = function() {
// https://developers.google.com/apps-script/reference/base/prompt-response
var oldText = ui.prompt('Old link text to replace').getResponseText();
var newText = ui.prompt('New link text to replace with').getResponseText();
log('Replacing: ' + oldText + ', ' + newText);
var sidebar = gDocUiHelper.createSidebar('Update All Links', '<h3>Replacing</h3><p><code>' + oldText + '</code> → <code>' + newText + '</code></p><hr /><ol>');
// current doc available to script
var doc = DocumentApp.getActiveDocument().getBody();//.getActiveSection();
// Search until a link is found
var links = P.findAllElementsFor(doc, function(text) {
var i = -1, n = text.getText().length, link = false, url, urls = [], updateResult;
// note: the following only gets the FIRST link in the text -- while(i < n && !(url = text.getLinkUrl(i++)));
// scan the text element for links
while(++i < n) {
// getLinkUrl will continue to get a link while INSIDE the stupid link, so only do this once
if(url = text.getLinkUrl(i)) {
if(false === link) {
link = { start: i, end: -1, url: url };
// log(true, 'Type: ' + text.getType(), 'Link: ' + url, function() { return 'Text: ' + text.getText().substring(i,100) + ((n-i) > 100 ? '...' : '')});
}
else {
link.end = i; // keep updating the end position until we leave
}
}
// just left the link -- reset link tracking
else if(false !== link) {
// and may as well update the link while we're here
updateLinkResult(text, oldText, newText, link, urls, sidebar);
link = false; // reset "counter"
}
}
// once we've reached the end of the text, must also check to see if the last thing we found was a link
if(false !== link) updateLinkResult(text, oldText, newText, link, urls, sidebar);
return urls;
});
sidebar.append('</ol><p><strong>' + links.length + ' links reviewed</strong></p>');
gDocUiHelper.attachSidebar(sidebar);
log(links);
};
P.findAllElementsFor = function(el, test) {
// generic utility function to recursively find all elements; heavily based on https://stackoverflow.com/a/18731628/1037948
var results = [], searchResult = null, i, result;
// https://developers.google.com/apps-script/reference/document/body#findElement(ElementType)
while (searchResult = el.findElement(DocumentApp.ElementType.TEXT, searchResult)) {
var t = searchResult.getElement().editAsText(); // .asParagraph()
// check to add to list
if(test && (result = test(t))) {
if( _.isArray(result) ) results = results.concat(result); // could be big? http://jsperf.com/self-concatenation/
else results.push(result);
}
}
// recurse children if not plain text item
if(el.getType() !== DocumentApp.ElementType.TEXT) {
i = el.getNumChildren();
var result;
while(--i > 0) {
result = P.findAllElementsFor(el.getChild(i));
if(result && result.length > 0) results = results.concat(result);
}
}
return results;
};
return P;
})({});
// really? it can't handle object properties?
function gDocsUpdateLinksMenu() {
gDocsHelper.updateLinksMenu();
}
gDocUiHelper.addMenu('Zaus', [ ['Update links', 'gDocsUpdateLinksMenu'] ]);
// #endregion --------------------- Utilities -----------------------------
And I'm including the "extra" utility classes for creating menus, sidebars, etc below for completeness:
var log = function() {
// return false;
var args = Array.prototype.slice.call(arguments);
// allowing functions delegates execution so we can save some non-debug cycles if code left in?
if(args[0] === true) Logger.log(_.map(args, function(v) { return _.isFunction(v) ? v() : v; }).join('; '));
else
_.each(args, function(v) {
Logger.log(_.isFunction(v) ? v() : v);
});
}
// #region --------------------- Menu -----------------------------
var gDocUiHelper = (function(P, un) {
P.addMenuToSheet = function addMenu(spreadsheet, title, items) {
var menu = ui.createMenu(title);
// make sure menu items are correct format
_.each(items, function(v,k) {
var err = [];
// provided in format [ [name, fn],... ] instead
if( _.isArray(v) ) {
if ( v.length === 2 ) {
menu.addItem(v[0], v[1]);
}
else {
err.push('Menu item ' + k + ' missing name or function: ' + v.join(';'))
}
}
else {
if( !v.name ) err.push('Menu item ' + k + ' lacks name');
if( !v.functionName ) err.push('Menu item ' + k + ' lacks function');
if(!err.length) menu.addItem(v.name, v.functionName);
}
if(err.length) {
log(err);
ui.alert(err.join('; '));
}
});
menu.addToUi();
};
// list of things to hook into
var initializers = {};
P.addMenu = function(menuTitle, menuItems) {
if(initializers[menuTitle] === un) {
initializers[menuTitle] = [];
}
initializers[menuTitle] = initializers[menuTitle].concat(menuItems);
};
P.createSidebar = function(title, content, options) {
var sidebar = HtmlService
.createHtmlOutput()
.setTitle(title)
.setWidth( (options && options.width) ? width : 350 /* pixels */);
sidebar.append(content);
if(options && options.on) DocumentApp.getUi().showSidebar(sidebar);
// else { sidebar.attach = function() { DocumentApp.getUi().showSidebar(this); }; } // should really attach to prototype...
return sidebar;
};
P.attachSidebar = function(sidebar) {
DocumentApp.getUi().showSidebar(sidebar);
};
P.onOpen = function() {
var spreadsheet = SpreadsheetApp.getActive();
log(initializers);
_.each(initializers, function(v,k) {
P.addMenuToSheet(spreadsheet, k, v);
});
};
return P;
})({});
// #endregion --------------------- Menu -----------------------------
/**
* A special function that runs when the spreadsheet is open, used to add a
* custom menu to the spreadsheet.
*/
function onOpen() {
gDocUiHelper.onOpen();
}
Had some trouble getting Mogsdad's solution to work. Specifically it misses links which end their parent element so there isn't a trailing non-link character to terminate it. I've implemented something which addresses this and returns a standard range element. Sharing here incase someone finds it useful.
function getAllLinks(element) {
var rangeBuilder = DocumentApp.getActiveDocument().newRange();
// Parse the text iteratively to find the start and end indices for each link
if (element.getType() === DocumentApp.ElementType.TEXT) {
var links = [];
var string = element.getText();
var previousUrl = null; // The URL of the previous character
var currentLink = null; // The latest link being built
for (var charIndex = 0; charIndex < string.length; charIndex++) {
var currentUrl = element.getLinkUrl(charIndex);
// New URL means create a new link
if (currentUrl !== null && previousUrl !== currentUrl) {
if (currentLink !== null) links.push(currentLink);
currentLink = {};
currentLink.url = String(currentUrl);
currentLink.startOffset = charIndex;
}
// In a URL means extend the end of the current link
if (currentUrl !== null) {
currentLink.endOffsetInclusive = charIndex;
}
// Not in a URL means close and push the link if ready
if (currentUrl === null) {
if (currentLink !== null) links.push(currentLink);
currentLink = null;
}
// End the loop and go again
previousUrl = currentUrl;
}
// Handle the end case when final character is a link
if (currentLink !== null) links.push(currentLink);
// Convert the links into a range before returning
links.forEach(function(link) {
rangeBuilder.addElement(element, link.startOffset, link.endOffsetInclusive);
});
}
// If not a text element then recursively get links from child elements
else if (element.getNumChildren) {
for (var i = 0; i < element.getNumChildren(); i++) {
rangeBuilder.addRange(getAllLinks(element.getChild(i)));
}
}
return rangeBuilder.build();
}
You are right ... search and replace is not applicable here.
Use setLinkUrl() https://developers.google.com/apps-script/reference/document/container-element#setLinkUrl(String)
Basically you have to iterate through the elements recursively (elements can contain elements) and for each
use getLinkUrl() to get the oldText
if not null , setLinkUrl(newText) .... leaves displayed text unchanged
This Excel macro lists the links from a Word doc. You'd need to copy your data into a Word doc first.
Sub getLinks()
Dim wApp As Word.Application, wDoc As Word.Document
Dim i As Integer, r As Range
Const filePath = "C:\test\test.docx"
Set wApp = CreateObject("Word.Application")
'wApp.Visible = True
Set wDoc = wApp.Documents.Open(filePath)
Set r = Range("A1")
For i = 1 To wDoc.Hyperlinks.Count
r = wDoc.Hyperlinks(i).Address
Set r = r.Offset(1, 0)
Next i
wApp.Quit
Set wDoc = Nothing
Set wApp = Nothing
End Sub
Here's a quick and dirty way to accomplish the same goal with no scripting:
From Google Docs, save the document in RTF format.
In your editor of choice, edit the links in the RTF file (in my case, I wanted to modify all the hyperlinks, so I used Emacs and regexp-replace). Save the file when you're done.
Create a fresh, new Google Doc, and from the menu, select File>Open and open the RTF file. Docs will convert your edited RTF file back into a proper Google Doc, restoring all formatting.
Google Docs' RTF format is pretty complete--I haven't noticed any loss of fidelity in making the round trip, and it has the advantage of fully exposing all the hyperlinks, formatting, and everything else about the document in a form that's easy to edit and to apply regex tools to.

special attributes in tag that are processed by javascript file

Impress.js supports a number of attributes:
data-x, data-y, data-z will move the slide on the screen in 3D space;
data-rotate, data-rotate-x, data-rotate-y rotate the element around the specified axis (in degrees);
data-scale – enlarges or shrinks the slide.
div id="intro" class="step" data-x="0" data-y="0">
<h2>Introducing Galaxy Nexus</h2>
<p>Android 4.0<br /> Super Amoled 720p Screen<br />
<img src="assets/img/nexus_1.jpg" width="232" height="458" alt="Galaxy Nexus" />
<!-- We are offsetting the second slide, rotating it and making it 1.8 times larger -->
<div id="simplicity" class="step" data-x="1100" data-y="1200" data-scale="1.8" data-rotate="190">
<h2>Simplicity in Android 4.0</h2>
<p>Android 4.0, Ice Cream Sandwich brings an entirely new look and feel..</p>
<img src="assets/img/nexus_2.jpg" width="289" height="535" alt="Galaxy Nexus" />
Impress.js
(function ( document, window ) {
'use strict';
// HELPER FUNCTIONS
var pfx = (function () {
var style = document.createElement('dummy').style,
prefixes = 'Webkit Moz O ms Khtml'.split(' '),
memory = {};
return function ( prop ) {
if ( typeof memory[ prop ] === "undefined" ) {
var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
memory[ prop ] = null;
for ( var i in props ) {
if ( style[ props[i] ] !== undefined ) {
memory[ prop ] = props[i];
break;
}
}
}
return memory[ prop ];
}
})();
var arrayify = function ( a ) {
return [].slice.call( a );
};
var css = function ( el, props ) {
var key, pkey;
for ( key in props ) {
if ( props.hasOwnProperty(key) ) {
pkey = pfx(key);
if ( pkey != null ) {
el.style[pkey] = props[key];
}
}
}
return el;
}
var byId = function ( id ) {
return document.getElementById(id);
}
var $ = function ( selector, context ) {
context = context || document;
return context.querySelector(selector);
};
var $$ = function ( selector, context ) {
context = context || document;
return arrayify( context.querySelectorAll(selector) );
};
var translate = function ( t ) {
return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
};
var rotate = function ( r, revert ) {
var rX = " rotateX(" + r.x + "deg) ",
rY = " rotateY(" + r.y + "deg) ",
rZ = " rotateZ(" + r.z + "deg) ";
return revert ? rZ+rY+rX : rX+rY+rZ;
};
var scale = function ( s ) {
return " scale(" + s + ") ";
};
var getElementFromUrl = function () {
// get id from url # by removing `#` or `#/` from the beginning,
// so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
return byId( window.location.hash.replace(/^#\/?/,"") );
};
// CHECK SUPPORT
var ua = navigator.userAgent.toLowerCase();
var impressSupported = ( pfx("perspective") != null ) &&
( document.body.classList ) &&
( document.body.dataset ) &&
( ua.search(/(iphone)|(ipod)|(android)/) == -1 );
var roots = {};
var impress = window.impress = function ( rootId ) {
rootId = rootId || "impress";
// if already initialized just return the API
if (roots["impress-root-" + rootId]) {
return roots["impress-root-" + rootId];
}
// DOM ELEMENTS
var root = byId( rootId );
if (!impressSupported) {
root.className = "impress-not-supported";
return;
} else {
root.className = "";
}
// viewport updates for iPad
var meta = $("meta[name='viewport']") || document.createElement("meta");
// hardcoding these values looks pretty bad, as they kind of depend on the content
// so they should be at least configurable
meta.content = "width=1024, minimum-scale=0.75, maximum-scale=0.75, user-scalable=no";
if (meta.parentNode != document.head) {
meta.name = 'viewport';
document.head.appendChild(meta);
}
var canvas = document.createElement("div");
canvas.className = "canvas";
arrayify( root.childNodes ).forEach(function ( el ) {
canvas.appendChild( el );
});
root.appendChild(canvas);
var steps = $$(".step", root);
// SETUP
// set initial values and defaults
document.documentElement.style.height = "100%";
css(document.body, {
height: "100%",
overflow: "hidden"
});
var props = {
position: "absolute",
transformOrigin: "top left",
transition: "all 0s ease-in-out",
transformStyle: "preserve-3d"
}
css(root, props);
css(root, {
top: "50%",
left: "50%",
perspective: "1000px"
});
css(canvas, props);
var current = {
translate: { x: 0, y: 0, z: 0 },
rotate: { x: 0, y: 0, z: 0 },
scale: 1
};
var stepData = {};
var isStep = function ( el ) {
return !!(el && el.id && stepData["impress-" + el.id]);
}
steps.forEach(function ( el, idx ) {
var data = el.dataset,
step = {
translate: {
x: data.x || 0,
y: data.y || 0,
z: data.z || 0
},
rotate: {
x: data.rotateX || 0,
y: data.rotateY || 0,
z: data.rotateZ || data.rotate || 0
},
scale: data.scale || 1,
el: el
};
if ( !el.id ) {
el.id = "step-" + (idx + 1);
}
stepData["impress-" + el.id] = step;
css(el, {
position: "absolute",
transform: "translate(-50%,-50%)" +
translate(step.translate) +
rotate(step.rotate) +
scale(step.scale),
transformStyle: "preserve-3d"
});
});
// making given step active
var active = null;
var hashTimeout = null;
var goto = function ( el ) {
if ( !isStep(el) || el == active) {
// selected element is not defined as step or is already active
return false;
}
// Sometimes it's possible to trigger focus on first link with some keyboard action.
// Browser in such a case tries to scroll the page to make this element visible
// (even that body overflow is set to hidden) and it breaks our careful positioning.
//
// So, as a lousy (and lazy) workaround we will make the page scroll back to the top
// whenever slide is selected
//
// If you are reading this and know any better way to handle it, I'll be glad to hear about it!
window.scrollTo(0, 0);
var step = stepData["impress-" + el.id];
if ( active ) {
active.classList.remove("active");
}
el.classList.add("active");
root.className = "step-" + el.id;
// `#/step-id` is used instead of `#step-id` to prevent default browser
// scrolling to element in hash
//
// and it has to be set after animation finishes, because in chrome it
// causes transtion being laggy
window.clearTimeout( hashTimeout );
hashTimeout = window.setTimeout(function () {
window.location.hash = "#/" + el.id;
}, 1000);
var target = {
rotate: {
x: -parseInt(step.rotate.x, 10),
y: -parseInt(step.rotate.y, 10),
z: -parseInt(step.rotate.z, 10)
},
translate: {
x: -step.translate.x,
y: -step.translate.y,
z: -step.translate.z
},
scale: 1 / parseFloat(step.scale)
};
// check if the transition is zooming in or not
var zoomin = target.scale >= current.scale;
// if presentation starts (nothing is active yet)
// don't animate (set duration to 0)
var duration = (active) ? "1s" : "0";
css(root, {
// to keep the perspective look similar for different scales
// we need to 'scale' the perspective, too
perspective: step.scale * 1000 + "px",
transform: scale(target.scale),
transitionDuration: duration,
transitionDelay: (zoomin ? "500ms" : "0ms")
});
css(canvas, {
transform: rotate(target.rotate, true) + translate(target.translate),
transitionDuration: duration,
transitionDelay: (zoomin ? "0ms" : "500ms")
});
current = target;
active = el;
return el;
};
var prev = function () {
var prev = steps.indexOf( active ) - 1;
prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
return goto(prev);
};
var next = function () {
var next = steps.indexOf( active ) + 1;
next = next < steps.length ? steps[ next ] : steps[ 0 ];
return goto(next);
};
window.addEventListener("hashchange", function () {
goto( getElementFromUrl() );
}, false);
window.addEventListener("orientationchange", function () {
window.scrollTo(0, 0);
}, false);
// START
// by selecting step defined in url or first step of the presentation
goto(getElementFromUrl() || steps[0]);
return (roots[ "impress-root-" + rootId ] = {
goto: goto,
next: next,
prev: prev
});
}
})(document, window);
// EVENTS
(function ( document, window ) {
'use strict';
// keyboard navigation handler
document.addEventListener("keydown", function ( event ) {
if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
switch( event.keyCode ) {
case 33: ; // pg up
case 37: ; // left
case 38: // up
impress().prev();
break;
case 9: ; // tab
case 32: ; // space
case 34: ; // pg down
case 39: ; // right
case 40: // down
impress().next();
break;
}
event.preventDefault();
}
}, false);
// delegated handler for clicking on the links to presentation steps
document.addEventListener("click", function ( event ) {
// event delegation with "bubbling"
// check if event target (or any of its parents is a link)
var target = event.target;
while ( (target.tagName != "A") &&
(target != document.body) ) {
target = target.parentNode;
}
if ( target.tagName == "A" ) {
var href = target.getAttribute("href");
// if it's a link to presentation step, target this step
if ( href && href[0] == '#' ) {
target = document.getElementById( href.slice(1) );
}
}
if ( impress().goto(target) ) {
event.stopImmediatePropagation();
event.preventDefault();
}
}, false);
// delegated handler for clicking on step elements
document.addEventListener("click", function ( event ) {
var target = event.target;
// find closest step element
while ( !target.classList.contains("step") &&
(target != document.body) ) {
target = target.parentNode;
}
if ( impress().goto(target) ) {
event.preventDefault();
}
}, false);
// touch handler to detect taps on the left and right side of the screen
document.addEventListener("touchstart", function ( event ) {
if (event.touches.length === 1) {
var x = event.touches[0].clientX,
width = window.innerWidth * 0.3,
result = null;
if ( x < width ) {
result = impress().prev();
} else if ( x > window.innerWidth - width ) {
result = impress().next();
}
if (result) {
event.preventDefault();
}
}
}, false);
})(document, window);
My question is the Impress.js supposedly to process the data-x, data-y, data-scale attribute of the div tag. But I don't see where the code in Impress.js is doing that. Can someone point it out?
This intro to datasets may help.
First this part checking support for .dataset:
// CHECK SUPPORT
var ua = navigator.userAgent.toLowerCase();
var impressSupported = ( pfx("perspective") != null ) &&
( document.body.classList ) &&
( document.body.dataset ) &&
( ua.search(/(iphone)|(ipod)|(android)/) == -1 );
Then this part of the code, about halfway down:
steps.forEach(function ( el, idx ) {
var data = el.dataset,
step = {
translate: {
x: data.x || 0,
y: data.y || 0,
z: data.z || 0
},
rotate: {
x: data.rotateX || 0,
y: data.rotateY || 0,
z: data.rotateZ || data.rotate || 0
},
scale: data.scale || 1,
el: el
};

jquery html chrome developer tools timeline, jquery firing for every mousemove event?

jQuery is firing on every mousemove event for me.
How do I get it to stop doing that?
It seems like jQuery 1.2.6 do not have this behavior, but 1.4 and 1.5 does.
Stackoverflow.com does the same thing. Wonder what changed.
The jQuery event code:
/*
* A number of helper functions used for managing events.
* Many of the ideas behind this code originated from
* Dean Edwards' addEvent library.
*/
jQuery.event = {
// Bind an event to an element
// Original by Dean Edwards
add: function( elem, types, handler, data ) {
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
// TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)
// Minor release fix for bug #8018
try {
// For whatever reason, IE has trouble passing the window object
// around, causing it to be cloned in the process
if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
elem = window;
}
}
catch ( e ) {}
if ( handler === false ) {
handler = returnFalse;
} else if ( !handler ) {
// Fixes bug #7229. Fix recommended by jdalton
return;
}
var handleObjIn, handleObj;
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
}
// Make sure that the function being executed has a unique ID
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
// Init the element's event structure
var elemData = jQuery._data( elem );
// If no elemData is found then we must be trying to bind to one of the
// banned noData elements
if ( !elemData ) {
return;
}
var events = elemData.events,
eventHandle = elemData.handle;
if ( !events ) {
elemData.events = events = {};
}
if ( !eventHandle ) {
elemData.handle = eventHandle = function( e ) {
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
}
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native events in IE.
eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = types.split(" ");
var type, i = 0, namespaces;
while ( (type = types[ i++ ]) ) {
handleObj = handleObjIn ?
jQuery.extend({}, handleObjIn) :
{ handler: handler, data: data };
// Namespaced event handlers
if ( type.indexOf(".") > -1 ) {
namespaces = type.split(".");
type = namespaces.shift();
handleObj.namespace = namespaces.slice(0).sort().join(".");
} else {
namespaces = [];
handleObj.namespace = "";
}
handleObj.type = type;
if ( !handleObj.guid ) {
handleObj.guid = handler.guid;
}
// Get the current list of functions bound to this event
var handlers = events[ type ],
special = jQuery.event.special[ type ] || {};
// Init the event handler queue
if ( !handlers ) {
handlers = events[ type ] = [];
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
if ( special.add ) {
special.add.call( elem, handleObj );
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
// Add the function to the element's handler list
handlers.push( handleObj );
// Keep track of which events have been used, for global triggering
jQuery.event.global[ type ] = true;
}
// Nullify elem to prevent memory leaks in IE
elem = null;
},
global: {},
// Detach an event or set of events from an element
remove: function( elem, types, handler, pos ) {
// don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
if ( handler === false ) {
handler = returnFalse;
}
var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
events = elemData && elemData.events;
if ( !elemData || !events ) {
return;
}
// types is actually an event object here
if ( types && types.type ) {
handler = types.handler;
types = types.type;
}
// Unbind all events for the element
if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
types = types || "";
for ( type in events ) {
jQuery.event.remove( elem, type + types );
}
return;
}
// Handle multiple events separated by a space
// jQuery(...).unbind("mouseover mouseout", fn);
types = types.split(" ");
while ( (type = types[ i++ ]) ) {
origType = type;
handleObj = null;
all = type.indexOf(".") < 0;
namespaces = [];
if ( !all ) {
// Namespaced event handlers
namespaces = type.split(".");
type = namespaces.shift();
namespace = new RegExp("(^|\\.)" +
jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
}
eventType = events[ type ];
if ( !eventType ) {
continue;
}
if ( !handler ) {
for ( j = 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( all || namespace.test( handleObj.namespace ) ) {
jQuery.event.remove( elem, origType, handleObj.handler, j );
eventType.splice( j--, 1 );
}
}
continue;
}
special = jQuery.event.special[ type ] || {};
for ( j = pos || 0; j < eventType.length; j++ ) {
handleObj = eventType[ j ];
if ( handler.guid === handleObj.guid ) {
// remove the given handler for the given type
if ( all || namespace.test( handleObj.namespace ) ) {
if ( pos == null ) {
eventType.splice( j--, 1 );
}
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
if ( pos != null ) {
break;
}
}
}
// remove generic event handler if no more handlers exist
if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
ret = null;
delete events[ type ];
}
}
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
var handle = elemData.handle;
if ( handle ) {
handle.elem = null;
}
delete elemData.events;
delete elemData.handle;
if ( jQuery.isEmptyObject( elemData ) ) {
jQuery.removeData( elem, undefined, true );
}
}
},
// bubbling is internal
trigger: function( event, data, elem /*, bubbling */ ) {
// Event object or event type
var type = event.type || event,
bubbling = arguments[3];
if ( !bubbling ) {
event = typeof event === "object" ?
// jQuery.Event object
event[ jQuery.expando ] ? event :
// Object literal
jQuery.extend( jQuery.Event(type), event ) :
// Just the event type (string)
jQuery.Event(type);
if ( type.indexOf("!") >= 0 ) {
event.type = type = type.slice(0, -1);
event.exclusive = true;
}
// Handle a global trigger
if ( !elem ) {
// Don't bubble custom events when global (to avoid too much overhead)
event.stopPropagation();
// Only trigger if we've ever bound an event for it
if ( jQuery.event.global[ type ] ) {
// XXX This code smells terrible. event.js should not be directly
// inspecting the data cache
jQuery.each( jQuery.cache, function() {
// internalKey variable is just used to make it easier to find
// and potentially change this stuff later; currently it just
// points to jQuery.expando
var internalKey = jQuery.expando,
internalCache = this[ internalKey ];
if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
jQuery.event.trigger( event, data, internalCache.handle.elem );
}
});
}
}
// Handle triggering a single element
// don't do events on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
return undefined;
}
// Clean up in case it is reused
event.result = undefined;
event.target = elem;
// Clone the incoming data, if any
data = jQuery.makeArray( data );
data.unshift( event );
}
event.currentTarget = elem;
// Trigger the event, it is assumed that "handle" is a function
var handle = jQuery._data( elem, "handle" );
if ( handle ) {
handle.apply( elem, data );
}
var parent = elem.parentNode || elem.ownerDocument;
// Trigger an inline bound script
try {
if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
event.result = false;
event.preventDefault();
}
}
// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (inlineError) {}
if ( !event.isPropagationStopped() && parent ) {
jQuery.event.trigger( event, data, parent, true );
} else if ( !event.isDefaultPrevented() ) {
var old,
target = event.target,
targetType = type.replace( rnamespaces, "" ),
isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
special = jQuery.event.special[ targetType ] || {};
if ( (!special._default || special._default.call( elem, event ) === false) &&
!isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
try {
if ( target[ targetType ] ) {
// Make sure that we don't accidentally re-trigger the onFOO events
old = target[ "on" + targetType ];
if ( old ) {
target[ "on" + targetType ] = null;
}
jQuery.event.triggered = event.type;
target[ targetType ]();
}
// prevent IE from throwing an error for some elements with some event types, see #3533
} catch (triggerError) {}
if ( old ) {
target[ "on" + targetType ] = old;
}
jQuery.event.triggered = undefined;
}
}
},
handle: function( event ) {
var all, handlers, namespaces, namespace_re, events,
namespace_sort = [],
args = jQuery.makeArray( arguments );
event = args[0] = jQuery.event.fix( event || window.event );
event.currentTarget = this;
// Namespaced event handlers
all = event.type.indexOf(".") < 0 && !event.exclusive;
if ( !all ) {
namespaces = event.type.split(".");
event.type = namespaces.shift();
namespace_sort = namespaces.slice(0).sort();
namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
}
event.namespace = event.namespace || namespace_sort.join(".");
events = jQuery._data(this, "events");
handlers = (events || {})[ event.type ];
if ( events && handlers ) {
// Clone the handlers to prevent manipulation
handlers = handlers.slice(0);
for ( var j = 0, l = handlers.length; j < l; j++ ) {
var handleObj = handlers[ j ];
// Filter the functions by class
if ( all || namespace_re.test( handleObj.namespace ) ) {
// Pass in a reference to the handler function itself
// So that we can later remove it
event.handler = handleObj.handler;
event.data = handleObj.data;
event.handleObj = handleObj;
var ret = handleObj.handler.apply( this, args );
if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
if ( event.isImmediatePropagationStopped() ) {
break;
}
}
}
}
return event.result;
},
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
// store a copy of the original event object
// and "clone" to set read-only properties
var originalEvent = event;
event = jQuery.Event( originalEvent );
for ( var i = this.props.length, prop; i; ) {
prop = this.props[ --i ];
event[ prop ] = originalEvent[ prop ];
}
// Fix target property, if necessary
if ( !event.target ) {
// Fixes #1925 where srcElement might not be defined either
event.target = event.srcElement || document;
}
// check if target is a textnode (safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
// Add relatedTarget, if necessary
if ( !event.relatedTarget && event.fromElement ) {
event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
}
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && event.clientX != null ) {
var doc = document.documentElement,
body = document.body;
event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
}
// Add which for key events
if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
event.which = event.charCode != null ? event.charCode : event.keyCode;
}
// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
if ( !event.metaKey && event.ctrlKey ) {
event.metaKey = event.ctrlKey;
}
// Add which for click: 1 === left; 2 === middle; 3 === right
// Note: button is not normalized, so don't use it
if ( !event.which && event.button !== undefined ) {
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
}
return event;
},
// Deprecated, use jQuery.guid instead
guid: 1E8,
// Deprecated, use jQuery.proxy instead
proxy: jQuery.proxy,
special: {
ready: {
// Make sure the ready event is setup
setup: jQuery.bindReady,
teardown: jQuery.noop
},
live: {
add: function( handleObj ) {
jQuery.event.add( this,
liveConvert( handleObj.origType, handleObj.selector ),
jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
},
remove: function( handleObj ) {
jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
}
},
beforeunload: {
setup: function( data, namespaces, eventHandle ) {
// We only want to do this special case on windows
if ( jQuery.isWindow( this ) ) {
this.onbeforeunload = eventHandle;
}
},
teardown: function( namespaces, eventHandle ) {
if ( this.onbeforeunload === eventHandle ) {
this.onbeforeunload = null;
}
}
}
}
};
To clarify, I don't like this behavior. I think it's unnecessary, especially if I never intend to use mousemove in the first place.
This kind of thing matters in some situations.
In the developer tools, go to the Sources tab, then on the right open up Event Listener Breakpoints from the accordion menu. Make sure nothing is selected. I had this problem because somehow mouse/click events were selected, so it was stopping there every time.
This is not an intrinsic part of jQuery's event handling code, but instead only occurs on some sites.
Presumably those sites are using some specific feature that ends up listening to all mouse moves, e.g. on the document object or the <body /> or the like. A good candidate for what could cause this would be the (mis)use of .live(); in general .delegate() is preferable, but sometimes .live() is unavoidable.
Regardless, whichever feature it is that causes this, StackOverflow et al. are willing to accept this cost. As you build up your own site, you can periodically check the Developer Tools timeline, and if this kind of behavior appears, you can make your own decision on cost/benefit.