%PDF- %PDF-
| Direktori : /home/riacommer/domains/gasworld.com.my/private_html/admin/vendor/MetroJS/src/js/ |
| Current File : /home/riacommer/domains/gasworld.com.my/private_html/admin/vendor/MetroJS/src/js/liveTile.js |
var MAX_LOOP_COUNT = 99000;
// .liveTile
$.fn.liveTile = function (method) {
if (pubMethods[method]) {
var args = [];
for (var i = 1; i <= arguments.length; i++) {
args[i - 1] = arguments[i];
}
return pubMethods[method].apply(this, args);
} else if (typeof method === 'object' || !method) {
return pubMethods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.liveTile');
return null;
}
};
$.fn.liveTile.contentModules = {
modules: [],
/* the default module layout
[
defaultModules.imageSwap,
defaultModules.htmlSwap
],*/
addContentModule: function (moduleName, module) {
if (!(this.modules instanceof Array))
this.modules = [];
this.modules.push(module);
},
hasContentModule: function (moduleName) {
if (typeof (moduleName) === "undefined" || !(this.modules instanceof Array))
return -1;
for (var i = 0; i < this.modules.length; i++) {
if (typeof (this.modules[i].moduleName) != "undefined" && this.modules[i].moduleName == moduleName)
return i;
}
return -1;
}
};
// default option values for .liveTile
$.fn.liveTile.defaults = {
mode: 'slide', // 'fade', 'slide', 'flip', 'flip-list', carousel
speed: 500, // how fast should animations be performed, in milliseconds
initDelay: -1, // how long to wait before the initial animation
delay: 5000, // how long to wait between animations
stops: "100%", // how much of the back tile should 'slide' reveal before starting a delay
stack: false, // should tiles in slide mode appear stacked (e.g Me tile)
direction: 'vertical', // which direction should animations be performed(horizontal | vertical)
animationDirection: 'forward', // the direction that carousel mode uses to determine which way to slide in tiles
tileSelector: '>div,>li,>p,>img,>a', // the selector used by carousel mode and flip-list to choose tile containers
tileFaceSelector: '>div,>li,>p,>img,>a',// the selector used to choose the front and back containers
ignoreDataAttributes: false, // should data attributes be ignored
click: null, // function ($tile, tdata) { return true; }
link: '', // a url to go to when clicked
newWindow: false, // should the link be opened in a new window
bounce: false, // should the tile shrink when tapped
bounceDirections: 'all', // which direction the tile will tile 'all', 'edges, 'corners'
bounceFollowsMove: true, // should a tile in bounce state tilt in the direction of the mouse as it moves
pauseOnHover: false, // should tile animations be paused on hover in and restarted on hover out
pauseOnHoverEvent: 'both', // pause is called on mouseover, mouseout, or both
playOnHover: false, // should "play" be called on hover
playOnHoverEvent: 'both', // play is called on mouseover, mouseout, or both
onHoverDelay: 0, // the amount of time to wait before the onHover event is fired
repeatCount: -1, // number of times to repeat the animation
appendBack: true, // appends the .last tile if one doesnt exist (slide and flip only)
alwaysTrigger: false, // should every item in a flip list trigger every time a delay passes
flipListOnHover: false, // should items in flip-list flip and stop when hovered
flipListOnHoverEvent: 'mouseout', // which event should be used to trigger the flip-list faces
noHAflipOpacity: '1', // the opacity level set for the backside of the flip animation on unaccelerated browsers
haTransFunc: 'ease', // the tranisiton-timing function to use in hardware accelerated mode
noHaTransFunc: 'linear', // the tranisiton-timing function to use in non hardware accelerated mode
currentIndex: 0, // what is the current stop index for slide mode or slide index for carousel mode
startNow: true, // should the tile immediately start or wait util play or restart has been called
useModernizr: (typeof (window.Modernizr) !== "undefined"), // checks to see if modernizer is already in use
useHardwareAccel: true, // should css animations, transitions and transforms be used when available
useTranslate: true,
faces: {
$front: null, // the jQuery element to use as the front face of the tile; this will bypass tileCssSelector
$back: null // the jQuery element to use as the back face of the tile; this will bypass tileCssSelector
},
animationStarting: function (tileData, $front, $back) {
// returning false will cancel the animation
},
animationComplete: function (tileData, $front, $back) {
},
triggerDelay: function (idx) { // used by flip-list to decide how random the tile flipping should be
return Math.random() * 3000;
},
swap: '', // which swap modules are active for this tile (image, html)
swapFront: '-', // override the available swap modules for the front face
swapBack: '-', // override the available swap modules for the back face
contentModules: []
};
// public methods that can be called via .liveTile(method name)
var pubMethods = {
init: function (options) {
// Setup the public options for the livetile
var settings = $.extend({}, $.fn.liveTile.defaults, options);
// checks for browser feature support to enable hardware acceleration
metrojs.checkCapabilities(settings);
helperMethods.getBrowserPrefix();
// setup the default content modules
if ($.fn.liveTile.contentModules.hasContentModule("image") == -1)
$.fn.liveTile.contentModules.addContentModule("image", defaultModules.imageSwap);
if ($.fn.liveTile.contentModules.hasContentModule("html") == -1)
$.fn.liveTile.contentModules.addContentModule("html", defaultModules.htmlSwap);
// this is where the magic happens
return $(this).each(function (tileIndex, ele) {
var $this = $(ele),
data = privMethods.initTileData($this, settings);
// append back tiles and add appropriate classes to prepare tiles
data.faces = privMethods.prepTile($this, data);
// action methods
data.fade = function (count) { privMethods.fade($this, count); };
data.slide = function (count) { privMethods.slide($this, count); };
data.carousel = function (count) { privMethods.carousel($this, count); };
data.flip = function (count) { privMethods.flip($this, count); };
data.flipList = function (count) { privMethods.flipList($this, count); };
var actions = {
fade: data.fade,
slide: data.slide,
carousel: data.carousel,
flip: data.flip,
'flip-list': data.flipList
};
data.doAction = function (count) {
// get the action for the current mode
var action = actions[data.mode];
if (typeof (action) === "function") {
action(count);
data.hasRun = true;
}
// prevent pauseOnHover from resuming a tile that has finished
if (count == data.timer.repeatCount)
data.runEvents = false;
};
// create a new tile timer
data.timer = new $.fn.metrojs.TileTimer(data.delay, data.doAction, data.repeatCount);
// apply the data
$this.data("LiveTile", data);
// handle events
// only bind pause / play on hover if we are not using a fliplist or flipListOnHover isn't set set
if (data.mode !== "flip-list" || data.flipListOnHover == false) {
if (data.pauseOnHover) {
privMethods.bindPauseOnHover($this);
} else if (data.playOnHover) {
privMethods.bindPlayOnHover($this, data);
}
}
// add a click / link to the tile
if (data.link.length > 0 || typeof (data.click) === "function") {
$this.css({ cursor: 'pointer' }).bind("click.liveTile", function (e) {
var proceed = true;
if (typeof (data.click) === "function") {
proceed = data.click($this, data) || false;
}
if (proceed && data.link.length > 0) {
e.preventDefault();
if (data.newWindow)
window.open(data.link);
else
window.location = data.link;
}
});
}
// add bounce if set
privMethods.bindBounce($this, data);
// start timer
if (data.startNow && data.mode != "none") {
data.runEvents = true;
data.timer.start(data.initDelay);
}
});
},
// goto is a future reserved word
'goto': function (options) {
var opts, t = typeof (options);
if (t === "undefined") {
opts = {
index: -99, // same as next
delay: 0,
autoAniDirection: false
};
}
if (t === "number" || !isNaN(options)) {
opts = {
index: parseInt(options, 10),
delay: 0
};
} else if (t === "string") {
if (options == "next") {
opts = {
index: -99,
delay: 0
};
} else if (options.indexOf("prev") === 0) {
opts = {
index: -100,
delay: 0
};
} else {
$.error(options + " is not a recognized action for .liveTile(\"goto\")");
return $(this);
}
} else if (t === "object") {
if (typeof (options.delay) === "undefined") {
options.delay = 0;
}
var ti = typeof (options.index);
if (ti === "undefined") {
options.index = 0;
} else if (ti === "string") {
if (options.index === "next")
options.index = -99;
else if (options.index.indexOf("prev") === 0)
options.index = -100;
}
opts = options;
}
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile"),
aniData = $tile.data("metrojs.tile"),
goTo = opts.index;
if (aniData.animating === true)
return $(this);
if (data.mode === "carousel") {
// get the index based off of the active carousel slide
var $cur = data.faces.$listTiles.filter(".active");
var curIdx = data.faces.$listTiles.index($cur);
// carousel will look for these values as triggers
if (goTo === -100) { // prev
// autoAniDirection determines if a forward or backward animation should be used based on the goTo index
if (typeof (opts.autoAniDirection) === "undefined" || opts.autoAniDirection == true)
data.tempValues.animationDirection = typeof (opts.animationDirection) === "undefined" ? "backward" : opts.animationDirection;
goTo = curIdx === 0 ? data.faces.$listTiles.length - 1 : curIdx - 1;
} else if (goTo === -99) { // next
if (typeof (opts.autoAniDirection) === "undefined" || opts.autoAniDirection == true)
data.tempValues.animationDirection = typeof (opts.animationDirection) === "undefined" ? "forward" : opts.animationDirection;
goTo = curIdx + 1;
}
if (curIdx == goTo) {
return;
}
if (typeof (opts.direction) !== "undefined") {
data.tempValues.direction = opts.direction;
}
if (typeof (opts.animationDirection) !== "undefined") {
data.tempValues.animationDirection = opts.animationDirection;
}
// the index is offset by 1 and incremented on animate
if (goTo == 0)
data.currentIndex = data.faces.$listTiles.length;
else
data.currentIndex = goTo - 1;
} else // slide mode will use the index directly
data.currentIndex = goTo;
// start the timer
data.runEvents = true;
data.timer.start(opts.delay >= 0 ? opts.delay : data.delay);
});
},
play: function (options) {
var opts, t = typeof (options);
if (t === "undefined") {
opts = {
delay: -1
};
} else if (t === "number") {
opts = {
delay: options
};
} else if (t === "object") {
if (typeof (options.delay) === "undefined") {
options.delay = -1;
}
opts = options;
}
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile");
data.runEvents = true;
if (opts.delay < 0 && !data.hasRun)
opts.delay = data.initDelay;
data.timer.start(opts.delay >= 0 ? opts.delay : data.delay);
});
},
animate: function () { // this is really only useful for certain edge cases in slide mode, use 'play' to toggle animations
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile");
data.doAction();
});
},
stop: function () {
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile");
data.hasRun = false;
data.runEvents = false;
data.timer.stop();
window.clearTimeout(data.eventTimeout);
window.clearTimeout(data.flCompleteTimeout);
window.clearTimeout(data.completeTimeout);
if (data.mode === "flip-list") {
data.faces.$listTiles.each(function (idx, li) {
var ldata = $(li).data("metrojs.tile");
window.clearTimeout(ldata.eventTimeout);
window.clearTimeout(ldata.flCompleteTimeout);
window.clearTimeout(ldata.completeTimeout);
});
}
});
},
pause: function () {
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile");
data.timer.pause();
data.runEvents = false;
window.clearTimeout(data.eventTimeout);
window.clearTimeout(data.flCompleteTimeout);
window.clearTimeout(data.completeTimeout);
if (data.mode === "flip-list") {
data.faces.$listTiles.each(function (idx, li) {
var ldata = $(li).data("metrojs.tile");
window.clearTimeout(ldata.eventTimeout);
window.clearTimeout(ldata.flCompleteTimeout);
window.clearTimeout(ldata.completeTimeout);
});
}
});
},
restart: function (options) {
var opts, t = typeof (options);
if (t === "undefined") {
opts = {
delay: -1
};
} else if (t === "number") {
opts = {
delay: options
};
} else if (t === "object") {
if (typeof (options.delay) === "undefined") {
options.delay = -1;
}
opts = options;
}
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele),
data = $tile.data("LiveTile");
if (opts.delay < 0 && !data.hasRun)
opts.delay = data.initDelay;
data.hasRun = false;
data.runEvents = true;
data.timer.restart(opts.delay >= 0 ? opts.delay : data.delay);
});
},
rebind: function (options) {
return $(this).each(function (tileIndex, ele) {
if (typeof (options) !== "undefined") {
if (typeof (options.timer) !== "undefined" && options.timer != null) {
options.timer.stop();
}
options.hasRun = false;
pubMethods["init"].apply(ele, options);
} else {
pubMethods["init"].apply(ele, {});
}
});
},
destroy: function (options) {
var t = typeof (options), opts;
if (t === "undefined") {
opts = {
removeCss: false
};
} else if (t === "boolean") {
opts = {
removeCss: options
};
} else if (t === "object") {
if (typeof (options.removeCss) === "undefined") {
options.removeCss = false;
}
opts = options;
}
return $(this).each(function (tileIndex, ele) {
var $tile = $(ele);
var data = $tile.data("LiveTile");
if (typeof (data) === "undefined")
return;
$tile.unbind(".liveTile");
var resetCss = helperMethods.appendStyleProperties({ margin: '', cursor: '' }, ['transform', 'transition'], ['', '']);
data.timer.stop();
window.clearTimeout(data.eventTimeout);
window.clearTimeout(data.flCompleteTimeout);
window.clearTimeout(data.completeTimeout);
if (data.faces.$listTiles != null) {
data.faces.$listTiles.each(function (idx, li) {
var $li = $(li);
if (data.mode === "flip-list") {
var ldata = $li.data("metrojs.tile");
window.clearTimeout(ldata.eventTimeout);
window.clearTimeout(ldata.flCompleteTimeout);
window.clearTimeout(ldata.completeTimeout);
} else if (data.mode === "carousel") {
var sdata = data.listData[idx];
if (sdata.bounce) {
privMethods.unbindMsBounce($li, sdata);
}
}
if (opts.removeCss) {
$li.removeClass("ha");
$li.find(data.tileFaceSelector)
.unbind(".liveTile")
.removeClass("bounce flip-front flip-back ha slide slide-front slide-back")
.css(resetCss);
} else {
$li.find(data.tileFaceSelector).unbind(".liveTile");
}
$li.removeData("metrojs.tile");
}).unbind(".liveTile");
}
if (data.faces.$front != null && opts.removeCss) {
data.faces.$front.removeClass("flip-front flip-back ha slide slide-front slide-back")
.css(resetCss);
}
if (data.faces.$back != null && opts.removeCss) {
data.faces.$back.removeClass("flip-front flip-back ha slide slide-front slide-back")
.css(resetCss);
}
// remove the bounce and hover methods
// todo: combine all mouse/touch events (down, move, up)
if (data.bounce) {
privMethods.unbindMsBounce($tile, data);
}
if (data.playOnHover) {
privMethods.unbindMsPlayOnHover($tile, data);
}
if (data.pauseOnhover) {
privMethods.unbindMsPauseOnHover($tile, data);
}
$tile.removeClass("ha");
$tile.removeData("LiveTile");
$tile.removeData("metrojs.tile");
data = null;
});
}
};
// private methods that are called by .liveTile
var privMethods = {
//getDataOrDefault for older versions of jQuery that dont look for 'data-' properties
dataAtr: function ($ele, name, def) {
return typeof ($ele.attr('data-' + name)) !== "undefined" ? $ele.attr('data-' + name) : def;
},
dataMethod: function ($ele, name, def) {
return typeof ($ele.data(name)) !== "undefined" ? $ele.data(name) : def;
},
getDataOrDefault: null,
initTileData: function ($tile, stgs) {
var useData = stgs.ignoreDataAttributes == false,
tdata = null;
if (this.getDataOrDefault == null)
this.getDataOrDefault = metrojs.capabilities.isOldJQuery ? this.dataAtr : this.dataMethod;
if (useData) {
tdata = { //an object to store settings for later access
speed: this.getDataOrDefault($tile, "speed", stgs.speed),
delay: this.getDataOrDefault($tile, "delay", stgs.delay),
stops: this.getDataOrDefault($tile, "stops", stgs.stops),
stack: this.getDataOrDefault($tile, "stack", stgs.stack),
mode: this.getDataOrDefault($tile, "mode", stgs.mode),
direction: this.getDataOrDefault($tile, "direction", stgs.direction),
useHardwareAccel: this.getDataOrDefault($tile, "ha", stgs.useHardwareAccel),
repeatCount: this.getDataOrDefault($tile, "repeat", stgs.repeatCount),
swap: this.getDataOrDefault($tile, "swap", stgs.swap),
appendBack: this.getDataOrDefault($tile, "appendback", stgs.appendBack),
currentIndex: this.getDataOrDefault($tile, "start-index", stgs.currentIndex),
animationDirection: this.getDataOrDefault($tile, "ani-direction", stgs.animationDirection),
startNow: this.getDataOrDefault($tile, "start-now", stgs.startNow),
tileSelector: this.getDataOrDefault($tile, "tile-selector", stgs.tileSelector),
tileFaceSelector: this.getDataOrDefault($tile, "face-selector", stgs.tileFaceSelector),
bounce: this.getDataOrDefault($tile, "bounce", stgs.bounce),
bounceDirections: this.getDataOrDefault($tile, "bounce-dir", stgs.bounceDirections),
bounceFollowsMove: this.getDataOrDefault($tile, "bounce-follows", stgs.bounceFollowsMove),
click: this.getDataOrDefault($tile, "click", stgs.click),
link: this.getDataOrDefault($tile, "link", stgs.link),
newWindow: this.getDataOrDefault($tile, "new-window", stgs.newWindow),
alwaysTrigger: this.getDataOrDefault($tile, "always-trigger", stgs.alwaysTrigger),
flipListOnHover: this.getDataOrDefault($tile, "flip-onhover", stgs.flipListOnHover),
pauseOnHover: this.getDataOrDefault($tile, "pause-onhover", stgs.pauseOnHover),
playOnHover: this.getDataOrDefault($tile, "play-onhover", stgs.playOnHover),
onHoverDelay: this.getDataOrDefault($tile, "hover-delay", stgs.onHoverDelay),
noHAflipOpacity: this.getDataOrDefault($tile, "flip-opacity", stgs.noHAflipOpacity),
useTranslate: this.getDataOrDefault($tile, "use-translate", stgs.useTranslate),
runEvents: false,
isReversed: false,
loopCount: 0,
contentModules: [],
listData: [],
height: $tile.height(),
width: $tile.width(),
tempValues: {}
};
} else {
tdata = $.extend(true,{
runEvents: false,
isReversed: false,
loopCount: 0,
contentModules: [],
listData: [],
height: $tile.height(),
width: $tile.width(),
tempValues: {}
}, stgs);
}
tdata.useTranslate = tdata.useTranslate && tdata.useHardwareAccel && metrojs.capabilities.canTransform && metrojs.capabilities.canTransition;
// set the margin to half of the height or width based on the direction
tdata.margin = (tdata.direction === "vertical") ? tdata.height / 2 : tdata.width / 2;
// convert stops if needed
tdata.stops = (typeof (stgs.stops) === "object" && (stgs.stops instanceof Array)) ? stgs.stops : ("" + tdata.stops).split(",");
// add a return stop
if (tdata.stops.length === 1)
tdata.stops.push("0px");
// add content modules, start with global swaps
var swaps = tdata.swap.replace(' ', '').split(",");
// get the front and back swap data
var sf = useData ? this.getDataOrDefault($tile, "swap-front", stgs.swapFront) : stgs.swapFront;
var sb = useData ? this.getDataOrDefault($tile, "swap-back", stgs.swapBack) : stgs.swapBack;
// set the data to the global value if its still the default
tdata.swapFront = sf === '-' ? swaps : sf.replace(' ', '').split(",");
tdata.swapBack = sb === '-' ? swaps : sb.replace(' ', '').split(",");
// make sure the swaps includes all front and back swaps
var i;
for (i = 0; i < tdata.swapFront.length; i++) {
if (tdata.swapFront[i].length > 0 && $.inArray(tdata.swapFront[i], swaps) === -1)
swaps.push(tdata.swapFront[i]);
}
for (i = 0; i < tdata.swapBack.length; i++) {
if (tdata.swapBack[i].length > 0 && $.inArray(tdata.swapBack[i], swaps) === -1)
swaps.push(tdata.swapBack[i]);
}
tdata.swap = swaps;
// add all required content modules for the swaps
for (i = 0; i < swaps.length; i++) {
if (swaps[i].length > 0) {
var moduleIdx = $.fn.liveTile.contentModules.hasContentModule(swaps[i]);
if (moduleIdx > -1) {
tdata.contentModules.push($.fn.liveTile.contentModules.modules[moduleIdx]);
}
}
}
// set the initDelay value to the delay if it's not set
tdata.initDelay = useData ? this.getDataOrDefault($tile, "initdelay", stgs.initDelay) : stgs.initDelay;
// if the delay is -1 call the triggerDelay function to get a value
if (tdata.delay < -1)
tdata.delay = stgs.triggerDelay(1);
else if (tdata.delay < 0)
tdata.delay = 3500 + (Math.random() * 4501);
// match the delay value if less than 0
if (tdata.initDelay < 0)
tdata.initDelay = tdata.delay;
// merge the objects
var mergedData = {};
for (i = 0; i < tdata.contentModules.length; i++)
$.extend(mergedData, tdata.contentModules[i].data);
$.extend(mergedData, stgs, tdata);
// add flip-list / carousel data
var $tiles;
if (mergedData.mode === "flip-list") {
$tiles = $tile.find(mergedData.tileSelector).not(".tile-title");
$tiles.each(function (idx, ele) {
var $li = $(ele);
var ldata = {
direction: useData ? privMethods.getDataOrDefault($li, "direction", mergedData.direction) : mergedData.direction,
newWindow: useData ? privMethods.getDataOrDefault($li, "new-window", false) : false,
link: useData ? privMethods.getDataOrDefault($li, "link", "") : "",
faces: { $front: null, $back: null },
height: $li.height(),
width: $li.width(),
isReversed: false
};
ldata.margin = ldata.direction === "vertical" ? ldata.height / 2 : ldata.width / 2;
mergedData.listData.push(ldata);
});
} else if (mergedData.mode === "carousel") {
mergedData.stack = true;
$tiles = $tile.find(mergedData.tileSelector).not(".tile-title");
$tiles.each(function (idx, ele) {
var $slide = $(ele);
var sdata = {
bounce: useData ? privMethods.getDataOrDefault($slide, "bounce", false) : false,
bounceDirections: useData ? privMethods.getDataOrDefault($slide, "bounce-dir", "all") : "all",
link: useData ? privMethods.getDataOrDefault($slide, "link", "") : "",
newWindow: useData ? privMethods.getDataOrDefault($slide, "new-window", false) : false,
animationDirection: useData ? privMethods.getDataOrDefault($slide, "ani-direction", "") : "",
direction: useData ? privMethods.getDataOrDefault($slide, "direction", "") : ""
};
mergedData.listData.push(sdata);
});
}
// get any additional options from the modules
for (i = 0; i < tdata.contentModules.length; i++){
if (typeof (mergedData.contentModules[i].initData) === "function")
mergedData.contentModules[i].initData(mergedData, $tile);
}
tdata = null;
return mergedData;
},
prepTile: function ($tile, tdata) {
//add the mode to the tile if it's not already there.
$tile.addClass(tdata.mode);
var ret = {
$tileFaces: null, // all possible tile faces in a liveTile in a non list mode
$listTiles: null, // all possible tiles in a liveTile in a list mode
$front: null, // the front face of a tile in a non list mode
$back: null // the back face of a tile in a non list mode
};
var rotateDir, frontCss, backCss, tileCss;
// prepare the tile based on the current mode
switch (tdata.mode) {
case "fade":
// front and back tile faces
ret.$tileFaces = $tile.find(tdata.tileFaceSelector).not(".tile-title");
ret.$front = (tdata.faces.$front != null && tdata.faces.$front.length > 0) ?
tdata.faces.$front.addClass('fade-front') :
ret.$tileFaces.filter(":first").addClass('fade-front');
// get back face from settings, via selector, or append it if necessary
if (tdata.faces.$back != null && tdata.faces.$back.length > 0) // use $back option
ret.$back = tdata.faces.$back.addClass('fade-back');
else if (ret.$tileFaces.length > 1) // get the last tile face
ret.$back = ret.$tileFaces.filter(":last").addClass('fade-back');
else if (tdata.appendBack) // append the back tile
ret.$back = $('<div class="fade-back"></div>').appendTo($tile);
else // just keep an empty placeholder
ret.$back = $('<div></div>');
break;
case "slide":
// front and back tile faces
ret.$tileFaces = $tile.find(tdata.tileFaceSelector).not(".tile-title");
// get front face from settings or via selector
ret.$front = (tdata.faces.$front != null && tdata.faces.$front.length > 0) ?
tdata.faces.$front.addClass('slide-front') :
ret.$tileFaces.filter(":first").addClass('slide-front'); // using :first for pre jQuery 1.4
// get back face from settings, via selector, or append it if necessary
if (tdata.faces.$back != null && tdata.faces.$back.length > 0) // use $back option
ret.$back = tdata.faces.$back.addClass('slide-back');
else if (ret.$tileFaces.length > 1) // get the last tile face
ret.$back = ret.$tileFaces.filter(":last").addClass('slide-back');
else if (tdata.appendBack) // append the back tile
ret.$back = $('<div class="slide-back"></div>').appendTo($tile);
else // just keep an empty placeholder
ret.$back = $('<div></div>');
// stack mode
if (tdata.stack == true) {
var prop,
translate;
if (tdata.direction === "vertical") {
prop = "top",
translate = 'translate(0%, -100%) translateZ(0)';
} else {
prop = "left",
translate = 'translate(-100%, 0%) translateZ(0)';
}
backCss = {};
if (tdata.useTranslate)
helperMethods.appendStyleProperties(backCss, ['transform'], [translate]);
else
backCss[prop] = "-100%";
ret.$back.css(backCss);
}
$tile.data("metrojs.tile", { animating: false });
if (metrojs.capabilities.canTransition && tdata.useHardwareAccel) { // hardware accelerated :)
$tile.addClass("ha");
ret.$front.addClass("ha");
ret.$back.addClass("ha");
}
break;
case "carousel":
ret.$listTiles = $tile.find(tdata.tileSelector).not(".tile-title");
var numberOfSlides = ret.$listTiles.length;
$tile.data("metrojs.tile", { animating: false });
tdata.currentIndex = Math.min(tdata.currentIndex, numberOfSlides - 1);
ret.$listTiles.each(function (idx, ele) {
var $slide = $(ele).addClass("slide");
var sdata = tdata.listData[idx],
aniDir = typeof (sdata.animationDirection) === "string" && sdata.animationDirection.length > 0 ? sdata.animationDirection : tdata.animationDirection,
dir = typeof (sdata.direction) === "string" && sdata.direction.length > 0 ? sdata.direction : tdata.direction;
if (idx == tdata.currentIndex) {
$slide.addClass("active");
} else if (aniDir === "forward") {
if (dir === "vertical") {
tileCss = tdata.useTranslate ? helperMethods.appendStyleProperties({}, ['transform'], ['translate(0%, 100%) translateZ(0)']) :
{ left: '0%', top: '100%' };
$slide.css(tileCss);
} else {
tileCss = tdata.useTranslate ? helperMethods.appendStyleProperties({}, ['transform'], ['translate(100%, 0%) translateZ(0)']) :
{ left: '100%', top: '0%' };
$slide.css(tileCss);
}
} else if (aniDir === "backward") {
if (dir === "vertical") {
tileCss = tdata.useTranslate ? helperMethods.appendStyleProperties({}, ['transform'], ['translate(0%, -100%) translateZ(0)']) :
{ left: '0%', top: '-100%' };
$slide.css(tileCss);
} else {
tileCss = tdata.useTranslate ? helperMethods.appendStyleProperties({}, ['transform'], ['translate(-100%, 0%) translateZ(0)']) :
{ left: '-100%', top: '0%' };
$slide.css(tileCss);
}
}
// link and bounce can be bound per slide
// add the click handler and link property
privMethods.bindLink($slide, sdata);
// add the bounce effect
if (tdata.useHardwareAccel && metrojs.capabilities.canTransition)
privMethods.bindBounce($slide, sdata);
$slide = null;
sdata = null;
});
// hardware accelerated :)
if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) {
$tile.addClass("ha");
ret.$listTiles.addClass("ha");
}
break;
case "flip-list":
// the tile containers inside the list
ret.$listTiles = $tile.find(tdata.tileSelector).not(".tile-title");
ret.$listTiles.each(function (idx, ele) {
var $li = $(ele).addClass("tile-" + (idx + 1));
// add the flip class to the front face
var $lFront = $li.find(tdata.tileFaceSelector).filter(":first").addClass("flip-front").css({ margin: "0px" });
// append a back tile face if one isnt present
if ($li.find(tdata.tileFaceSelector).length === 1 && tdata.appendBack == true)
$li.append("<div></div>");
// add the flip class to the back face
var $lBack = $li.find(tdata.tileFaceSelector).filter(":last").addClass("flip-back").css({ margin: "0px" });
// update the tdata object with the faces
tdata.listData[idx].faces.$front = $lFront;
tdata.listData[idx].faces.$back = $lBack;
// set data for overrides and easy access
$li.data("metrojs.tile", {
animating: false,
count: 1,
completeTimeout: null,
flCompleteTimeout: null,
index: idx
});
var ldata = $li.data("metrojs.tile");
// add the hardware accelerated classes
if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) { // hardware accelerated :)
$li.addClass("ha");
$lFront.addClass("ha");
$lBack.addClass("ha");
rotateDir = tdata.listData[idx].direction === "vertical" ? "rotateX(180deg)" : "rotateY(180deg)";
backCss = helperMethods.appendStyleProperties({}, ["transform"], [rotateDir]);
$lBack.css(backCss);
} else { // not hardware accelerated :(
// the front tile face will take up the entire tile
frontCss = (tdata.listData[idx].direction === "vertical") ?
{ height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
{ height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
// the back tile face is hidden by default and expanded halfway through a flip
backCss = (tdata.listData[idx].direction === "vertical") ?
{ height: '0px', width: '100%', marginTop: tdata.listData[idx].margin + 'px', opacity: tdata.noHAflipOpacity } :
{ height: '100%', width: '0px', marginLeft: tdata.listData[idx].margin + 'px', opacity: tdata.noHAflipOpacity };
$lFront.css(frontCss);
$lBack.css(backCss);
}
var flipEnded = function () {
ldata.count++;
if (ldata.count >= MAX_LOOP_COUNT)
ldata.count = 1;
};
if (tdata.flipListOnHover) {
var event = tdata.flipListOnHoverEvent + ".liveTile";
$lFront.bind(event, function () {
privMethods.flip($li, ldata.count, tdata, flipEnded);
});
$lBack.bind(event, function () {
privMethods.flip($li, ldata.count, tdata, flipEnded);
});
}
if (tdata.listData[idx].link.length > 0) {
$li.css({ cursor: 'pointer' }).bind("click.liveTile", function () {
if (tdata.listData[idx].newWindow)
window.open(tdata.listData[idx].link);
else
window.location = tdata.listData[idx].link;
});
}
});
break;
case "flip":
// front and back tile faces
ret.$tileFaces = $tile.find(tdata.tileFaceSelector).not(".tile-title");
// get front face from settings or via selector
ret.$front = (tdata.faces.$front != null && tdata.faces.$front.length > 0) ?
tdata.faces.$front.addClass('flip-front') :
ret.$tileFaces.filter(":first").addClass('flip-front');
// get back face from settings, via selector, or append it if necessary
if (tdata.faces.$back != null && tdata.faces.$back.length > 0) {
// use $back option
ret.$back = tdata.faces.$back.addClass('flip-back');
} else if (ret.$tileFaces.length > 1) {
// get the last tile face
ret.$back = ret.$tileFaces.filter(":last").addClass('flip-back');
} else if (tdata.appendBack) {
// append the back tile
ret.$back = $('<div class="flip-back"></div>').appendTo($tile);
} else {
// just keep an empty placeholder
ret.$back = $('<div></div>');
}
$tile.data("metrojs.tile", { animating: false });
if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) {
// hardware accelerated :)
$tile.addClass("ha");
ret.$front.addClass("ha");
ret.$back.addClass("ha");
rotateDir = tdata.direction === "vertical" ? "rotateX(180deg)" : "rotateY(180deg)";
backCss = helperMethods.appendStyleProperties({}, ["transform"], [rotateDir]);
ret.$back.css(backCss);
} else {
// not hardware accelerated :(
// the front tile face will take up the entire tile
frontCss = (tdata.direction === "vertical") ?
{ height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
{ height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
// the back tile face is hidden by default and expanded halfway through a flip
backCss = (tdata.direction === "vertical") ?
{ height: '0%', width: '100%', marginTop: tdata.margin + 'px', opacity: '0' } :
{ height: '100%', width: '0%', marginLeft: tdata.margin + 'px', opacity: '0' };
ret.$front.css(frontCss);
ret.$back.css(backCss);
}
break;
}
return ret;
},
bindPauseOnHover: function ($tile) {
// stop the tile when hovered and resume after a delay
(function () {
var data = $tile.data("LiveTile"),
isOver = false,
isPending = false,
pauseIn = (data.pauseOnHoverEvent == "both" || data.pauseOnHoverEvent == "mouseover" || data.pauseOnHoverEvent == "mouseenter"),
pauseOut = (data.pauseOnHoverEvent == "both" || data.pauseOnHoverEvent == "mouseout" || data.pauseOnHoverEvent == "mouseleave");
data.pOnHoverMethods = {
pause: function () {
data.timer.pause();
if (data.mode === "flip-list") {
data.faces.$listTiles.each(function (idx, li) {
window.clearTimeout($(li).data("metrojs.tile").completeTimeout);
});
}
},
over: function (e) {
if (isOver || isPending)
return;
if (data.runEvents) {
isPending = true;
data.eventTimeout = window.setTimeout(function () {
isPending = false;
if (pauseOut)
isOver = true;
data.pOnHoverMethods.pause();
}, data.onHoverDelay);
}
},
out: function (e) {
if (isPending) {
window.clearTimeout(data.eventTimeout);
isPending = false;
return;
}
if (pauseIn) {
if (!isOver && !isPending)
return;
if (data.runEvents) {
// todo: use a custom value if provided
data.timer.start(data.hasRun ? data.delay : data.initDelay);
}
} else {
data.pOnHoverMethods.pause();
}
isOver = false;
}
};
if (!metrojs.capabilities.canTouch) {
if (pauseIn)
$tile.bind("mouseover.liveTile", data.pOnHoverMethods.over);
if (pauseOut)
$tile.bind("mouseout.liveTile", data.pOnHoverMethods.out);
} else {
if (window.navigator.msPointerEnabled) { // pointer
if (pauseIn)
$tile[0].addEventListener('MSPointerOver', data.pOnHoverMethods.over, false);
if (pauseOut)
$tile[0].addEventListener('MSPointerOut', data.pOnHoverMethods.out, false);
} else { // touch events
if (pauseIn)
$tile.bind("touchstart.liveTile", data.pOnHoverMethods.over);
if (pauseOut)
$tile.bind("touchend.liveTile", data.pOnHoverMethods.out);
}
}
})();
},
unbindMsPauseOnHover: function ($tile, data) {
if (typeof (data.pOnHoverMethods) !== "undefined" && window.navigator.msPointerEnabled) {
$tile[0].removeEventListener('MSPointerOver', data.pOnHoverMethods.over, false);
$tile[0].removeEventListener('MSPointerOut', data.pOnHoverMethods.out, false);
}
},
bindPlayOnHover: function ($tile, data) {
// play the tile immediately when hovered
(function () {
var isOver = false,
isPending = false,
playIn = (data.playOnHoverEvent == "both" || data.playOnHoverEvent == "mouseover" || data.playOnHoverEvent == "mouseenter"),
playOut = (data.playOnHoverEvent == "both" || data.playOnHoverEvent == "mouseout" || data.playOnHoverEvent == "mouseleave");
data.onHoverMethods = {
over: function (event) {
if (isOver || isPending || (data.bounce && data.bounceMethods.down != "no"))
return;
// if startNow is set use the opposite of isReversed so we're in sync
var rev = (data.mode == "flip") || (data.startNow ? !data.isReversed : data.isReversed);
window.clearTimeout(data.eventTimeout);
if ((data.runEvents && rev) || !data.hasRun) {
isPending = true;
data.eventTimeout = window.setTimeout(function () {
isPending = false;
if(playOut)
isOver = true;
pubMethods["play"].apply($tile[0], [0]);
}, data.onHoverDelay);
}
},
out: function (event) {
if (isPending) {
window.clearTimeout(data.eventTimeout);
isPending = false;
return;
}
if (playIn) {
if (!isOver && !isPending) {
return;
}
}
window.clearTimeout(data.eventTimeout);
data.eventTimeout = window.setTimeout(function () {
var rev = (data.mode == "flip") || (data.startNow ? data.isReversed : !data.isReversed);
if (data.runEvents && rev) {
pubMethods["play"].apply($tile[0], [0]);
}
isOver = false;
}, data.speed + 200);
}
};
if (!metrojs.capabilities.canTouch) {
if (playIn)
$tile.bind('mouseenter.liveTile', data.onHoverMethods.over);
if (playOut)
$tile.bind('mouseleave.liveTile', data.onHoverMethods.out);
} else {
if (window.navigator.msPointerEnabled) { // pointer
if(playIn)
$tile[0].addEventListener('MSPointerDown', data.onHoverMethods.over, false);
// mouseleave gives a more consistent effect than out when the children are transformed
if(playOut)
$tile.bind("mouseleave.liveTile", data.onHoverMethods.out);
} else { // touch events
if(playIn)
$tile.bind("touchstart.liveTile", data.onHoverMethods.over);
if(playOut)
$tile.bind("touchend.liveTile", data.onHoverMethods.out);
}
}
})();
},
unbindMsPlayOnHover: function ($tile, data) {
if (typeof (data.onHoverMethods) !== "undefined" && window.navigator.msPointerEnabled) {
$tile[0].removeEventListener('MSPointerDown', data.onHoverMethods.over, false);
}
},
bindBounce: function ($tile, data) {
// add bounce
if (data.bounce) {
$tile.addClass("bounce");
$tile.addClass("noselect");
(function () {
data.bounceMethods = {
down: "no",
threshold: 30,
zeroPos: { x: 0, y: 0 },
eventPos: { x: 0, y: 0 },
inTilePos: { x: 0, y: 0 },
pointPos: { x: 0, y: 0 },
regions: {
c: [0, 0], // center
tl: [-1, -1], // top left
tr: [1, -1], // top right
bl: [-1, 1], // bottom left
br: [1, 1], // bottom right
t: [null, -1], // top
r: [1, null], // right
b: [null, 1], // bottom
l: [-1, null] // left
},
targets: {
all: ['c', 't', 'r', 'b', 'l', 'tl', 'tr', 'bl', 'br'],
edges: ['c', 't', 'r', 'b', 'l'],
corners: ['c', 'tl', 'tr', 'bl', 'br']
},
hitTest: function ($el, pos, targetRegions, omegaC) {
var regions = data.bounceMethods.regions,
checkFor = data.bounceMethods.targets[targetRegions],
i = 0,
strictMatch = null,
looseMatch = null,
defResult = { hit: [0, 0], name: 'c' };
// scale only for android 2.x and old ie
if (metrojs.capabilities.isOldAndroid || !metrojs.capabilities.canTransition)
return defResult;
if (typeof (checkFor) == "undefined") {
if (typeof (targetRegions) === "string")
checkFor = targetRegions.split(',');
// only default to center if explicitly requested
if ($.isArray(checkFor) && $.inArray('c') == -1) {
omegaC = 0;
defResult = null;
}
}
// check for a matching region
var w = $el.width(),
h = $el.height(),
// center threshold - maximum amount from center
ct = [w * omegaC, h * omegaC],
// how far from the center is the point
diffX = pos.x - (w * 0.5),
diffY = pos.y - (h * 0.5),
// if we're beyond the center threshold, set -1 or 1 else 0
hit = [
diffX > 0 ? (Math.abs(diffX) <= ct[0] ? 0 : 1) : (Math.abs(diffX) <= ct[0] ? 0 : -1),
diffY > 0 ? (Math.abs(diffY) <= ct[1] ? 0 : 1) : (Math.abs(diffY) <= ct[1] ? 0 : -1)
];
for (; i < checkFor.length; i++) {
if (strictMatch != null)
return strictMatch;
var r = checkFor[i],
region = regions[r];
if (r == "*") {
r = checkFor[i + 1];
return { region: regions[r], name: r };
}
if (hit[0] == region[0] && hit[1] == region[1]) {
// found the region with a strict lookup
strictMatch = { hit: region, name: r };
} else if ((hit[0] == region[0] || region[0] == null) && (hit[1] == region[1] || region[1] == null)) {
// found the region with a loose lookup
looseMatch = { hit: region, name: r };
}
}
// prefer a strict match
if (strictMatch != null)
return strictMatch;
else if (looseMatch != null)
return looseMatch;
else // no matches were found, return center
return defResult;
},
bounceDown: function (e) {
if (e.target.tagName == "A" && !$(e).is(".bounce"))
return;
var point = e.originalEvent && e.originalEvent.touches ? e.originalEvent.touches[0] : e,
offsetOfTile = $tile.offset(),
scrollX = window.pageXOffset,
scrollY = window.pageYOffset;
data.bounceMethods.pointPos = {
x: point.pageX,
y: point.pageY
};
data.bounceMethods.inTilePos = {
x: point.pageX - offsetOfTile.left,
y: point.pageY - offsetOfTile.top
};
if (!data.$tileParent) {
data.$tileParent = $tile.parent();
}
var offsetOfParent = data.$tileParent.offset();
data.bounceMethods.eventPos = {
x: (offsetOfTile.left - offsetOfParent.left) + ($tile.width() / 2),
y: (offsetOfTile.top - offsetOfParent.top) + ($tile.height() / 2)
};
var hit = data.bounceMethods.hitTest($tile, data.bounceMethods.inTilePos, data.bounceDirections, 0.25);
if (hit == null)
data.bounceMethods.down = "no";
else {
if (window.navigator.msPointerEnabled) {
document.addEventListener('MSPointerUp', data.bounceMethods.bounceUp, false);
$tile[0].addEventListener('MSPointerUp', data.bounceMethods.bounceUp, false);
document.addEventListener('MSPointerCancel', data.bounceMethods.bounceUp, false);
if (data.bounceFollowsMove)
$tile[0].addEventListener('MSPointerMove', data.bounceMethods.bounceMove, false);
} else {
$(document).bind("mouseup.liveTile, touchend.liveTile, touchcancel.liveTile, dragstart.liveTile", data.bounceMethods.bounceUp);
if (data.bounceFollowsMove) {
$tile.bind("touchmove.liveTile", data.bounceMethods.bounceMove);
$tile.bind("mousemove.liveTile", data.bounceMethods.bounceMove);
}
}
var bClass = "bounce-" + hit.name;
$tile.addClass(bClass);
data.bounceMethods.down = bClass;
data.bounceMethods.downPcss = helperMethods.appendStyleProperties({}, ['perspective-origin'], [data.bounceMethods.eventPos.x + "px " + data.bounceMethods.eventPos.y + "px"]);
data.$tileParent.css(data.bounceMethods.downPcss);
}
},
bounceUp: function () {
if (data.bounceMethods.down != "no") {
data.bounceMethods.unBounce();
if (window.navigator.msPointerEnabled) {
document.removeEventListener('MSPointerUp', data.bounceMethods.bounceUp, false);
$tile[0].removeEventListener('MSPointerUp', data.bounceMethods.bounceUp, false);
document.removeEventListener('MSPointerCancel', data.bounceMethods.bounceUp, false);
if (data.bounceFollowsMove)
$tile[0].removeEventListener('MSPointerMove', data.bounceMethods.bounceMove, false);
} else
$(document).unbind("mouseup.liveTile, touchend.liveTile, touchcancel.liveTile, dragstart.liveTile", data.bounceMethods.bounceUp);
if (data.bounceFollowsMove) {
$tile.unbind("touchmove.liveTile", data.bounceMethods.bounceMove);
$tile.unbind("mousemove.liveTile", data.bounceMethods.bounceMove);
}
}
},// not currently used
bounceMove: function (e) {
if (data.bounceMethods.down != "no") {
var point = e.originalEvent && e.originalEvent.touches ? e.originalEvent.touches[0] : e,
x = Math.abs(point.pageX - data.bounceMethods.pointPos.x),
y = Math.abs(point.pageY - data.bounceMethods.pointPos.y);
if (x > data.bounceMethods.threshold || y > data.bounceMethods.threshold) {
var bounceClass = data.bounceMethods.down;
data.bounceMethods.bounceDown(e);
if (bounceClass != data.bounceMethods.down)
$tile.removeClass(bounceClass);
}
}
},
unBounce: function () {
$tile.removeClass(data.bounceMethods.down);
if (typeof (data.bounceMethods.downPcss) == "object") {
var names = ['perspective-origin', 'perspective-origin-x', 'perspective-origin-y'],
vals = ['', '', ''];
data.bounceMethods.downPcss = helperMethods.appendStyleProperties({}, names, vals);
// let the bounce finish and then strip out the perspective
window.setTimeout(function () {
data.$tileParent.css(data.bounceMethods.downPcss);
}, 200);
}
data.bounceMethods.down = "no";
data.bounceMethods.inTilePos = data.bounceMethods.zeroPos;
data.bounceMethods.eventPos = data.bounceMethods.zeroPos;
}
};
// IE 10+
if (window.navigator.msPointerEnabled) {// touch only -> // && window.navigator.msMaxTouchPoints) {
$tile[0].addEventListener('MSPointerDown', data.bounceMethods.bounceDown, false);
} else if (metrojs.capabilities.canTouch) {
// everybody else
$tile.bind("touchstart.liveTile", data.bounceMethods.bounceDown);
} else {
$tile.bind("mousedown.liveTile", data.bounceMethods.bounceDown);
}
})();
}
},
unbindMsBounce: function ($tile, data) {
if (data.bounce && window.navigator.msPointerEnabled) {// touch only -> // && window.navigator.msMaxTouchPoints) {
$tile[0].removeEventListener('MSPointerDown', data.bounceMethods.bounceDown, false);
$tile[0].removeEventListener('MSPointerCancel', data.bounceMethods.bounceUp, false);
$tile[0].removeEventListener('MSPointerOut', data.bounceMethods.bounceUp, false);
//$tile[0].removeEventListener('MSPointerMove', data.bounceMethods.bounceMove, false);
}
},
bindLink: function ($tile, data) {
if (data.link.length > 0) {
$tile.css({ cursor: 'pointer' }).bind("click.liveTile", function (e) {
if (e.target.tagName == "A" && !$(e).is(".live-tile,.slide,.flip"))
return;
if (data.newWindow)
window.open(data.link);
else
window.location = data.link;
});
}
},
runContenModules: function (data, $front, $back, index) {
for (var i = 0; i < data.contentModules.length; i++) {
var currentModule = data.contentModules[i];
if (typeof (currentModule.action) == "function")
currentModule.action(data, $front, $back, index);
}
},
fade: function ($tile, count, data) {
var tdata = typeof (data) === "object" ? data : $tile.data("LiveTile"),
resumeTimer = function () {
// if the tile should run again start the timer back with the current delay
if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
if (tdata.timer.count != tdata.timer.repeatCount) {
tdata.timer.start(tdata.delay);
}
}
};
if (tdata.faces.$front.is(":animated"))
return;
tdata.timer.pause();
var loopCount = tdata.loopCount + 1;
tdata.isReversed = loopCount % 2 === 0; // the count starts at 1
var start = tdata.animationStarting.call($tile[0], tdata, tdata.faces.$front, tdata.faces.$back);
if (typeof (start) != "undefined" && start == false) {
resumeTimer();
return;
}
tdata.loopCount = loopCount;
var faded = function () {
resumeTimer();
// run content modules and animationComplete callback
privMethods.runContenModules(tdata, tdata.faces.$front, tdata.faces.$back);
tdata.animationComplete.call($tile[0], tdata, tdata.faces.$front, tdata.faces.$back);
};
if (tdata.isReversed)
tdata.faces.$front.fadeIn(tdata.speed, tdata.noHaTransFunc, faded);
else
tdata.faces.$front.fadeOut(tdata.speed, tdata.noHaTransFunc, faded);
},
slide: function ($tile, count, data, stopIndex, callback) {
var tdata = typeof (data) === "object" ? data : $tile.data("LiveTile"),
aniData = $tile.data("metrojs.tile");
if (aniData.animating == true || $tile.is(":animated")) {
tdata = null;
aniData = null;
return;
}
var resumeTimer = function () {
// if the tile should run again start the timer back with the current delay
if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
if (tdata.timer.count != tdata.timer.repeatCount) {
tdata.timer.start(tdata.delay);
}
}
};
if (tdata.mode !== "carousel") {
tdata.isReversed = tdata.currentIndex % 2 !== 0; // the count starts at 1
// carousel mode maintains its own timer
tdata.timer.pause();
var start = tdata.animationStarting.call($tile[0], tdata, tdata.faces.$front, tdata.faces.$back);
if (typeof (start) != "undefined" && start == false) {
resumeTimer();
return;
}
tdata.loopCount = tdata.loopCount + 1;
} else {
// in carousel mode the face that just left the stage is always the $back
tdata.isReversed = true;
}
// get temp values passed in from data methods
var direction;
if (typeof (tdata.tempValues.direction) === "string" && tdata.tempValues.direction.length > 0)
direction = tdata.tempValues.direction;
else
direction = tdata.direction;
tdata.tempValues.direction = null;
var css = {},
cssback = {},
// the stop index is overridden in carousel mode
stopIdx = typeof (stopIndex) === "undefined" ? tdata.currentIndex : stopIndex,
stop = $.trim(tdata.stops[Math.min(stopIdx, tdata.stops.length - 1)]),
pxIdx = stop.indexOf('px'),
offset = 0,
amount = 0,
metric = (direction === "vertical") ? tdata.height : tdata.width,
tProp = (direction === "vertical") ? "top" : "left",
stack = tdata.stack == true;
// when the slide is complete increment the index or call the callback
var slideFinished = function () {
if (typeof (callback) === "undefined") {
tdata.currentIndex = tdata.currentIndex + 1;
if (tdata.currentIndex > tdata.stops.length - 1) {
tdata.currentIndex = 0;
}
} else {
callback();
}
if (tdata.mode != "carousel") {
resumeTimer();
}
// run content modules and animationComplete callback
privMethods.runContenModules(tdata, tdata.faces.$front, tdata.faces.$back, tdata.currentIndex);
tdata.animationComplete.call($tile[0], tdata, tdata.faces.$front, tdata.faces.$back);
tdata = null;
aniData = null;
};
if (pxIdx > 0) {
amount = parseInt(stop.substring(0, pxIdx), 10);
offset = (amount - metric) + 'px';
} else {
//is a percentage
amount = parseInt(stop.replace('%', ''), 10);
offset = (amount - 100) + '%';
}
// hardware accelerated :)
if (metrojs.capabilities.canTransition && tdata.useHardwareAccel) {
if (typeof (aniData.animating) !== "undefined" && aniData.animating == true)
return;
aniData.animating = true;
var props = ['transition-property', 'transition-duration', 'transition-timing-function'],
vals = [tdata.useTranslate ? "transform" : tProp, tdata.speed + 'ms', tdata.haTransFunc];
vals[helperMethods.browserPrefix + 'transition-property'] = helperMethods.browserPrefix + "transform";
css = helperMethods.appendStyleProperties(css, props, vals);
cssback = helperMethods.appendStyleProperties(cssback, props, vals);
var vertical = direction === "vertical",
prop = vertical ? "top" : "left",
translateTo;
if (!tdata.useTranslate) {
css[prop] = stop;
if (stack)
cssback[prop] = offset;
} else {
translateTo = vertical ? "translate(0%, " + stop + ")" : "translate(" + stop + ", 0%)";
css = helperMethods.appendStyleProperties(css, ['transform'], [translateTo + "translateZ(0)"]);
if (stack) {
translateTo = vertical ? "translate(0%, " + offset + ")" : "translate(" + offset + ", 0%)";
cssback = helperMethods.appendStyleProperties(cssback, ['transform'], [translateTo + "translateZ(0)"]);
}
}
tdata.faces.$front.css(css);
if (stack)
tdata.faces.$back.css(cssback);
window.clearTimeout(tdata.completeTimeout);
tdata.completeTimeout = window.setTimeout(function () {
aniData.animating = false;
slideFinished();
}, tdata.speed);
} else {
// not hardware accelerated :(
css[tProp] = stop;
cssback[tProp] = offset;
aniData.animating = true;
var $front = tdata.faces.$front.stop(),
$back = tdata.faces.$back.stop();
$front.animate(css, tdata.speed, tdata.noHaTransFunc, function () {
aniData.animating = false;
slideFinished();
});
// change the css value to the offset
if (stack)
$back.animate(cssback, tdata.speed, tdata.noHaTransFunc, function () { });
}
},
carousel: function ($tile, count) {
var tdata = $tile.data("LiveTile");
// dont update css or call slide if animated or if there's only one face
var aniData = $tile.data("metrojs.tile");
if (aniData.animating == true || tdata.faces.$listTiles.length <= 1) {
aniData = null;
return;
}
var resumeTimer = function () {
if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
if (tdata.timer.count != tdata.timer.repeatCount) {
tdata.timer.start(tdata.delay);
}
}
};
// pause the timer and use a per slide delay
tdata.timer.pause();
var $cur = tdata.faces.$listTiles.filter(".active"),
idx = tdata.faces.$listTiles.index($cur),
goTo = tdata.currentIndex,
eq = goTo != idx ? goTo : idx,
nxtIdx = eq + 1 >= tdata.faces.$listTiles.length ? 0 : eq + 1,
sdata = tdata.listData[nxtIdx];
if (idx == nxtIdx) {
aniData = null;
$cur = null;
return;
}
// get temp values passed in from data methods
var animationDirection;
if (typeof (tdata.tempValues.animationDirection) === "string" && tdata.tempValues.animationDirection.length > 0)
animationDirection = tdata.tempValues.animationDirection;
else if (typeof (sdata.animationDirection) === "string" && sdata.animationDirection.length > 0) {
animationDirection = sdata.animationDirection;
} else
animationDirection = tdata.animationDirection;
// the temp value for animation direction is not used in slide so i'm setting it to null
tdata.tempValues.animationDirection = null;
var direction;
if (typeof (tdata.tempValues.direction) === "string" && tdata.tempValues.direction.length > 0) {
direction = tdata.tempValues.direction;
} else if (typeof (sdata.direction) === "string" && sdata.direction.length > 0) {
direction = sdata.direction;
tdata.tempValues.direction = direction;
} else {
direction = tdata.direction;
}
var $nxt = tdata.faces.$listTiles.eq(nxtIdx),
start = tdata.animationStarting.call($tile[0], tdata, $cur, $nxt);
if (typeof (start) != "undefined" && start == false) {
resumeTimer();
return;
}
tdata.loopCount = tdata.loopCount + 1;
var nxtCss = helperMethods.appendStyleProperties({}, ['transition-duration'], ['0s']),
vertical = direction === "vertical",
translateTo;
if (animationDirection === "backward") {
if (!tdata.useTranslate || !metrojs.capabilities.canTransition) {
if (vertical) {
nxtCss.top = "-100%";
nxtCss.left = "0%";
} else {
nxtCss.top = "0%";
nxtCss.left = "-100%";
}
tdata.stops = ['100%'];
} else {
translateTo = vertical ? "translate(0%, -100%)" : "translate(-100%, 0%)";
nxtCss = helperMethods.appendStyleProperties(nxtCss, ["transform"], [translateTo + " translateZ(0)"]);
tdata.stops = ['100%'];
}
tdata.faces.$front = $cur;
tdata.faces.$back = $nxt;
} else {
if (!tdata.useTranslate || !metrojs.capabilities.canTransition) {
if (vertical) {
nxtCss.top = "100%";
nxtCss.left = "0%";
} else {
nxtCss.top = "0%";
nxtCss.left = "100%";
}
} else {
translateTo = vertical ? "translate(0%, 100%)" : "translate(100%, 0%)";
nxtCss = helperMethods.appendStyleProperties(nxtCss, ["transform"], [translateTo + " translateZ(0)"]);
}
tdata.faces.$front = $nxt;
tdata.faces.$back = $cur;
tdata.stops = ['0%'];
}
$nxt.css(nxtCss);
// the timeout wrapper gives the css call above enough time to finish in case we dynamically set the direction
window.setTimeout(function () {
$cur.removeClass("active");
$nxt.addClass("active");
privMethods.slide($tile, count, tdata, 0, function () {
tdata.currentIndex = nxtIdx;
aniData = null;
$cur = null;
$nxt = null;
resumeTimer();
});
}, 150);
},
flip: function ($tile, count, data, callback) {
var aniData = $tile.data("metrojs.tile");
if (aniData.animating == true) {
aniData = null;
return;
}
var tdata = typeof (data) === "object" ? data : $tile.data("LiveTile");
var $front, $back, direction, deg, rotateDir, css,
raiseEvt = typeof (callback) === "undefined",
index = 0,
isReversed, // the count starts at 1
resumeTimer = function () {
// if the tile should run again start the timer back with the current delay
if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
if (tdata.timer.count != tdata.timer.repeatCount) {
tdata.timer.start(tdata.delay);
}
}
};
// the timer is only paused if animationComplete is fired
if (raiseEvt) {
tdata.timer.pause();
var loopCount = tdata.loopCount + 1;
isReversed = loopCount % 2 === 0;
tdata.isReversed = isReversed;
$front = tdata.faces.$front;
$back = tdata.faces.$back;
var args = isReversed ? [tdata, $back, $front] : [tdata, $front, $back];
var start = tdata.animationStarting.apply($tile[0], args);
if (typeof (start) != "undefined" && start == false) {
resumeTimer();
return;
}
direction = tdata.direction;
height = tdata.height;
width = tdata.width;
margin = tdata.margin;
tdata.loopCount = loopCount;
} else {
isReversed = count % 2 === 0;
index = aniData.index;
$front = tdata.listData[index].faces.$front;
$back = tdata.listData[index].faces.$back;
tdata.listData[index].isReversed = isReversed;
direction = tdata.listData[index].direction;
height = tdata.listData[index].height;
width = tdata.listData[index].width;
margin = tdata.listData[index].margin;
}
if (metrojs.capabilities.canFlip3d && tdata.useHardwareAccel) { // Hardware accelerated :)
deg = !isReversed ? "180deg" : "360deg";
rotateDir = direction === "vertical" ? "rotateX(" + deg + ")" : "rotateY(" + deg + ")";
css = helperMethods.appendStyleProperties({}, ["transform", "transition"], [rotateDir, "all " + tdata.speed + "ms " + tdata.haTransFunc + " 0s"]);
var bDeg = !isReversed ? "360deg" : "540deg";
var bRotateDir = direction === "vertical" ? "rotateX(" + bDeg + ")" : "rotateY(" + bDeg + ")";
var bCss = helperMethods.appendStyleProperties({}, ["transform", "transition"], [bRotateDir, "all " + tdata.speed + "ms " + tdata.haTransFunc + " 0s"]);
$front.css(css);
$back.css(bCss);
var action = function () {
aniData.animating = false;
var resetDir, newCss;
if (!isReversed) {
privMethods.runContenModules(tdata, $back, $front, index);
if (raiseEvt) {
resumeTimer();
tdata.animationComplete.call($tile[0], tdata, $back, $front);
} else
callback(tdata, $back, $front);
} else {
resetDir = direction === "vertical" ? "rotateX(0deg)" : "rotateY(0deg)";
newCss = helperMethods.appendStyleProperties({}, ["transform", "transition"], [resetDir, "all 0s " + tdata.haTransFunc + " 0s"]);
$front.css(newCss);
//call content modules
privMethods.runContenModules(tdata, $front, $back, index);
if (raiseEvt) {
resumeTimer();
tdata.animationComplete.call($tile[0], tdata, $front, $back);
} else
callback(tdata, $front, $back);
$front = null;
$back = null;
tdata = null;
aniData = null;
}
};
if (tdata.mode === "flip-list") {
window.clearTimeout(tdata.listData[index].completeTimeout);
tdata.listData[index].completeTimeout = window.setTimeout(action, tdata.speed);
} else {
window.clearTimeout(tdata.completeTimeout);
tdata.completeTimeout = window.setTimeout(action, tdata.speed);
}
} else { // not Hardware accelerated :(
var speed = tdata.speed / 2;
var hideCss = (direction === "vertical") ?
{ height: '0px', width: '100%', marginTop: margin + 'px', opacity: tdata.noHAflipOpacity } :
{ height: '100%', width: '0px', marginLeft: margin + 'px', opacity: tdata.noHAflipOpacity };
var showCss = (direction === "vertical") ?
{ height: '100%', width: '100%', marginTop: '0px', opacity: '1' } :
{ height: '100%', width: '100%', marginLeft: '0px', opacity: '1' };
var noHaAction;
if (!isReversed) {
aniData.animating = true;
$front.stop().animate(hideCss, { duration: speed });
noHaAction = function () {
aniData.animating = false;
$back.stop().animate(showCss, {
duration: speed,
complete: function () {
privMethods.runContenModules(tdata, $back, $front, index);
if (raiseEvt) {
resumeTimer();
tdata.animationComplete.call($tile[0], tdata, $back, $front);
} else
callback(tdata, $back, $front);
$front = null;
$back = null;
tdata = null;
aniData = null;
}
});
};
if (tdata.mode === "flip-list") {
window.clearTimeout(tdata.listData[aniData.index].completeTimeout);
tdata.listData[aniData.index].completeTimeout = window.setTimeout(noHaAction, speed);
} else {
window.clearTimeout(tdata.completeTimeout);
tdata.completeTimeout = window.setTimeout(noHaAction, speed);
}
} else {
aniData.animating = true;
$back.stop().animate(hideCss, { duration: speed });
noHaAction = function () {
aniData.animating = false;
$front.stop().animate(showCss, {
duration: speed,
complete: function () {
privMethods.runContenModules(tdata, $front, $back, index);
if (raiseEvt) {
resumeTimer();
tdata.animationComplete.call($tile[0], tdata, $front, $back);
} else
callback(tdata, $front, $back);
aniData = null;
$front = null;
$back = null;
}
});
};
if (tdata.mode === "flip-list") {
window.clearTimeout(tdata.listData[aniData.index].completeTimeout);
tdata.listData[aniData.index].completeTimeout = window.setTimeout(noHaAction, speed);
} else {
window.clearTimeout(tdata.completeTimeout);
tdata.completeTimeout = window.setTimeout(noHaAction, speed);
}
}
}
},
flipList: function ($tile, count) {
var tdata = $tile.data("LiveTile"),
maxDelay = tdata.speed,
triggered = false,
resumeTimer = function () {
if (tdata.timer.repeatCount > 0 || tdata.timer.repeatCount == -1) {
if (tdata.timer.count != tdata.timer.repeatCount) {
tdata.timer.start(tdata.delay);
}
}
};
tdata.timer.pause();
var start = tdata.animationStarting.call($tile[0], tdata, null, null);
if (typeof (start) != "undefined" && start == false) {
resumeTimer();
return;
}
tdata.loopCount = tdata.loopCount + 1;
tdata.faces.$listTiles.each(function (idx, ele) {
var $li = $(ele),
ldata = $li.data("metrojs.tile"),
tDelay = tdata.triggerDelay(idx),
triggerDelay = tdata.speed + Math.max(tDelay, 0),
trigger = tdata.alwaysTrigger;
if (!trigger)
trigger = (Math.random() * 351) > 150 ? true : false;
if (trigger) {
triggered = true;
maxDelay = Math.max(triggerDelay + tdata.speed, maxDelay);
window.clearTimeout(ldata.flCompleteTimeout);
ldata.flCompleteTimeout = window.setTimeout(function () {
// call the flip method with the merged data, but dont fire animationComplete
privMethods.flip($li, ldata.count, tdata, function (data) {
ldata.count++;
if (ldata.count >= MAX_LOOP_COUNT)
ldata.count = 1;
$li = null;
ldata = null;
});
}, triggerDelay);
}
});
if (triggered) {
window.clearTimeout(tdata.flCompleteTimeout);
tdata.flCompleteTimeout = window.setTimeout(function () {
privMethods.runContenModules(tdata, null, null, -1);
tdata.animationComplete.call($tile[0], tdata, null, null);
resumeTimer();
}, maxDelay + tdata.speed); // add some padding to make sure the final callback finished
}
}
};
// methods that can be called more universally
var helperMethods = {
stylePrefixes: 'Webkit Moz O ms Khtml '.split(' '),
domPrefixes: '-webkit- -moz- -o- -ms- -khtml- '.split(' '),
browserPrefix: null,
// a method to append css3 properties for each browser
// note: values are identical for each property
appendStyleProperties: function (obj, names, values) {
for (var i = 0; i <= names.length - 1; i++) {
obj[$.trim(this.browserPrefix + names[i])] = values[i];
obj[$.trim(names[i])] = values[i];
}
return obj;
},
applyStyleValue: function (obj, name, value) {
obj[$.trim(this.browserPrefix + name)] = value;
obj[name] = value;
return obj;
},
getBrowserPrefix: function () {
if (this.browserPrefix == null) {
var prefix = "";
for (var i = 0; i <= this.domPrefixes.length - 1; i++) {
if (typeof (document.body.style[this.domPrefixes[i] + "transform"]) != "undefined")
prefix = this.domPrefixes[i];
}
return this.browserPrefix = prefix;
}
return this.browserPrefix;
},
//a shuffle method to provide more randomness than sort
//credit: http://javascript.about.com/library/blshuffle.htm
//note: avoiding prototype for sharepoint compatability
shuffleArray: function (array) {
var s = [];
while (array.length) s.push(array.splice(Math.random() * array.length, 1));
while (s.length) array.push(s.pop());
return array;
}
};
var defaultModules = {
moduleName: 'custom',
customSwap: {
data: {
customDoSwapFront: function () { return false; },
customDoSwapBack: function () { return false; },
customGetContent: function (tdata, $front, $back, index) { return null; }
},
initData: function (tdata, $ele) {
var swapData = {};
swapData.doSwapFront = $.inArray('custom', tdata.swapFront) > -1 && tdata.customDoSwapFront();
swapData.doSwapBack = $.inArray('custom', tdata.swapBack) > -1 && tdata.customDoSwapBack();
if (typeof (tdata.customSwap) !== "undefined")
tdata.customSwap = $.extend(swapData, tdata.customSwap);
else
tdata.customSwap = swapData;
},
action: function (tdata, $front, $back, index) {
}
},
htmlSwap: {
moduleName: 'html',
data: { // public data for the swap module
frontContent: [], // a list of html to use for the front
frontIsRandom: true, // should html be chosen at random or in order
frontIsInGrid: false, // only chooses one item for each iteration in flip-list
backContent: [], // a list of html to use for the back
backIsRandom: true, // should html be chosen at random or in order
backIsInGrid: false // only chooses one item for each iteration in flip-list
},
initData: function (tdata, $ele) {
var swapData = { // private data for the swap module
backBag: [],
backIndex: 0,
backStaticIndex: 0,
backStaticRndm: -1,
prevBackIndex: -1,
frontBag: [],
frontIndex: 0,
frontStaticIndex: 0,
frontStaticRndm: -1,
prevFrontIndex: -1
};
if (!tdata.ignoreDataAttributes) {
swapData.frontIsRandom = privMethods.getDataOrDefault($ele, "front-israndom", tdata.frontIsRandom);
swapData.frontIsInGrid = privMethods.getDataOrDefault($ele, "front-isingrid", tdata.frontIsInGrid);
swapData.backIsRandom = privMethods.getDataOrDefault($ele, "back-israndom", tdata.backIsRandom);
swapData.backIsInGrid = privMethods.getDataOrDefault($ele, "back-isingrid", tdata.backIsInGrid);
} else {
swapData.frontIsRandom = tdata.frontIsRandom;
swapData.frontIsInGrid = tdata.frontIsInGrid;
swapData.backIsRandom = tdata.backIsRandom;
swapData.backIsInGrid = tdata.backIsInGrid;
}
swapData.doSwapFront = $.inArray('html', tdata.swapFront) > -1 && (tdata.frontContent instanceof Array) && tdata.frontContent.length > 0;
swapData.doSwapBack = $.inArray('html', tdata.swapBack) > -1 && (tdata.backContent instanceof Array) && tdata.backContent.length > 0;
if (typeof (tdata.htmlSwap) !== "undefined")
tdata.htmlSwap = $.extend(swapData, tdata.htmlSwap);
else
tdata.htmlSwap = swapData;
if (tdata.htmlSwap.doSwapFront) {
tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.prevFrontIndex);
tdata.htmlSwap.frontStaticRndm = tdata.htmlSwap.frontBag.pop();
}
if (tdata.htmlSwap.doSwapBack) {
tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.prevBackIndex);
tdata.htmlSwap.backStaticRndm = tdata.htmlSwap.backBag.pop();
}
},
prepBag: function (bag, content, prevIdx) {
bag = bag || [];
var bagCount = 0;
for (var i = 0; i < content.length; i++) {
//make sure there's not an immediate repeat
if (i != prevIdx || bag.length === 1) {
bag[bagCount] = i;
bagCount++;
}
}
return helperMethods.shuffleArray(bag);
},
getFrontSwapIndex: function (tdata) {
var idx = 0;
if (!tdata.htmlSwap.frontIsRandom) {
idx = tdata.htmlSwap.frontIsInGrid ? tdata.htmlSwap.frontStaticIndex : tdata.htmlSwap.frontIndex;
} else {
if (tdata.htmlSwap.frontBag.length === 0) {
tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.prevFrontIndex);
}
if (tdata.htmlSwap.frontIsInGrid) {
idx = tdata.htmlSwap.frontStaticRndm;
} else {
idx = tdata.htmlSwap.frontBag.pop();
}
}
return idx;
},
getBackSwapIndex: function (tdata) {
var idx = 0;
if (!tdata.htmlSwap.backIsRandom) {
idx = tdata.htmlSwap.backIsInGrid ? tdata.htmlSwap.backStaticIndex : tdata.htmlSwap.backIndex;
} else {
if (tdata.htmlSwap.backBag.length === 0) {
tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.prevBackIndex);
}
if (tdata.htmlSwap.backIsInGrid) {
idx = tdata.htmlSwap.backStaticRndm;
} else {
idx = tdata.htmlSwap.backBag.pop();
}
}
return idx;
},
action: function (tdata, $front, $back, index) {
if (!tdata.htmlSwap.doSwapFront && !tdata.htmlSwap.doSwapBack)
return;
var isList = tdata.mode === "flip-list";
var swapIndex = 0;
var isReversed = isList ? tdata.listData[Math.max(index, 0)].isReversed : tdata.isReversed;
if (isList && index == -1) {
// flip list completed
if (!isReversed) {
if (tdata.htmlSwap.doSwapFront) {
// update the random value for grid mode
if (tdata.htmlSwap.frontBag.length === 0)
tdata.htmlSwap.frontBag = this.prepBag(tdata.htmlSwap.frontBag, tdata.frontContent, tdata.htmlSwap.frontStaticRndm);
tdata.htmlSwap.frontStaticRndm = tdata.htmlSwap.frontBag.pop();
// update the static index
tdata.htmlSwap.frontStaticIndex++;
if (tdata.htmlSwap.frontStaticIndex >= tdata.frontContent.length)
tdata.htmlSwap.frontStaticIndex = 0;
}
} else {
if (tdata.htmlSwap.doSwapBack) {
// update the random value for grid mode
if (tdata.htmlSwap.backBag.length === 0)
tdata.htmlSwap.backBag = this.prepBag(tdata.htmlSwap.backBag, tdata.backContent, tdata.htmlSwap.backStaticRndm);
tdata.htmlSwap.backStaticRndm = tdata.htmlSwap.backBag.pop();
// update the static index
tdata.htmlSwap.backStaticIndex++;
if (tdata.htmlSwap.backStaticIndex >= tdata.backContent.length)
tdata.htmlSwap.backStaticIndex = 0;
}
}
return;
}
if (!isReversed) {
if (!tdata.htmlSwap.doSwapFront)
return;
swapIndex = this.getFrontSwapIndex(tdata);
tdata.htmlSwap.prevFrontIndex = swapIndex;
if (tdata.mode === "slide") {
if (!tdata.startNow)
$front.html(tdata.frontContent[swapIndex]);
else
$back.html(tdata.frontContent[swapIndex]);
} else
$back.html(tdata.frontContent[swapIndex]);
// increment the front index to get the next item from the list
tdata.htmlSwap.frontIndex++;
if (tdata.htmlSwap.frontIndex >= tdata.frontContent.length)
tdata.htmlSwap.frontIndex = 0;
if (!isList) {
// increment the static index if we're not in list mode
tdata.htmlSwap.frontStaticIndex++;
if (tdata.htmlSwap.frontStaticIndex >= tdata.frontContent.length)
tdata.htmlSwap.frontStaticIndex = 0;
} else {
// flip list
}
} else {
if (!tdata.htmlSwap.doSwapBack)
return;
swapIndex = this.getBackSwapIndex(tdata);
tdata.htmlSwap.prevBackIndex = swapIndex;
$back.html(tdata.backContent[tdata.htmlSwap.backIndex]);
tdata.htmlSwap.backIndex++;
if (tdata.htmlSwap.backIndex >= tdata.backContent.length)
tdata.htmlSwap.backIndex = 0;
if (!isList) {
tdata.htmlSwap.backStaticIndex++;
if (tdata.htmlSwap.backStaticIndex >= tdata.backContent.length)
tdata.htmlSwap.backStaticIndex = 0;
} else {
// flip list
}
}
}
},
imageSwap: {
moduleName: 'image',
data: {
preloadImages: false,
imageCssSelector: '>img,>a>img', // the selector used to choose a an image to apply a src or background to
fadeSwap: false, // fade the image before swapping
frontImages: [], // a list of images to use for the front
frontIsRandom: true, // should images be chosen at random or in order
frontIsBackgroundImage: false, // set the src attribute or css background-image property
frontIsInGrid: false, // only chooses one item for each iteration in flip-list
backImages: null, // a list of images to use for the back
backIsRandom: true, // should images be chosen at random or in order
backIsBackgroundImage: false, // set the src attribute or css background-image property
backIsInGrid: false // only chooses one item for each iteration in flip-list
},
initData: function (tdata, $ele) {
var swapData = {
backBag: [],
backIndex: 0,
backStaticIndex: 0,
backStaticRndm: -1,
frontBag: [],
frontIndex: 0,
frontStaticIndex: 0,
frontStaticRndm: -1,
prevBackIndex: -1,
prevFrontIndex: -1
}, useData = tdata.ignoreDataAttributes;
if (useData) {
swapData.imageCssSelector = privMethods.getDataOrDefault($ele, "image-css", tdata.imageCssSelector);
swapData.fadeSwap = privMethods.getDataOrDefault($ele, "fadeswap", tdata.fadeSwap);
swapData.frontIsRandom = privMethods.getDataOrDefault($ele, "front-israndom", tdata.frontIsRandom);
swapData.frontIsInGrid = privMethods.getDataOrDefault($ele, "front-isingrid", tdata.frontIsInGrid);
swapData.frontIsBackgroundImage = privMethods.getDataOrDefault($ele, "front-isbg", tdata.frontIsBackgroundImage);
swapData.backIsRandom = privMethods.getDataOrDefault($ele, "back-israndom", tdata.backIsRandom);
swapData.backIsInGrid = privMethods.getDataOrDefault($ele, "back-isingrid", tdata.backIsInGrid);
swapData.backIsBackgroundImage = privMethods.getDataOrDefault($ele, "back-isbg", tdata.backIsBackgroundImage);
swapData.doSwapFront = $.inArray('image', tdata.swapFront) > -1 && (tdata.frontImages instanceof Array) && tdata.frontImages.length > 0;
swapData.doSwapBack = $.inArray('image', tdata.swapBack) > -1 && (tdata.backImages instanceof Array) && tdata.backImages.length > 0;
swapData.alwaysSwapFront = privMethods.getDataOrDefault($ele, "front-alwaysswap", tdata.alwaysSwapFront);
swapData.alwaysSwapBack = privMethods.getDataOrDefault($ele, "back-alwaysswap", tdata.alwaysSwapBack);
} else {
swapData.imageCssSelector = tdata.imageCssSelector;
swapData.fadeSwap = tdata.fadeSwap;
swapData.frontIsRandom = tdata.frontIsRandom;
swapData.frontIsInGrid = tdata.frontIsInGrid;
swapData.frontIsBackgroundImage = tdata.frontIsBackgroundImage;
swapData.backIsRandom = tdata.backIsRandom;
swapData.backIsInGrid = tdata.backIsInGrid;
swapData.backIsBackgroundImage = tdata.backIsBackgroundImage;
swapData.doSwapFront = $.inArray('image', tdata.swapFront) > -1 && (tdata.frontImages instanceof Array) && tdata.frontImages.length > 0;
swapData.doSwapBack = $.inArray('image', tdata.swapBack) > -1 && (tdata.backImages instanceof Array) && tdata.backImages.length > 0;
swapData.alwaysSwapFront = tdata.alwaysSwapFront;
swapData.alwaysSwapBack = tdata.alwaysSwapBack;
}
if (typeof (tdata.imgSwap) !== "undefined")
tdata.imgSwap = $.extend(swapData, tdata.imgSwap);
else
tdata.imgSwap = swapData;
if (tdata.imgSwap.doSwapFront) {
tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.prevFrontIndex);
tdata.imgSwap.frontStaticRndm = tdata.imgSwap.frontBag.pop();
if (tdata.preloadImages)
$(tdata.frontImages).metrojs.preloadImages(function () { });
}
if (tdata.imgSwap.doSwapBack) {
tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.prevBackIndex);
tdata.imgSwap.backStaticRndm = tdata.imgSwap.backBag.pop();
if (tdata.preloadImages)
$(tdata.backImages).metrojs.preloadImages(function () { });
}
},
prepBag: function (bag, content, prevIdx) {
bag = bag || [];
var bagCount = 0;
for (var i = 0; i < content.length; i++) {
//make sure there's not an immediate repeat
if (i != prevIdx || content.length === 1) {
bag[bagCount] = i;
bagCount++;
}
}
return helperMethods.shuffleArray(bag);
},
getFrontSwapIndex: function (tdata) {
var idx = 0;
if (!tdata.imgSwap.frontIsRandom) {
idx = tdata.imgSwap.frontIsInGrid ? tdata.imgSwap.frontStaticIndex : tdata.imgSwap.frontIndex;
} else {
if (tdata.imgSwap.frontBag.length === 0) {
tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.prevFrontIndex);
}
if (tdata.imgSwap.frontIsInGrid) {
idx = tdata.imgSwap.frontStaticRndm;
} else {
idx = tdata.imgSwap.frontBag.pop();
}
}
return idx;
},
getBackSwapIndex: function (tdata) {
var idx = 0;
if (!tdata.imgSwap.backIsRandom) {
idx = tdata.imgSwap.backIsInGrid ? tdata.imgSwap.backStaticIndex : tdata.imgSwap.backIndex;
} else {
if (tdata.imgSwap.backBag.length === 0) {
tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.prevBackIndex);
}
if (tdata.imgSwap.backIsInGrid) {
idx = tdata.imgSwap.backStaticRndm;
} else {
idx = tdata.imgSwap.backBag.pop();
}
}
return idx;
},
setImageProperties: function ($img, image, isBackground) {
var css = {}, // css object to apply
attr = {}; // attribute values to apply
// get image source
if (typeof (image.src) !== 'undefined') {
if (!isBackground)
attr.src = image.src;
else
css.backgroundImage = "url('" + image.src + "')";
}
// get alt text
if (typeof (image.alt) !== 'undefined')
attr.alt = image.alt;
// set css
if (typeof (image.css) === 'object')
$img.css($.extend(css, image.css));
else
$img.css(css);
// set attributes
if (typeof (image.attr) === 'object')
$img.attr($.extend(attr, image.attr));
else
$img.attr(attr);
},
action: function (tdata, $front, $back, index) {
if (!tdata.imgSwap.doSwapFront && !tdata.imgSwap.doSwapBack)
return;
var isList = tdata.mode === "flip-list",
isSlide = tdata.mode == "slide",
swapIndex = 0,
isReversed = isList ? tdata.listData[Math.max(index, 0)].isReversed : tdata.isReversed;
if (isList && index == -1) {
// flip list completed
if (tdata.alwaysSwapFront || !isReversed) {
if (tdata.imgSwap.doSwapFront) {
// update the random value for grid mode
if (tdata.imgSwap.frontBag.length === 0)
tdata.imgSwap.frontBag = this.prepBag(tdata.imgSwap.frontBag, tdata.frontImages, tdata.imgSwap.frontStaticRndm);
tdata.imgSwap.frontStaticRndm = tdata.imgSwap.frontBag.pop();
// update the static index
tdata.imgSwap.frontStaticIndex++;
if (tdata.imgSwap.frontStaticIndex >= tdata.frontImages.length)
tdata.imgSwap.frontStaticIndex = 0;
}
}
if (tdata.alwaysSwapBack || isReversed) {
if (tdata.imgSwap.doSwapBack) {
// update the random value for grid mode
if (tdata.imgSwap.backBag.length === 0)
tdata.imgSwap.backBag = this.prepBag(tdata.imgSwap.backBag, tdata.backImages, tdata.imgSwap.backStaticRndm);
tdata.imgSwap.backStaticRndm = tdata.imgSwap.backBag.pop();
// update the static index
tdata.imgSwap.backStaticIndex++;
if (tdata.imgSwap.backStaticIndex >= tdata.backImages.length)
tdata.imgSwap.backStaticIndex = 0;
}
}
return;
}
var $face, // face being swapped
$img, // image to apply values
image,// image object to hold properties
swap; // wrapper for setimageProperties for fade
if (tdata.alwaysSwapFront || !isReversed) {
if (!tdata.imgSwap.doSwapFront)
return;
swapIndex = this.getFrontSwapIndex(tdata);
tdata.imgSwap.prevFrontIndex = swapIndex;
// slide mode has a static front and back face
$face = (tdata.mode === "slide") ? $front : $back;
$img = $face.find(tdata.imgSwap.imageCssSelector);
image = typeof (tdata.frontImages[swapIndex]) === "object" ? tdata.frontImages[swapIndex] : { src: tdata.frontImages[swapIndex] };
swap = function (callback) {
// set src, alt, css and attribute values
var isBg = tdata.imgSwap.frontIsBackgroundImage;
if (typeof(callback) == "function") {
if (isBg)
window.setTimeout(callback, 100);
else
$img[0].onload = callback;
}
defaultModules.imageSwap.setImageProperties($img, image, isBg);
};
if (tdata.fadeSwap) {
$img.fadeOut(function () {
swap(function () {
$img.fadeIn();
});
});
} else
swap();
// increment indexes
tdata.imgSwap.frontIndex++;
if (tdata.imgSwap.frontIndex >= tdata.frontImages.length)
tdata.imgSwap.frontIndex = 0;
if (!isList) {
tdata.imgSwap.frontStaticIndex++;
if (tdata.imgSwap.frontStaticIndex >= tdata.frontImages.length)
tdata.imgSwap.frontStaticIndex = 0;
} else {
}
}
if (tdata.alwaysSwapBack || isReversed) {
if (!tdata.imgSwap.doSwapBack)
return;
// get the new index
swapIndex = this.getBackSwapIndex(tdata);
tdata.imgSwap.prevBackIndex = swapIndex;
// use the $face var for consistency
$face = $back;
$img = $face.find(tdata.imgSwap.imageCssSelector);
image = typeof (tdata.backImages[swapIndex]) === "object" ? tdata.backImages[swapIndex] : { src: tdata.backImages[swapIndex] };
swap = function () {
// set src, alt, css and attribute values
defaultModules.imageSwap.setImageProperties($img, image, tdata.imgSwap.backIsBackgroundImage);
};
if (tdata.fadeSwap) {
$img.fadeOut(function () {
swap(function () {
$img.fadeIn();
});
});
} else
swap();
// increment indexes
tdata.imgSwap.backIndex++;
if (tdata.imgSwap.backIndex >= tdata.backImages.length)
tdata.imgSwap.backIndex = 0;
if (!isList) {
tdata.imgSwap.backStaticIndex++;
if (tdata.imgSwap.backStaticIndex >= tdata.backImages.length)
tdata.imgSwap.backStaticIndex = 0;
} else {
}
}
}
}
};
// object to maintain timer state
$.fn.metrojs.TileTimer = function (interval, callback, repeatCount) {
this.timerId = null; // the id of the current timeout
this.interval = interval; // the amount of time to wait between each action call
this.action = callback; // the method that is fired on each tick
this.count = 0; // the number of times the action has been fired
this.repeatCount = typeof (repeatCount) === "undefined" ? 0 : repeatCount; // the number of times the action will be fired
// call the action method after a delay and call start | stop based on repeat count
this.start = function (delay) {
window.clearTimeout(this.timerId);
var t = this;
this.timerId = window.setTimeout(function () {
t.tick.call(t, interval);
}, delay);
};
this.tick = function (when) {
this.action(this.count + 1);
this.count++;
// reset the loop count
if (this.count >= MAX_LOOP_COUNT)
this.count = 0;
if (this.repeatCount > 0 || this.repeatCount == -1) {
if (this.count != this.repeatCount) {
this.start(when);
} else
this.stop();
}
}
// clear the timer and reset the count
this.stop = function () {
this.timerId = window.clearTimeout(this.timerId);
this.reset();
};
this.resume = function () {
if (this.repeatCount > 0 || this.repeatCount == -1) {
if (this.count != this.repeatCount) {
this.start(interval);
}
}
};
// clear the timer but leave the count intact
this.pause = function () {
this.timerId = window.clearTimeout(this.timerId);
};
// reset count
this.reset = function () {
this.count = 0;
};
// reset count and timer
this.restart = function (delay) {
this.stop();
this.start(delay);
};
};