h5ai-flpsite/src/h5ai/js/inc/jquery.fracs.js
2011-09-04 21:18:19 +02:00

872 lines
29 KiB
JavaScript

/*
* jQuery.fracs 0.10
* http://larsjung.de/fracs
*
* provided under the terms of the MIT License
*/
/*
* ModPlug 0.4
* http://larsjung.de/modplug
*
* provided under the terms of the MIT License
*/
(function ($) {
"use strict";
/*globals jQuery */
/*jslint confusion: true */
var reference = "_mp_api";
$.ModPlug = $.ModPlug || {
plugin: function (namespace, options) {
if (!namespace || $[namespace] || $.fn[namespace]) {
// $.error("No namespace specified, or a plugin already exists on 'jQuery." + namespace + "'");
return !namespace ? 1 : ($[namespace] ? 2 : 3);
}
var defaults = {
statics: {},
methods: {},
defaultStatic: undefined,
defaultMethod: undefined
},
settings = $.extend({}, defaults, options),
staticPlug = function () {
var args, defaultMethod;
args = Array.prototype.slice.call(arguments);
defaultMethod = settings.defaultStatic instanceof Function ? settings.defaultStatic.apply(this, args) : settings.defaultStatic;
if (staticPlug[defaultMethod] instanceof Function) {
return staticPlug[defaultMethod].apply(this, args);
}
$.error("Static method defaulted to '" + defaultMethod + "' does not exist on 'jQuery." + namespace + "'");
},
methods = {},
methodPlug = function (method) {
var args, defaultMethod;
if (methods[method] instanceof Function) {
args = Array.prototype.slice.call(arguments, 1);
return methods[method].apply(this, args);
}
args = Array.prototype.slice.call(arguments);
defaultMethod = settings.defaultMethod instanceof Function ? settings.defaultMethod.apply(this, args) : settings.defaultMethod;
if (methods[defaultMethod] instanceof Function) {
return methods[defaultMethod].apply(this, args);
}
$.error("Method '" + method + "' defaulted to '" + defaultMethod + "' does not exist on 'jQuery." + namespace + "'");
},
api = {
addStatics: function (newStatics) {
$.extend(staticPlug, newStatics);
staticPlug[reference] = api;
return this;
},
addMethods: function (newMethods) {
$.extend(methods, newMethods);
return this;
}
};
api.addStatics(settings.statics).addMethods(settings.methods);
$[namespace] = staticPlug;
$.fn[namespace] = methodPlug;
return 0;
},
module: function (namespace, options) {
if (!$[namespace] || !$[namespace][reference]) {
// $.error("No ModPlug plugin exists on 'jQuery." + namespace + "'");
return !$[namespace] ? 1 : 2;
}
var defaults = {
statics: {},
methods: {}
},
settings = $.extend({}, defaults, options);
$[namespace][reference].addStatics(settings.statics).addMethods(settings.methods);
return 0;
}
};
}(jQuery));
/*
* jQuery.fracs - Core API
*/
(function ($) {
"use strict";
/*globals jQuery, HTMLElement */
/*jslint browser: true, vars: true */
var FracsData = function (htmlElementOrRect) {
var target = htmlElementOrRect,
callbacks = [],
prevFracs;
this.size = function () {
return callbacks.length;
};
this.bind = function (callback) {
if (callback instanceof Function && $.inArray(callback, callbacks) === -1) {
callbacks.push(callback);
}
};
this.unbind = function (callback) {
if (callback instanceof Function) {
var idx = $.inArray(callback, callbacks);
if (idx >= 0) {
callbacks.splice(idx, 1);
}
} else {
callbacks = [];
}
};
this.check = function () {
var rect = target instanceof HTMLElement ? $.fracs.rect(target) : target,
fracs = $.fracs.fracs(rect, $.fracs.viewport());
if (!prevFracs || !prevFracs.equals(fracs)) {
$.each(callbacks, function (idx, callback) {
callback.call(target, fracs, prevFracs);
});
prevFracs = fracs;
}
};
};
var Rect = function (left, top, width, height) {
var fracsData;
this.left = Math.round(left);
this.top = Math.round(top);
this.width = Math.round(width);
this.height = Math.round(height);
this.right = this.left + this.width;
this.bottom = this.top + this.height;
this.equals = function (that) {
return this.left === that.left && this.top === that.top && this.width === that.width && this.height === that.height;
};
this.area = function () {
return this.width * this.height;
};
this.intersection = function (rect) {
var left = Math.max(this.left, rect.left),
right = Math.min(this.right, rect.right),
top = Math.max(this.top, rect.top),
bottom = Math.min(this.bottom, rect.bottom),
width = right - left,
height = bottom - top;
return (width >= 0 && height >= 0) ? new Rect(left, top, width, height) : undefined;
};
this.envelope = function (rect) {
var left = Math.min(this.left, rect.left),
right = Math.max(this.right, rect.right),
top = Math.min(this.top, rect.top),
bottom = Math.max(this.bottom, rect.bottom),
width = right - left,
height = bottom - top;
return new Rect(left, top, width, height);
};
this.bind = function (callback) {
if (!fracsData) {
fracsData = new FracsData(this);
$(window).bind("scroll resize", fracsData.check);
}
fracsData.bind(callback);
};
this.unbind = function (callback) {
if (fracsData) {
fracsData.unbind(callback);
if (fracsData.size() === 0) {
$(window).unbind("scroll resize", fracsData.check);
fracsData = undefined;
}
}
};
this.check = function () {
if (fracsData) {
fracsData.check();
}
};
this.fracs = function () {
$.fracs.fracs(this);
};
};
var FracsResult = function (rectDocument, rectElement, rectViewport, visible, viewport, possible) {
/*jslint confusion: true */
if (!rectDocument || !rectElement || !rectViewport || !visible || !viewport || !possible) {
this.rects = undefined;
this.visible = 0;
this.viewport = 0;
this.possible = 0;
} else {
this.rects = {
document: rectDocument,
element: rectElement,
viewport: rectViewport
};
this.visible = visible;
this.viewport = viewport;
this.possible = possible;
}
this.equals = function (that) {
return this.fracsEqual(that) && this.rectsEqual(that);
};
this.fracsEqual = function (that) {
return this.visible === that.visible && this.viewport === that.viewport && this.possible === that.possible;
};
this.rectsEqual = function (that) {
if (!this.rects || !that.rects) {
return this.rects === that.rects;
}
return this.rects.document.equals(that.rects.document)
&& this.rects.element.equals(that.rects.element)
&& this.rects.viewport.equals(that.rects.viewport);
};
};
var ScrollState = function () {
var document = $.fracs.document(),
viewport = $.fracs.viewport(),
width = document.width - viewport.width,
height = document.height - viewport.height;
this.width = width <= 0 ? undefined : viewport.left / width;
this.height = height <= 0 ? undefined : viewport.top / height;
this.left = viewport.left;
this.top = viewport.top;
this.right = document.right - viewport.right;
this.bottom = document.bottom - viewport.bottom;
this.equals = function (that) {
return this.width === that.width && this.height === that.height
&& this.left === that.left && this.top === that.top
&& this.right === that.right && this.bottom === that.bottom;
};
};
var ScrollStateTracker = function () {
var prevState,
callbacks = [],
check = function () {
var state = new ScrollState();
if (!prevState || !prevState.equals(state)) {
$.each(callbacks, function (idx, callback) {
callback.call(window, state, prevState);
});
prevState = state;
}
};
$(window).bind("resize scroll load", check);
this.bind = function (callback) {
callbacks.push(callback);
};
};
// @beta
var FracsElement = function (htmlElement, fracs) {
this.element = htmlElement;
this.fracs = fracs;
this.update = function () {
var fracs = $.fracs.fracs(this.element),
changed = !this.fracs || !this.fracs.equals(fracs);
this.fracs = fracs;
return changed;
};
};
// @beta
var FracsGroup = function (htmlElements, property, callback) {
var THIS = this,
targets = [],
prevBest = null;
$.each(htmlElements, function (idx, element) {
if (element instanceof HTMLElement) {
targets.push(new FracsElement(element));
}
});
this.check = function () {
var best,
viewport = $.fracs.viewport();
$.each(targets, function (idx, target) {
target.update();
if (!best || target.fracs[property] > best.fracs[property]) {
best = target;
}
});
if (best && best.fracs[property] === 0) {
best = null;
}
if (prevBest !== best) {
callback.call(THIS, best, prevBest);
prevBest = best;
}
};
};
var $document = $(document),
$window = $(window),
$htmlBody = $("html,body"),
scrollStateTracker,
dataNs = "fracs",
statics = {
document: function () {
/*jslint confusion: true */
return new Rect(0, 0, $document.width(), $document.height());
},
viewport: function () {
/*jslint confusion: true */
return new Rect($window.scrollLeft(), $window.scrollTop(), $window.width(), $window.height());
},
rect: function (htmlElement) {
var $target = $(htmlElement),
offset = $target.offset();
if (!$target.is(":visible")) {
return new Rect(0, 0, 0, 0);
}
return new Rect(offset.left, offset.top, $target.outerWidth(), $target.outerHeight());
},
fracs: function (rect, viewport) {
var intersection, intersectionElementSpace, intersectionViewportSpace, intersectionArea, possibleArea;
rect = rect instanceof HTMLElement ? statics.rect(rect) : rect;
viewport = viewport || statics.viewport();
intersection = rect.intersection(viewport);
if (!intersection) {
return new FracsResult();
}
intersectionElementSpace = new Rect(intersection.left - rect.left, intersection.top - rect.top, intersection.width, intersection.height);
intersectionViewportSpace = new Rect(intersection.left - viewport.left, intersection.top - viewport.top, intersection.width, intersection.height);
intersectionArea = intersection.area();
possibleArea = Math.min(rect.width, viewport.width) * Math.min(rect.height, viewport.height);
return new FracsResult(
intersection,
intersectionElementSpace,
intersectionViewportSpace,
intersectionArea / rect.area(),
intersectionArea / viewport.area(),
intersectionArea / possibleArea
);
},
round: function (value, decs) {
if (isNaN(decs) || decs <= 0) {
return Math.round(value);
}
return Math.round(value * Math.pow(10, decs)) / Math.pow(10, decs);
},
scrollTo: function (left, top, duration) {
duration = isNaN(duration) ? 1000 : duration;
$htmlBody.stop(true).animate({ scrollLeft: left, scrollTop: top }, duration);
},
scroll: function (left, top, duration) {
duration = isNaN(duration) ? 1000 : duration;
$htmlBody.stop(true).animate({ scrollLeft: $window.scrollLeft() + left, scrollTop: $window.scrollTop() + top }, duration);
},
scrollState: function (callback) {
if (callback instanceof Function) {
scrollStateTracker = scrollStateTracker || new ScrollStateTracker();
scrollStateTracker.bind(callback);
} else {
return new ScrollState();
}
}
},
methods = {
bind: function (callback) {
return this.each(function () {
var $this = $(this),
data = $this.data(dataNs);
if (!data) {
data = new FracsData(this);
$this.data(dataNs, data);
$window.bind("scroll resize", data.check);
}
data.bind(callback);
});
},
unbind: function (callback) {
return this.each(function () {
var $this = $(this),
data = $this.data(dataNs);
if (data) {
data.unbind(callback);
if (data.size() === 0) {
$this.removeData(dataNs);
$window.unbind("scroll resize", data.check);
}
}
});
},
check: function () {
return this.each(function () {
var data = $(this).data(dataNs);
if (data) {
data.check();
}
});
},
fracs: function () {
return statics.fracs(statics.rect(this.get(0)), statics.viewport());
},
rect: function () {
return statics.rect(this.get(0));
},
max: function (property, callback) {
if (callback instanceof Function) {
var data = new FracsGroup(this, property, callback);
$window.bind("scroll resize", data.check);
data.check();
return this;
} else {
var obj, elements, maxValue;
if ($.inArray(property, [ "possible", "visible", "viewport" ]) >= 0) {
obj = "fracs";
} else if ($.inArray(property, [ "width", "height", "left", "right", "top", "bottom" ]) >= 0) {
obj = "rect";
} else {
return this;
}
this.each(function () {
var fracs = statics[obj](this);
if (!maxValue || fracs[property] > maxValue) {
elements = [ this ];
maxValue = fracs[property];
} else if (fracs[property] === maxValue) {
elements.push(this);
}
});
return $(elements);
}
},
min: function (property) {
var obj, elements, minValue;
if ($.inArray(property, [ "possible", "visible", "viewport" ]) >= 0) {
obj = "fracs";
} else if ($.inArray(property, [ "width", "height", "left", "right", "top", "bottom" ]) >= 0) {
obj = "rect";
} else {
return this;
}
this.each(function () {
var fracs = statics[obj](this);
if (!minValue || fracs[property] < minValue) {
elements = [ this ];
minValue = fracs[property];
} else if (fracs[property] === minValue) {
elements.push(this);
}
});
return $(elements);
},
envelope: function () {
var envelope, rect;
this.each(function () {
rect = statics.rect(this);
envelope = !envelope ? rect : envelope.envelope(rect);
});
return envelope;
},
scrollTo: function (paddingLeft, paddingTop, duration) {
var rect;
paddingLeft = paddingLeft || 0;
paddingTop = paddingTop || 0;
rect = statics.rect(this.get(0));
statics.scrollTo(rect.left - paddingLeft, rect.top - paddingTop, duration);
return this;
},
softLink: function (paddingLeft, paddingTop, duration) {
return this.filter("a[href^=#]").each(function () {
var $a = $(this),
href = $a.attr("href");
$a.click(function () {
$(href).fracs("scrollTo", paddingLeft, paddingTop, duration);
});
});
}
},
defaultStatic = function () {
return "fracs";
},
defaultMethod = function () {
if (arguments.length === 0) {
return "fracs";
} else if (arguments[0] instanceof Function) {
return "bind";
}
};
$.ModPlug.plugin("fracs", {
statics: statics,
methods: methods,
defaultStatic: defaultStatic,
defaultMethod: defaultMethod
});
}(jQuery));
/*
* jQuery.fracs - Outline API
*/
(function ($) {
"use strict";
/*globals jQuery */
/*jslint browser: true, vars: true */
var Outline = function (canvas, options) {
if (!(canvas instanceof HTMLElement && canvas.nodeName.toLowerCase() === "canvas")) {
return undefined;
}
var defaults = {
crop: false,
duration: 0,
focusWidth: 0.5,
focusHeight: 0.5,
autoFocus: true,
styles: [ {
selector: "header,footer,section,article",
fillStyle: "rgb(230,230,230)"
}, {
selector: "h1",
fillStyle: "rgb(240,140,060)"
}, {
selector: "h2",
fillStyle: "rgb(200,100,100)"
}, {
selector: "h3",
fillStyle: "rgb(100,200,100)"
}, {
selector: "h4",
fillStyle: "rgb(100,100,200)"
} ],
viewportStyle: {
fillStyle: "rgba(228,77,38,0.3)"
},
viewportDragStyle: {
fillStyle: "rgba(228,77,38,0.6)"
},
invertViewport: false
},
settings = $.extend({}, defaults, options),
$window = $(window),
$htmlBody = $("html,body"),
$canvas = $(canvas),
width = $canvas.attr("width"),
height = $canvas.attr("height"),
context = canvas.getContext("2d"),
docRect,
vpRect,
scale,
drag = false,
focusWidth,
focusHeight,
scroll = function (event) {
var r, x, y;
r = $canvas.fracs("rect");
x = event.pageX - r.left;
y = event.pageY - r.top;
$.fracs.scrollTo(x / scale - vpRect.width * focusWidth, y / scale - vpRect.height * focusHeight, settings.duration);
},
drawRect = function (context, rect, strokeWidth, strokeStyle, fillStyle, invert) {
if (strokeWidth !== undefined && scale) {
strokeWidth = strokeWidth > 0.2 / scale ? strokeWidth : 0.2 / scale;
}
if (strokeStyle || fillStyle) {
if (invert !== true) {
context.beginPath();
context.rect(rect.left, rect.top, rect.width, rect.height);
if (fillStyle) {
context.fillStyle = fillStyle;
context.fill();
}
if (strokeStyle) {
context.lineWidth = strokeWidth;
context.strokeStyle = strokeStyle;
context.stroke();
}
} else {
if (fillStyle) {
context.beginPath();
context.rect(0, 0, docRect.width, rect.top);
context.rect(0, rect.top, rect.left, rect.height);
context.rect(rect.right, rect.top, docRect.right - rect.right, rect.height);
context.rect(0, rect.bottom, docRect.width, docRect.bottom - rect.bottom);
context.fillStyle = fillStyle;
context.fill();
}
if (strokeStyle) {
context.beginPath();
context.rect(rect.left, rect.top, rect.width, rect.height);
context.lineWidth = strokeWidth;
context.strokeStyle = strokeStyle;
context.stroke();
}
}
}
},
drawElement = function (context, htmlElement, strokeWidth, strokeStyle, fillStyle) {
var $element = $(htmlElement),
rect = $element.fracs("rect");
if ($element.css("visibility") === "hidden") {
return;
}
strokeWidth = strokeWidth === "auto" ? $element.css("border-top-width") : strokeWidth;
strokeStyle = strokeStyle === "auto" ? $element.css("border-top-color") : strokeStyle;
fillStyle = fillStyle === "auto" ? $element.css("background-color") : fillStyle;
drawRect(context, rect, strokeWidth, strokeStyle, fillStyle);
},
drawViewport = function () {
var strokeWidth, strokeStyle, fillStyle;
if (drag && settings.viewportDragStyle) {
strokeWidth = settings.viewportDragStyle.storkeWidth;
strokeStyle = settings.viewportDragStyle.strokeStyle;
fillStyle = settings.viewportDragStyle.fillStyle;
} else {
strokeWidth = settings.viewportStyle.storkeWidth;
strokeStyle = settings.viewportStyle.strokeStyle;
fillStyle = settings.viewportStyle.fillStyle;
}
drawRect(context, vpRect, strokeWidth, strokeStyle, fillStyle, settings.invertViewport);
},
applyStyles = function (context) {
$.each(settings.styles, function (idx, style) {
$(style.selector).each(function () {
drawElement(context, this, style.strokeWidth, style.strokeStyle, style.fillStyle);
});
});
},
draw = function () {
/*jslint confusion: true */
var scaleX, scaleY;
docRect = $.fracs.document();
vpRect = $.fracs.viewport();
scaleX = width / docRect.width;
scaleY = height / docRect.height;
scale = scaleX < scaleY ? scaleX : scaleY;
if (settings.crop) {
$canvas.attr("width", docRect.width * scale).attr("height", docRect.height * scale);
}
context.clearRect(0, 0, $canvas.width(), $canvas.height());
context.scale(scale, scale);
applyStyles(context);
drawViewport();
context.scale(1 / scale, 1 / scale);
},
init = function () {
$canvas
.css("cursor", "pointer")
.mousedown(function (event) {
var r;
event.preventDefault();
drag = true;
if (settings.autoFocus) {
r = $canvas.fracs("rect");
focusWidth = (((event.pageX - r.left) / scale) - vpRect.left) / vpRect.width;
focusHeight = (((event.pageY - r.top) / scale) - vpRect.top) / vpRect.height;
}
if (!settings.autoFocus || focusWidth < 0 || focusWidth > 1 || focusHeight < 0 || focusHeight > 1) {
focusWidth = settings.focusWidth;
focusHeight = settings.focusHeight;
}
scroll(event);
$canvas.css("cursor", "crosshair").addClass("dragOn");
$htmlBody.css("cursor", "crosshair");
$window
.bind("mousemove", scroll)
.one("mouseup", function (event) {
event.preventDefault();
$canvas.css("cursor", "pointer").removeClass("dragOn");
$htmlBody.css("cursor", "auto");
$window.unbind("mousemove", scroll);
drag = false;
draw();
});
});
canvas.onselectstart = function () {
return false;
};
$window.bind("load resize scroll", draw);
draw();
};
init();
this.draw = draw;
};
var dataNs = "outline",
methods = {
outline: function (options) {
return this.each(function () {
var outline;
if (options === "redraw") {
outline = $(this).data(dataNs);
if (outline) {
outline.draw();
}
} else {
outline = new Outline(this, options);
if (outline) {
$(this).data(dataNs, outline);
}
}
});
}
};
$.ModPlug.module("fracs", {
methods: methods
});
}(jQuery));