Version 4.2.0
This commit is contained in:
1 parent
0dc2aee5ed
commit
96997ddd8e
2074 files changed
+125454
-55780
No files matched your search
@@ -0,0 +1,462 @@
|
||||
window.ips = {};
|
||||
|
||||
/**
|
||||
* Event handling
|
||||
*/
|
||||
// http://www.anujgakhar.com/2013/05/22/cross-browser-event-handling-in-javascript/
|
||||
window.ips.eventHandler = {
|
||||
on: function (el, ev, fn) {
|
||||
if( window.addEventListener ){
|
||||
el.addEventListener( ev, fn, false );
|
||||
} else if( window.attachEvent ){
|
||||
el.attachEvent( 'on' + ev, fn );
|
||||
} else {
|
||||
el[ 'on' + ev ] = fn;
|
||||
}
|
||||
},
|
||||
|
||||
off: function (el, ev, fn) {
|
||||
if( window.removeEventListener ){
|
||||
el.removeEventListener( ev, fn, false );
|
||||
} else if( window.detachEvent ) {
|
||||
el.detachEvent( 'on' + ev, fn );
|
||||
} else {
|
||||
elem[ 'on' + ev ] = null;
|
||||
}
|
||||
},
|
||||
|
||||
stop: function (ev) {
|
||||
var e = ev || window.event;
|
||||
e.cancelBubble = true;
|
||||
if( e.stopPropagation ){
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
window.ips.utils = {
|
||||
|
||||
/**
|
||||
* Log to console if supported
|
||||
*
|
||||
* @param {string} message Message to log
|
||||
* @returns {void}
|
||||
*/
|
||||
log: function (message) {
|
||||
if( window.console ){
|
||||
console.log( "(EMBED): " + message );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Error to console if supported
|
||||
*
|
||||
* @param {string} message Message to log
|
||||
* @returns {void}
|
||||
*/
|
||||
error: function (message) {
|
||||
if( window.console ){
|
||||
console.error( message );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets an element based on ID
|
||||
*
|
||||
* @param {string} id Element ID
|
||||
* @returns {element}
|
||||
*/
|
||||
get: function (id) {
|
||||
return document.getElementById( id );
|
||||
},
|
||||
|
||||
/**
|
||||
* Extend an object with another object
|
||||
*
|
||||
* @param {object} originalObj Original object
|
||||
* @param {object} newObj New object
|
||||
* @returns {void}
|
||||
*/
|
||||
extendObj: function (originalObj, newObj) {
|
||||
for( var i in newObj ){
|
||||
if( newObj.hasOwnProperty(i) ){
|
||||
originalObj[i] = newObj[i];
|
||||
}
|
||||
}
|
||||
|
||||
return originalObj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns parsed information about a URL
|
||||
*
|
||||
* @param {string} url URL to parse
|
||||
* @returns {object}
|
||||
*/
|
||||
parseURL: function (url) {
|
||||
var elem = document.createElement('a');
|
||||
ips.utils.insertBefore( elem, document.body.firstChild );
|
||||
elem.href = url;
|
||||
|
||||
var data = {
|
||||
protocol: elem.protocol,
|
||||
hostname: elem.hostname,
|
||||
port: elem.port,
|
||||
pathname: elem.pathname,
|
||||
search: elem.search,
|
||||
hash: elem.hash,
|
||||
host: elem.host
|
||||
};
|
||||
|
||||
elem.parentNode.removeChild( elem );
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the document scroll offset
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
getScrollOffset: function () {
|
||||
var doc = document.documentElement;
|
||||
|
||||
return {
|
||||
left: (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0),
|
||||
top: (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the offset relative to the document for an element
|
||||
*
|
||||
* @param {element} element Element to get the offset for
|
||||
* @returns {object}
|
||||
*/
|
||||
getOffset: function (element) {
|
||||
var p = {
|
||||
left: element.offsetLeft || 0,
|
||||
top: element.offsetTop || 0
|
||||
};
|
||||
|
||||
while (element = element.offsetParent) {
|
||||
p.left += element.offsetLeft;
|
||||
p.top += element.offsetTop;
|
||||
}
|
||||
|
||||
return p;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the outer height of the element
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getObjHeight: function (elem) {
|
||||
return elem.offsetHeight || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the outer width of the element
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getObjWidth: function (elem) {
|
||||
return elem.offsetWidth || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fade the element in
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
fadeIn: function (elem) {
|
||||
elem.style.opacity = 0;
|
||||
|
||||
var last = +new Date();
|
||||
var tick = function() {
|
||||
elem.style.opacity = (parseFloat(elem.style.opacity) + (new Date() - last) / 400).toFixed(2);
|
||||
last = +new Date();
|
||||
|
||||
if( parseFloat(elem.style.opacity) < 1 ){
|
||||
( window.requestAnimationFrame && requestAnimationFrame(tick) ) || setTimeout(tick, 16);
|
||||
} else if (parseFloat(elem.style.opacity) >= 1) {
|
||||
elem.style.opacity = 1;
|
||||
}
|
||||
};
|
||||
|
||||
tick();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the document height
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getDocHeight: function () {
|
||||
var D = document;
|
||||
|
||||
return Math.max(
|
||||
D.body.scrollHeight, D.documentElement.scrollHeight,
|
||||
D.body.offsetHeight, D.documentElement.offsetHeight,
|
||||
D.body.clientHeight, D.documentElement.clientHeight
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the viewport height
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getViewportHeight: function () {
|
||||
return Math.max( document.documentElement.clientHeight, window.innerHeight || 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns attributes for an element
|
||||
*
|
||||
* @param {element} element DOM element
|
||||
* @returns {object}
|
||||
*/
|
||||
getAttributes: function (element) {
|
||||
if( typeof element == 'undefined' ){
|
||||
return;
|
||||
}
|
||||
|
||||
var attributes = {};
|
||||
|
||||
if( element.hasAttributes() ){
|
||||
var _attr = element.attributes;
|
||||
|
||||
for( var i = 0; i < _attr.length; i++ ){
|
||||
attributes[ _attr[ i ].name.toLowerCase() ] = _attr[ i ].value;
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
},
|
||||
|
||||
/**
|
||||
* A simple method to insert an element after another element
|
||||
*
|
||||
* @param {element} elem The new element
|
||||
* @param {element} existing The existing element, after which the new will be inserted
|
||||
* @returns {void}
|
||||
*/
|
||||
insertAfter: function (elem, existing) {
|
||||
existing.parentNode.insertBefore( elem, existing.nextSibling );
|
||||
},
|
||||
|
||||
/**
|
||||
* A simple method to insert an element before another element
|
||||
*
|
||||
* @param {element} elem The new element
|
||||
* @param {element} existing The existing element, before which the new will be inserted
|
||||
* @returns {void}
|
||||
*/
|
||||
insertBefore: function (elem, existing) {
|
||||
existing.parentNode.insertBefore( elem, existing );
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a style property value for the given element and style
|
||||
*
|
||||
* @param {element} elem Element whose style is to be fetched
|
||||
* @param {string} style Property to fetch
|
||||
* @returns {mixed}
|
||||
*/
|
||||
getStyle: function (elem, style) {
|
||||
return window.getComputedStyle( elem, null ).getPropertyValue( style );
|
||||
},
|
||||
|
||||
/*
|
||||
* Cross-browser 'dom ready' event handler to init the page
|
||||
*/
|
||||
/*! contentloaded.min.js - https://github.com/dperini/ContentLoaded - Author: Diego Perini - License: MIT */
|
||||
contentLoaded: function (b,i) {
|
||||
var j=false,k=true,a=b.document,l=a.documentElement,f=a.addEventListener,h=f?'addEventListener':'attachEvent',n=f?'removeEventListener':'detachEvent',g=f?'':'on',c=function(d){if(d.type=='readystatechange'&&a.readyState!='complete')return;(d.type=='load'?b:a)[n](g+d.type,c,false);if(!j&&(j=true))i.call(b,d.type||d)},m=function(){try{l.doScroll('left')}catch(e){setTimeout(m,50);return}c('poll')};if(a.readyState=='complete')i.call(b,'lazy');else{if(!f&&l.doScroll){try{k=!b.frameElement}catch(e){}if(k)m()}a[h](g+'DOMContentLoaded',c,false);a[h](g+'readystatechange',c,false);b[h](g+'load',c,false)}
|
||||
}
|
||||
};
|
||||
|
||||
/* Polyfill for Element.closest, from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest */
|
||||
if (window.Element && !Element.prototype.closest) {
|
||||
Element.prototype.closest = function(s) {
|
||||
var matches = (this.document || this.ownerDocument).querySelectorAll(s);
|
||||
var i;
|
||||
var el = this;
|
||||
|
||||
do {
|
||||
i = matches.length;
|
||||
while (--i >= 0 && matches.item(i) !== el) {};
|
||||
} while ((i < 0) && (el = el.parentElement));
|
||||
|
||||
return el;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TextOverflowClamp.js
|
||||
*
|
||||
* Updated 2014-05-08 to improve speed and fix some bugs.
|
||||
*
|
||||
* Updated 2013-05-09 to remove jQuery dependancy.
|
||||
* But be careful with webfonts!
|
||||
*
|
||||
* NEW!
|
||||
* - Support for padding.
|
||||
* - Support for nearby floated elements.
|
||||
* - Support for text-indent.
|
||||
*/
|
||||
|
||||
// bind function support for older browsers without it
|
||||
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (oThis) {
|
||||
if (typeof this !== "function") {
|
||||
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
||||
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () {},
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP && oThis
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
fNOP.prototype = this.prototype;
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
|
||||
// the actual meat is here
|
||||
(function(w, d){
|
||||
var clamp, measure, text, lineWidth,
|
||||
lineStart, lineCount, wordStart,
|
||||
line, lineText, wasNewLine,
|
||||
ce = d.createElement.bind(d),
|
||||
ctn = d.createTextNode.bind(d),
|
||||
width, widthChild, newWidthChild;
|
||||
|
||||
// measurement element is made a child of the clamped element to get it's style
|
||||
measure = ce('span');
|
||||
|
||||
(function(s){
|
||||
s.position = 'absolute'; // prevent page reflow
|
||||
s.whiteSpace = 'pre'; // cross-browser width results
|
||||
s.visibility = 'hidden'; // prevent drawing
|
||||
})(measure.style);
|
||||
|
||||
// width element calculates the width of each line
|
||||
width = ce('span');
|
||||
|
||||
widthChild = ce('span');
|
||||
widthChild.style.display = 'block';
|
||||
widthChild.style.overflow = 'hidden';
|
||||
widthChild.appendChild(ctn("\u2060"));
|
||||
|
||||
clamp = function (el, lineClamp) {
|
||||
var i;
|
||||
// make sure the element belongs to the document
|
||||
if(!el.ownerDocument || !el.ownerDocument === d) return;
|
||||
// reset to safe starting values
|
||||
lineStart = wordStart = 0;
|
||||
lineCount = 1;
|
||||
wasNewLine = false;
|
||||
//lineWidth = el.clientWidth;
|
||||
lineWidth = [];
|
||||
// get all the text, remove any line changes
|
||||
text = (el.textContent || el.innerText).replace(/\n/g, ' ');
|
||||
// create a child block element that accounts for floats
|
||||
for(i = 1; i < lineClamp; i++) {
|
||||
newWidthChild = widthChild.cloneNode(true);
|
||||
width.appendChild(newWidthChild);
|
||||
if(i === 1) {
|
||||
widthChild.style.textIndent = 0;
|
||||
}
|
||||
}
|
||||
widthChild.style.textIndent = '';
|
||||
// cleanup
|
||||
newWidthChild = void 0;
|
||||
// remove all content
|
||||
while(el.firstChild)
|
||||
el.removeChild(el.firstChild);
|
||||
// ready for width calculating magic
|
||||
el.appendChild(width);
|
||||
// then start calculating widths of each line
|
||||
for(i = 0; i < lineClamp - 1; i++) {
|
||||
lineWidth.push(width.childNodes[i].clientWidth);
|
||||
}
|
||||
// we are done, no need for this anymore
|
||||
el.removeChild(width);
|
||||
// cleanup the lines
|
||||
while(width.firstChild)
|
||||
width.removeChild(width.firstChild);
|
||||
// add measurement element within so it inherits styles
|
||||
el.appendChild(measure);
|
||||
// http://ejohn.org/blog/search-and-dont-replace/
|
||||
text.replace(/ /g, function(m, pos) {
|
||||
// ignore any further processing if we have total lines
|
||||
if(lineCount === lineClamp) return;
|
||||
// create a text node and place it in the measurement element
|
||||
measure.appendChild(ctn(text.substr(lineStart, pos - lineStart)));
|
||||
// have we exceeded allowed line width?
|
||||
if(lineWidth[lineCount - 1] <= measure.clientWidth) {
|
||||
if(wasNewLine) {
|
||||
// we have a long word so it gets a line of it's own
|
||||
lineText = text.substr(lineStart, pos + 1 - lineStart);
|
||||
// next line start position
|
||||
lineStart = pos + 1;
|
||||
} else {
|
||||
// grab the text until this word
|
||||
lineText = text.substr(lineStart, wordStart - lineStart);
|
||||
// next line start position
|
||||
lineStart = wordStart;
|
||||
}
|
||||
// create a line element
|
||||
line = ce('span');
|
||||
// add text to the line element
|
||||
line.appendChild(ctn(lineText));
|
||||
// add the line element to the container
|
||||
el.appendChild(line);
|
||||
// yes, we created a new line
|
||||
wasNewLine = true;
|
||||
lineCount++;
|
||||
} else {
|
||||
// did not create a new line
|
||||
wasNewLine = false;
|
||||
}
|
||||
// remember last word start position
|
||||
wordStart = pos + 1;
|
||||
// clear measurement element
|
||||
measure.removeChild(measure.firstChild);
|
||||
});
|
||||
// remove the measurement element from the container
|
||||
el.removeChild(measure);
|
||||
// create the last line element
|
||||
line = ce('span');
|
||||
// see if we need to add styles
|
||||
if(lineCount === lineClamp) {
|
||||
// give styles required for text-overflow to kick in
|
||||
(function(s) {
|
||||
s.display = 'block';
|
||||
s.overflow = 'hidden';
|
||||
s.textIndent = 0;
|
||||
s.textOverflow = 'ellipsis';
|
||||
s.whiteSpace = 'nowrap';
|
||||
})(line.style);
|
||||
}
|
||||
// add all remaining text to the line element
|
||||
line.appendChild(ctn(text.substr(lineStart)));
|
||||
// add the line element to the container
|
||||
el.appendChild(line);
|
||||
}
|
||||
w.clamp = clamp;
|
||||
})(window, window.document);
|
||||
@@ -1,428 +0,0 @@
|
||||
/*
|
||||
* IPS embed handling
|
||||
* http://www.invisionpower.com
|
||||
*/
|
||||
( function () {
|
||||
"use strict";
|
||||
|
||||
var _origin;
|
||||
var _div;
|
||||
var _posting = false;
|
||||
var _timer;
|
||||
var _timeout = 200; //ms
|
||||
var _embedId = '';
|
||||
|
||||
/**
|
||||
* Init method, called when the document is ready
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function init() {
|
||||
// Check for postMessage and JSON support
|
||||
if( !window.postMessage || !window.JSON.parse ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Work out our URL
|
||||
_div = utils.get('ipsEmbed');
|
||||
var url = utils.parseURL( window.location );
|
||||
|
||||
if( url.protocol == '' || url.protocol == ':' ){
|
||||
utils.log( url );
|
||||
url.protocol = window.location.protocol;
|
||||
}
|
||||
|
||||
// Set our origin
|
||||
_origin = url.protocol + '//' + url.host;
|
||||
utils.log( "Origin in loader is " + _origin );
|
||||
|
||||
// Hide the content
|
||||
_div.style.opacity = '0.00001';
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts our main loop, which posts messages to the parent frame as needed
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function startTimeout() {
|
||||
|
||||
var currentSize = 0;
|
||||
var repeats = 0;
|
||||
|
||||
utils.log("Starting timeout...");
|
||||
|
||||
// Main loop
|
||||
_timer = setInterval( function () {
|
||||
// What we want to do here is make the loading process more pleasant and less jumpy.
|
||||
// To do that, we'll make the embed invisible until we've fetched the same height 6 times
|
||||
// in a row (approx 1 second). If that happens we'll assume it has finished loading, and then
|
||||
// we'll fade it in and start sending the recorded height to the parent for resizing.
|
||||
|
||||
var height = utils.getObjHeight( _div );
|
||||
|
||||
// If we HAVEN'T started posting our size
|
||||
if( !_posting ){
|
||||
if( height == currentSize ){
|
||||
repeats++;
|
||||
} else {
|
||||
// The height has changed, so reset our repeat counter
|
||||
repeats = 0;
|
||||
}
|
||||
|
||||
if( repeats == 6 ){
|
||||
_posting = true;
|
||||
utils.fadeIn( _div );
|
||||
}
|
||||
}
|
||||
|
||||
currentSize = height;
|
||||
|
||||
if( _posting ){
|
||||
_div.parentNode.className = '';
|
||||
|
||||
_postMessage('height', {
|
||||
height: height
|
||||
});
|
||||
}
|
||||
}, _timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* Posts a message to the iframe
|
||||
*
|
||||
* @param {number} [pageNo] Page number to load
|
||||
* @returns {void}
|
||||
*/
|
||||
var _postMessage = function (method, obj) {
|
||||
// Send to parent window
|
||||
window.top.postMessage( JSON.stringify( utils.extendObj( obj || {}, {
|
||||
method: method,
|
||||
embedId: _embedId
|
||||
} ) ), _origin );
|
||||
};
|
||||
|
||||
/**
|
||||
* Events sent to the iframe
|
||||
*/
|
||||
var messageEvents = {
|
||||
/**
|
||||
* The parent is ready for messages
|
||||
*
|
||||
* @param {object} data Data from the iframe
|
||||
* @returns {void}
|
||||
*/
|
||||
ready: function (data) {
|
||||
_embedId = data.embedId;
|
||||
_postMessage('ok');
|
||||
|
||||
startTimeout();
|
||||
},
|
||||
|
||||
stop: function (data) {
|
||||
clearInterval( _timer );
|
||||
eventHandler.off( window, 'message', windowMessage );
|
||||
}
|
||||
};
|
||||
|
||||
/*******************************************************************************************/
|
||||
/* Boring stuff below */
|
||||
|
||||
|
||||
/**
|
||||
* Event handling
|
||||
*/
|
||||
// http://www.anujgakhar.com/2013/05/22/cross-browser-event-handling-in-javascript/
|
||||
var eventHandler = {
|
||||
on: function (el, ev, fn) {
|
||||
if( window.addEventListener ){
|
||||
el.addEventListener( ev, fn, false );
|
||||
} else if( window.attachEvent ){
|
||||
el.attachEvent( 'on' + ev, fn );
|
||||
} else {
|
||||
el[ 'on' + ev ] = fn;
|
||||
}
|
||||
},
|
||||
|
||||
off: function (el, ev, fn) {
|
||||
if( window.removeEventListener ){
|
||||
el.removeEventListener( ev, fn, false );
|
||||
} else if( window.detachEvent ) {
|
||||
el.detachEvent( 'on' + ev, fn );
|
||||
} else {
|
||||
elem[ 'on' + ev ] = null;
|
||||
}
|
||||
},
|
||||
|
||||
stop: function (ev) {
|
||||
var e = ev || window.event;
|
||||
e.cancelBubble = true;
|
||||
if( e.stopPropagation ){
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Main message handler
|
||||
eventHandler.on( window, 'message', windowMessage );
|
||||
|
||||
function windowMessage (e) {
|
||||
if( e.origin !== _origin ){
|
||||
utils.log( e.origin + 'does not equal' + _origin );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var pmData = JSON.parse( e.data );
|
||||
var method = pmData.method;
|
||||
} catch (err) {
|
||||
utils.error("iframe: invalid data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( method && typeof messageEvents[ method ] != 'undefined' ){
|
||||
utils.log("Called " + method );
|
||||
messageEvents[ method ].call( this, pmData );
|
||||
} else {
|
||||
utils.log("Method " + method + " doesn't exist");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
var utils = {
|
||||
|
||||
/**
|
||||
* Log to console if supported
|
||||
*
|
||||
* @param {string} message Message to log
|
||||
* @returns {void}
|
||||
*/
|
||||
log: function (message) {
|
||||
if( window.console ){
|
||||
console.log( "(EMBED): " + message );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Error to console if supported
|
||||
*
|
||||
* @param {string} message Message to log
|
||||
* @returns {void}
|
||||
*/
|
||||
error: function (message) {
|
||||
if( window.console ){
|
||||
console.error( message );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets an element based on ID
|
||||
*
|
||||
* @param {string} id Element ID
|
||||
* @returns {element}
|
||||
*/
|
||||
get: function (id) {
|
||||
return document.getElementById( id );
|
||||
},
|
||||
|
||||
/**
|
||||
* Extend an object with another object
|
||||
*
|
||||
* @param {object} originalObj Original object
|
||||
* @param {object} newObj New object
|
||||
* @returns {void}
|
||||
*/
|
||||
extendObj: function (originalObj, newObj) {
|
||||
for( var i in newObj ){
|
||||
if( newObj.hasOwnProperty(i) ){
|
||||
originalObj[i] = newObj[i];
|
||||
}
|
||||
}
|
||||
|
||||
return originalObj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns parsed information about a URL
|
||||
*
|
||||
* @param {string} url URL to parse
|
||||
* @returns {object}
|
||||
*/
|
||||
parseURL: function (url) {
|
||||
var elem = document.createElement('a');
|
||||
utils.insertBefore( elem, _div );
|
||||
elem.href = url;
|
||||
|
||||
var data = {
|
||||
protocol: elem.protocol,
|
||||
hostname: elem.hostname,
|
||||
port: elem.port,
|
||||
pathname: elem.pathname,
|
||||
search: elem.search,
|
||||
hash: elem.hash,
|
||||
host: elem.host
|
||||
};
|
||||
|
||||
elem.parentNode.removeChild( elem );
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the document scroll offset
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
getScrollOffset: function () {
|
||||
var doc = document.documentElement;
|
||||
|
||||
return {
|
||||
left: (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0),
|
||||
top: (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the offset relative to the document for an element
|
||||
*
|
||||
* @param {element} element Element to get the offset for
|
||||
* @returns {object}
|
||||
*/
|
||||
getOffset: function (element) {
|
||||
var p = {
|
||||
left: element.offsetLeft || 0,
|
||||
top: element.offsetTop || 0
|
||||
};
|
||||
|
||||
while (element = element.offsetParent) {
|
||||
p.left += element.offsetLeft;
|
||||
p.top += element.offsetTop;
|
||||
}
|
||||
|
||||
return p;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the outer height of the element
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getObjHeight: function (elem) {
|
||||
return elem.offsetHeight || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fade the element in
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
fadeIn: function (elem) {
|
||||
elem.style.opacity = 0;
|
||||
|
||||
var last = +new Date();
|
||||
var tick = function() {
|
||||
elem.style.opacity = +elem.style.opacity + (new Date() - last) / 400;
|
||||
last = +new Date();
|
||||
|
||||
if( +elem.style.opacity < 1 ){
|
||||
( window.requestAnimationFrame && requestAnimationFrame(tick) ) || setTimeout(tick, 16);
|
||||
}
|
||||
};
|
||||
|
||||
tick();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the document height
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getDocHeight: function () {
|
||||
var D = document;
|
||||
|
||||
return Math.max(
|
||||
D.body.scrollHeight, D.documentElement.scrollHeight,
|
||||
D.body.offsetHeight, D.documentElement.offsetHeight,
|
||||
D.body.clientHeight, D.documentElement.clientHeight
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the viewport height
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getViewportHeight: function () {
|
||||
return Math.max( document.documentElement.clientHeight, window.innerHeight || 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns attributes for an element
|
||||
*
|
||||
* @param {element} element DOM element
|
||||
* @returns {object}
|
||||
*/
|
||||
getAttributes: function (element) {
|
||||
if( typeof element == 'undefined' ){
|
||||
return;
|
||||
}
|
||||
|
||||
var attributes = {};
|
||||
|
||||
if( element.hasAttributes() ){
|
||||
var _attr = element.attributes;
|
||||
|
||||
for( var i = 0; i < _attr.length; i++ ){
|
||||
attributes[ _attr[ i ].name.toLowerCase() ] = _attr[ i ].value;
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
},
|
||||
|
||||
/**
|
||||
* A simple method to insert an element after another element
|
||||
*
|
||||
* @param {element} elem The new element
|
||||
* @param {element} existing The existing element, after which the new will be inserted
|
||||
* @returns {void}
|
||||
*/
|
||||
insertAfter: function (elem, existing) {
|
||||
existing.parentNode.insertBefore( elem, existing.nextSibling );
|
||||
},
|
||||
|
||||
/**
|
||||
* A simple method to insert an element before another element
|
||||
*
|
||||
* @param {element} elem The new element
|
||||
* @param {element} existing The existing element, before which the new will be inserted
|
||||
* @returns {void}
|
||||
*/
|
||||
insertBefore: function (elem, existing) {
|
||||
existing.parentNode.insertBefore( elem, existing );
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a style property value for the given element and style
|
||||
*
|
||||
* @param {element} elem Element whose style is to be fetched
|
||||
* @param {string} style Property to fetch
|
||||
* @returns {mixed}
|
||||
*/
|
||||
getStyle: function (elem, style) {
|
||||
return window.getComputedStyle( elem, null ).getPropertyValue( style );
|
||||
},
|
||||
|
||||
/*
|
||||
* Cross-browser 'dom ready' event handler to init the page
|
||||
*/
|
||||
/*! contentloaded.min.js - https://github.com/dperini/ContentLoaded - Author: Diego Perini - License: MIT */
|
||||
contentLoaded: function (b,i) {
|
||||
var j=false,k=true,a=b.document,l=a.documentElement,f=a.addEventListener,h=f?'addEventListener':'attachEvent',n=f?'removeEventListener':'detachEvent',g=f?'':'on',c=function(d){if(d.type=='readystatechange'&&a.readyState!='complete')return;(d.type=='load'?b:a)[n](g+d.type,c,false);if(!j&&(j=true))i.call(b,d.type||d)},m=function(){try{l.doScroll('left')}catch(e){setTimeout(m,50);return}c('poll')};if(a.readyState=='complete')i.call(b,'lazy');else{if(!f&&l.doScroll){try{k=!b.frameElement}catch(e){}if(k)m()}a[h](g+'DOMContentLoaded',c,false);a[h](g+'readystatechange',c,false);b[h](g+'load',c,false)}
|
||||
}
|
||||
};
|
||||
utils.contentLoaded( window, function () {
|
||||
init();
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* IPS embed handling
|
||||
* https://www.invisioncommunity.com
|
||||
*/
|
||||
( function () {
|
||||
"use strict";
|
||||
|
||||
var _origin;
|
||||
var _div;
|
||||
var _posting = false;
|
||||
var _timer;
|
||||
var _timeout = 200; //ms
|
||||
var _embedId = '';
|
||||
var _failSafe = null;
|
||||
|
||||
/**
|
||||
* Init method, called when the document is ready
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function init() {
|
||||
// Check for postMessage and JSON support
|
||||
if( !window.postMessage || !window.JSON.parse ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Work out our URL
|
||||
_div = ips.utils.get('ipsEmbed');
|
||||
var url = ips.utils.parseURL( window.location );
|
||||
|
||||
if( url.protocol == '' || url.protocol == ':' ){
|
||||
utils.log( url );
|
||||
url.protocol = window.location.protocol;
|
||||
}
|
||||
|
||||
// Set our origin
|
||||
_origin = url.protocol + '//' + url.host;
|
||||
ips.utils.log( "Origin in loader is " + _origin );
|
||||
|
||||
// Hide the content
|
||||
_div.style.opacity = '0.00001';
|
||||
|
||||
// But if we're in the 'top frame', don't bother showing loading
|
||||
try {
|
||||
if( window.self === window.top ){
|
||||
_div.style.opacity = 1;
|
||||
_div.parentNode.className = '';
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
// Start an emergency timeout, which we'll use to force-show the embed if the parent page
|
||||
// isn't talking to us for some reason. This will force the embed to eventually show, albeit at the wrong size,
|
||||
// instead of just being forever loading.
|
||||
var counter = 0;
|
||||
_failSafe = setInterval( function () {
|
||||
if( counter >= 6 ){ // approx 6 seconds
|
||||
ips.utils.log("Triggered failsafe timer");
|
||||
_div.parentNode.className = '';
|
||||
ips.utils.fadeIn( _div );
|
||||
clearInterval( _failSafe );
|
||||
}
|
||||
counter++;
|
||||
}, 1000 );
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts our main loop, which posts messages to the parent frame as needed
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function startTimeout() {
|
||||
|
||||
var currentSize = 0;
|
||||
var repeats = 0;
|
||||
|
||||
ips.utils.log("Starting timeout...");
|
||||
|
||||
// Main loop
|
||||
_timer = setInterval( function () {
|
||||
// What we want to do here is make the loading process more pleasant and less jumpy.
|
||||
// To do that, we'll make the embed invisible until we've fetched the same height 6 times
|
||||
// in a row (approx 1 second). If that happens we'll assume it has finished loading, and then
|
||||
// we'll fade it in and start sending the recorded height to the parent for resizing.
|
||||
|
||||
var height = ips.utils.getObjHeight( _div );
|
||||
|
||||
// If we HAVEN'T started posting our size
|
||||
if( !_posting ){
|
||||
if( height == currentSize ){
|
||||
repeats++;
|
||||
} else {
|
||||
// The height has changed, so reset our repeat counter
|
||||
repeats = 0;
|
||||
}
|
||||
|
||||
if( repeats == 6 ){
|
||||
_posting = true;
|
||||
ips.utils.fadeIn( _div );
|
||||
}
|
||||
}
|
||||
|
||||
currentSize = height;
|
||||
|
||||
if( _posting ){
|
||||
_div.parentNode.className = '';
|
||||
|
||||
_postMessage('height', {
|
||||
height: ( height + 10 )
|
||||
});
|
||||
}
|
||||
}, _timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* Posts a message to the iframe
|
||||
*
|
||||
* @param {number} [pageNo] Page number to load
|
||||
* @returns {void}
|
||||
*/
|
||||
var _postMessage = function (method, obj) {
|
||||
// Send to parent window
|
||||
window.top.postMessage( JSON.stringify( ips.utils.extendObj( obj || {}, {
|
||||
method: method,
|
||||
embedId: _embedId
|
||||
} ) ), _origin );
|
||||
};
|
||||
|
||||
/**
|
||||
* Events sent to the iframe
|
||||
*/
|
||||
var messageEvents = {
|
||||
/**
|
||||
* The parent is ready for messages
|
||||
*
|
||||
* @param {object} data Data from the iframe
|
||||
* @returns {void}
|
||||
*/
|
||||
ready: function (data) {
|
||||
_embedId = data.embedId;
|
||||
_postMessage('ok');
|
||||
|
||||
startTimeout();
|
||||
clearInterval( _failSafe ); // Stop our emergency timer
|
||||
},
|
||||
|
||||
stop: function (data) {
|
||||
clearInterval( _timer );
|
||||
clearInterval( _failSafe ); // Stop our emergency timer
|
||||
eventHandler.off( window, 'message', windowMessage );
|
||||
}
|
||||
};
|
||||
|
||||
/*******************************************************************************************/
|
||||
/* Boring stuff below */
|
||||
|
||||
// Main message handler
|
||||
ips.eventHandler.on( window, 'message', windowMessage );
|
||||
|
||||
function windowMessage (e) {
|
||||
if( e.origin !== _origin ){
|
||||
ips.utils.log( e.origin + 'does not equal' + _origin );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var pmData = JSON.parse( e.data );
|
||||
var method = pmData.method;
|
||||
} catch (err) {
|
||||
ips.utils.error("iframe: invalid data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( method && typeof messageEvents[ method ] != 'undefined' ){
|
||||
ips.utils.log("Called " + method );
|
||||
messageEvents[ method ].call( this, pmData );
|
||||
} else {
|
||||
ips.utils.log("Method " + method + " doesn't exist");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ips.utils.contentLoaded( window, function () {
|
||||
init();
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* IPS embed handling
|
||||
* https://www.invisioncommunity.com
|
||||
*/
|
||||
( function () {
|
||||
"use strict";
|
||||
|
||||
var _origin;
|
||||
var _div;
|
||||
var _posting = false;
|
||||
var _timer;
|
||||
var _timeout = 200; //ms
|
||||
var _embedId = '';
|
||||
var _embedMaxWidth = null;
|
||||
var _initialHeight = 0;
|
||||
|
||||
/**
|
||||
* Init method, called when the document is ready
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function init() {
|
||||
// Check for postMessage and JSON support
|
||||
if( !window.postMessage || !window.JSON.parse ){
|
||||
return;
|
||||
}
|
||||
|
||||
// Work out our URL
|
||||
_div = ips.utils.get('ipsEmbed');
|
||||
var url = ips.utils.parseURL( window.location );
|
||||
|
||||
if( url.protocol == '' || url.protocol == ':' ){
|
||||
ips.utils.log( url );
|
||||
url.protocol = window.location.protocol;
|
||||
}
|
||||
|
||||
// Set our origin
|
||||
_origin = url.protocol + '//' + url.host;
|
||||
ips.utils.log( "Origin in loader is " + _origin );
|
||||
|
||||
// Hide the content
|
||||
_div.style.opacity = '0.00001';
|
||||
|
||||
_initialHeight = ips.utils.getObjHeight( _div );
|
||||
|
||||
// Do we have a specified maxWidth here?
|
||||
var maxWidthElem = document.querySelector('[data-embedInfo-maxSize]');
|
||||
|
||||
if( maxWidthElem ){
|
||||
_embedMaxWidth = parseInt( maxWidthElem.getAttribute('data-embedInfo-maxSize') );
|
||||
maxWidthElem.style.maxWidth = _embedMaxWidth + "px";
|
||||
}
|
||||
|
||||
// Check for any truncated text
|
||||
var truncated = document.querySelectorAll('[data-truncate]');
|
||||
|
||||
if( truncated ){
|
||||
for( var n = 0; n < truncated.length; n++ ){
|
||||
var size = parseInt( truncated[ n ].getAttribute('data-truncate') || 5 );
|
||||
clamp( truncated[ n ], size );
|
||||
}
|
||||
}
|
||||
|
||||
ips.eventHandler.on( document.body, 'click', clickLink );
|
||||
|
||||
// Set all links to open in a new tab/window
|
||||
var links = document.querySelectorAll('a');
|
||||
for( var i = 0; i < links.length; i++ ){
|
||||
links[i].setAttribute('target', '_blank');
|
||||
}
|
||||
|
||||
startTimeout();
|
||||
};
|
||||
|
||||
var _showEmbed = function () {
|
||||
document.body.className = document.body.className.replace('unloaded ', '');
|
||||
ips.utils.fadeIn( _div );
|
||||
};
|
||||
|
||||
/**
|
||||
* Starts our main loop, which posts messages to the parent frame as needed
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
var startTimeout = function () {
|
||||
|
||||
var currentSize = 0;
|
||||
var repeats = 0;
|
||||
|
||||
ips.utils.log("Starting timeout...");
|
||||
|
||||
// Main loop
|
||||
_timer = setInterval( function () {
|
||||
// What we want to do here is make the loading process more pleasant and less jumpy.
|
||||
// To do that, we'll make the embed invisible until we've fetched the same height 6 times
|
||||
// in a row (approx 1 second). If that happens we'll assume it has finished loading, and then
|
||||
// we'll fade it in and start sending the recorded height to the parent for resizing.
|
||||
|
||||
var height = ips.utils.getObjHeight( _div );
|
||||
|
||||
// If we HAVEN'T started posting our size
|
||||
if( !_posting ){
|
||||
if( height == currentSize ){
|
||||
repeats++;
|
||||
} else {
|
||||
// The height has changed, so reset our repeat counter
|
||||
repeats = 0;
|
||||
}
|
||||
|
||||
if( repeats == 6 ){
|
||||
_posting = true;
|
||||
_showEmbed();
|
||||
}
|
||||
}
|
||||
|
||||
currentSize = height;
|
||||
|
||||
if( _posting ){
|
||||
if( _embedMaxWidth !== null ){
|
||||
_postMessage('dims', {
|
||||
height: height,
|
||||
width: _embedMaxWidth
|
||||
});
|
||||
} else {
|
||||
_postMessage('height', {
|
||||
height: height
|
||||
});
|
||||
}
|
||||
}
|
||||
}, _timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* Posts a message to the iframe
|
||||
*
|
||||
* @param {number} [pageNo] Page number to load
|
||||
* @returns {void}
|
||||
*/
|
||||
var _postMessage = function (method, obj) {
|
||||
// Send to parent window
|
||||
window.top.postMessage( JSON.stringify( ips.utils.extendObj( obj || {}, {
|
||||
method: method,
|
||||
embedId: _embedId
|
||||
} ) ), _origin );
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles link clicks, to check for dialogs. If one is found, the options are passed
|
||||
* up to the parent to display.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
var clickLink = function (e) {
|
||||
var link = e.target.closest('a');
|
||||
|
||||
if( link !== null ){
|
||||
if( link.hasAttributes() ){
|
||||
var output = {};
|
||||
var attrs = link.attributes;
|
||||
|
||||
for( var i = attrs.length - 1; i > 0; i-- ){
|
||||
if( attrs[i].name !== 'class' && attrs[i].name !== 'title' ){
|
||||
output[ attrs[i].name ] = attrs[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
if( output['data-ipsdialog'] !== undefined ){
|
||||
e.preventDefault();
|
||||
|
||||
_postMessage('dialog', {
|
||||
url: link.href,
|
||||
options: output
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Events sent to the iframe
|
||||
*/
|
||||
var messageEvents = {
|
||||
/**
|
||||
* The parent is ready for messages
|
||||
*
|
||||
* @param {object} data Data from the iframe
|
||||
* @returns {void}
|
||||
*/
|
||||
ready: function (data) {
|
||||
_embedId = data.embedId;
|
||||
_postMessage('ok');
|
||||
},
|
||||
|
||||
stop: function (data) {
|
||||
clearInterval( _timer );
|
||||
ips.eventHandler.off( window, 'message', windowMessage );
|
||||
},
|
||||
|
||||
responsiveState: function (data) {
|
||||
if( data.currentIs === 'phone' ){
|
||||
document.body.className += ' ipsRichEmbed_phone';
|
||||
} else {
|
||||
document.body.className = document.body.className.replace( ' ipsRichEmbed_phone', '' );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*******************************************************************************************/
|
||||
/* Boring stuff below */
|
||||
// Main message handler
|
||||
ips.eventHandler.on( window, 'message', windowMessage );
|
||||
|
||||
function windowMessage (e) {
|
||||
if( e.origin !== _origin ){
|
||||
ips.utils.log( e.origin + 'does not equal' + _origin );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var pmData = JSON.parse( e.data );
|
||||
var method = pmData.method;
|
||||
} catch (err) {
|
||||
ips.utils.error("iframe: invalid data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( method && typeof messageEvents[ method ] != 'undefined' ){
|
||||
ips.utils.log("Called " + method );
|
||||
messageEvents[ method ].call( this, pmData );
|
||||
} else {
|
||||
ips.utils.log("Method " + method + " doesn't exist");
|
||||
}
|
||||
};
|
||||
|
||||
ips.utils.contentLoaded( window, function () {
|
||||
init();
|
||||
});
|
||||
})();
|
||||
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Return JS files
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 1 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
require_once '../../../../init.php';
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Return JS language strings
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
require_once '../../../../init.php';
|
||||
|
||||
Reference in new issue
Block a user