/* Copyright 2008-2013 Clipperz Srl This file is part of Clipperz, the online password manager. For further information about its features and functionalities please refer to http://www.clipperz.com. * Clipperz is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * Clipperz is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License along with Clipperz. If not, see http://www.gnu.org/licenses/. */ /*** MochiKit.Visual 1.5 See for documentation, downloads, license, etc. (c) 2005 Bob Ippolito and others. All rights Reserved. ***/ MochiKit.Base.module(MochiKit, 'Visual', '1.5', ['Base', 'DOM', 'Style', 'Color', 'Position']); MochiKit.Visual._RoundCorners = function (e, options) { e = MochiKit.DOM.getElement(e); this._setOptions(options); if (this.options.__unstable__wrapElement) { e = this._doWrap(e); } var color = this.options.color; var C = MochiKit.Color.Color; if (this.options.color === "fromElement") { color = C.fromBackground(e); } else if (!(color instanceof C)) { color = C.fromString(color); } this.isTransparent = (color.asRGB().a <= 0); var bgColor = this.options.bgColor; if (this.options.bgColor === "fromParent") { bgColor = C.fromBackground(e.offsetParent); } else if (!(bgColor instanceof C)) { bgColor = C.fromString(bgColor); } this._roundCornersImpl(e, color, bgColor); }; MochiKit.Visual._RoundCorners.prototype = { _doWrap: function (e) { var parent = e.parentNode; var doc = MochiKit.DOM.currentDocument(); if (typeof(doc.defaultView) === "undefined" || doc.defaultView === null) { return e; } var style = doc.defaultView.getComputedStyle(e, null); if (typeof(style) === "undefined" || style === null) { return e; } var wrapper = MochiKit.DOM.DIV({"style": { display: "block", // convert padding to margin marginTop: style.getPropertyValue("padding-top"), marginRight: style.getPropertyValue("padding-right"), marginBottom: style.getPropertyValue("padding-bottom"), marginLeft: style.getPropertyValue("padding-left"), // remove padding so the rounding looks right padding: "0px" /* paddingRight: "0px", paddingLeft: "0px" */ }}); wrapper.innerHTML = e.innerHTML; e.innerHTML = ""; e.appendChild(wrapper); return e; }, _roundCornersImpl: function (e, color, bgColor) { if (this.options.border) { this._renderBorder(e, bgColor); } if (this._isTopRounded()) { this._roundTopCorners(e, color, bgColor); } if (this._isBottomRounded()) { this._roundBottomCorners(e, color, bgColor); } }, _renderBorder: function (el, bgColor) { var borderValue = "1px solid " + this._borderColor(bgColor); var borderL = "border-left: " + borderValue; var borderR = "border-right: " + borderValue; var style = "style='" + borderL + ";" + borderR + "'"; el.innerHTML = "
" + el.innerHTML + "
"; }, _roundTopCorners: function (el, color, bgColor) { var corner = this._createCorner(bgColor); for (var i = 0; i < this.options.numSlices; i++) { corner.appendChild( this._createCornerSlice(color, bgColor, i, "top") ); } el.style.paddingTop = 0; el.insertBefore(corner, el.firstChild); }, _roundBottomCorners: function (el, color, bgColor) { var corner = this._createCorner(bgColor); for (var i = (this.options.numSlices - 1); i >= 0; i--) { corner.appendChild( this._createCornerSlice(color, bgColor, i, "bottom") ); } el.style.paddingBottom = 0; el.appendChild(corner); }, _createCorner: function (bgColor) { var dom = MochiKit.DOM; return dom.DIV({style: {backgroundColor: bgColor.toString()}}); }, _createCornerSlice: function (color, bgColor, n, position) { var slice = MochiKit.DOM.SPAN(); var inStyle = slice.style; inStyle.backgroundColor = color.toString(); inStyle.display = "block"; inStyle.height = "1px"; inStyle.overflow = "hidden"; inStyle.fontSize = "1px"; var borderColor = this._borderColor(color, bgColor); if (this.options.border && n === 0) { inStyle.borderTopStyle = "solid"; inStyle.borderTopWidth = "1px"; inStyle.borderLeftWidth = "0px"; inStyle.borderRightWidth = "0px"; inStyle.borderBottomWidth = "0px"; // assumes css compliant box model inStyle.height = "0px"; inStyle.borderColor = borderColor.toString(); } else if (borderColor) { inStyle.borderColor = borderColor.toString(); inStyle.borderStyle = "solid"; inStyle.borderWidth = "0px 1px"; } if (!this.options.compact && (n == (this.options.numSlices - 1))) { inStyle.height = "2px"; } this._setMargin(slice, n, position); this._setBorder(slice, n, position); return slice; }, _setOptions: function (options) { this.options = { corners: "all", color: "fromElement", bgColor: "fromParent", blend: true, border: false, compact: false, __unstable__wrapElement: false }; MochiKit.Base.update(this.options, options); this.options.numSlices = (this.options.compact ? 2 : 4); }, _whichSideTop: function () { var corners = this.options.corners; if (this._hasString(corners, "all", "top")) { return ""; } var has_tl = (corners.indexOf("tl") != -1); var has_tr = (corners.indexOf("tr") != -1); if (has_tl && has_tr) { return ""; } if (has_tl) { return "left"; } if (has_tr) { return "right"; } return ""; }, _whichSideBottom: function () { var corners = this.options.corners; if (this._hasString(corners, "all", "bottom")) { return ""; } var has_bl = (corners.indexOf('bl') != -1); var has_br = (corners.indexOf('br') != -1); if (has_bl && has_br) { return ""; } if (has_bl) { return "left"; } if (has_br) { return "right"; } return ""; }, _borderColor: function (color, bgColor) { if (color == "transparent") { return bgColor; } else if (this.options.border) { return this.options.border; } else if (this.options.blend) { return bgColor.blendedColor(color); } return ""; }, _setMargin: function (el, n, corners) { var marginSize = this._marginSize(n) + "px"; var whichSide = ( corners == "top" ? this._whichSideTop() : this._whichSideBottom() ); var style = el.style; if (whichSide == "left") { style.marginLeft = marginSize; style.marginRight = "0px"; } else if (whichSide == "right") { style.marginRight = marginSize; style.marginLeft = "0px"; } else { style.marginLeft = marginSize; style.marginRight = marginSize; } }, _setBorder: function (el, n, corners) { var borderSize = this._borderSize(n) + "px"; var whichSide = ( corners == "top" ? this._whichSideTop() : this._whichSideBottom() ); var style = el.style; if (whichSide == "left") { style.borderLeftWidth = borderSize; style.borderRightWidth = "0px"; } else if (whichSide == "right") { style.borderRightWidth = borderSize; style.borderLeftWidth = "0px"; } else { style.borderLeftWidth = borderSize; style.borderRightWidth = borderSize; } }, _marginSize: function (n) { if (this.isTransparent) { return 0; } var o = this.options; if (o.compact && o.blend) { var smBlendedMarginSizes = [1, 0]; return smBlendedMarginSizes[n]; } else if (o.compact) { var compactMarginSizes = [2, 1]; return compactMarginSizes[n]; } else if (o.blend) { var blendedMarginSizes = [3, 2, 1, 0]; return blendedMarginSizes[n]; } else { var marginSizes = [5, 3, 2, 1]; return marginSizes[n]; } }, _borderSize: function (n) { var o = this.options; var borderSizes; if (o.compact && (o.blend || this.isTransparent)) { return 1; } else if (o.compact) { borderSizes = [1, 0]; } else if (o.blend) { borderSizes = [2, 1, 1, 1]; } else if (o.border) { borderSizes = [0, 2, 0, 0]; } else if (this.isTransparent) { borderSizes = [5, 3, 2, 1]; } else { return 0; } return borderSizes[n]; }, _hasString: function (str) { for (var i = 1; i< arguments.length; i++) { if (str.indexOf(arguments[i]) != -1) { return true; } } return false; }, _isTopRounded: function () { return this._hasString(this.options.corners, "all", "top", "tl", "tr" ); }, _isBottomRounded: function () { return this._hasString(this.options.corners, "all", "bottom", "bl", "br" ); }, _hasSingleTextChild: function (el) { return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3); } }; /** @id MochiKit.Visual.roundElement */ MochiKit.Visual.roundElement = function (e, options) { new MochiKit.Visual._RoundCorners(e, options); }; /** @id MochiKit.Visual.roundClass */ MochiKit.Visual.roundClass = function (tagName, className, options) { var elements = MochiKit.DOM.getElementsByTagAndClassName( tagName, className ); for (var i = 0; i < elements.length; i++) { MochiKit.Visual.roundElement(elements[i], options); } }; /** @id MochiKit.Visual.tagifyText */ MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) { /*** Change a node text to character in tags. @param tagifyStyle: the style to apply to character nodes, default to 'position: relative'. ***/ tagifyStyle = tagifyStyle || 'position:relative'; if (/MSIE/.test(navigator.userAgent)) { tagifyStyle += ';zoom:1'; } element = MochiKit.DOM.getElement(element); var ma = MochiKit.Base.map; ma(function (child) { if (child.nodeType == 3) { ma(function (character) { element.insertBefore( MochiKit.DOM.SPAN({style: tagifyStyle}, character == ' ' ? String.fromCharCode(160) : character), child); }, child.nodeValue.split('')); MochiKit.DOM.removeElement(child); } }, element.childNodes); }; MochiKit.Visual._forceRerendering = function (element) { try { element = MochiKit.DOM.getElement(element); var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch(e) { } }; /** @id MochiKit.Visual.multiple */ MochiKit.Visual.multiple = function (elements, effect, /* optional */options) { /*** Launch the same effect subsequently on given elements. ***/ options = MochiKit.Base.update({ speed: 0.1, delay: 0.0 }, options); var masterDelay = options.delay; var index = 0; MochiKit.Base.map(function (innerelement) { options.delay = index * options.speed + masterDelay; new effect(innerelement, options); index += 1; }, elements); }; MochiKit.Visual.PAIRS = { 'slide': ['slideDown', 'slideUp'], 'blind': ['blindDown', 'blindUp'], 'appear': ['appear', 'fade'], 'size': ['grow', 'shrink'] }; /** @id MochiKit.Visual.toggle */ MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) { /*** Toggle an item between two state depending of its visibility, making a effect between these states. Default effect is 'appear', can be 'slide' or 'blind'. ***/ element = MochiKit.DOM.getElement(element); effect = (effect || 'appear').toLowerCase(); options = MochiKit.Base.update({ queue: {position: 'end', scope: (element.id || 'global'), limit: 1} }, options); var v = MochiKit.Visual; v[MochiKit.Style.getStyle(element, 'display') != 'none' ? v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options); }; /*** Transitions: define functions calculating variations depending of a position. ***/ MochiKit.Visual.Transitions = { __export__: false }; /** @id MochiKit.Visual.Transitions.linear */ MochiKit.Visual.Transitions.linear = function (pos) { return pos; }; /** @id MochiKit.Visual.Transitions.sinoidal */ MochiKit.Visual.Transitions.sinoidal = function (pos) { return 0.5 - Math.cos(pos*Math.PI)/2; }; /** @id MochiKit.Visual.Transitions.reverse */ MochiKit.Visual.Transitions.reverse = function (pos) { return 1 - pos; }; /** @id MochiKit.Visual.Transitions.flicker */ MochiKit.Visual.Transitions.flicker = function (pos) { return 0.25 - Math.cos(pos*Math.PI)/4 + Math.random()/2; }; /** @id MochiKit.Visual.Transitions.wobble */ MochiKit.Visual.Transitions.wobble = function (pos) { return 0.5 - Math.cos(9*pos*Math.PI)/2; }; /** @id MochiKit.Visual.Transitions.pulse */ MochiKit.Visual.Transitions.pulse = function (pos, pulses) { if (pulses) { pos *= 2 * pulses; } else { pos *= 10; } var decimals = pos - Math.floor(pos); return (Math.floor(pos) % 2 == 0) ? decimals : 1 - decimals; }; /** @id MochiKit.Visual.Transitions.parabolic */ MochiKit.Visual.Transitions.parabolic = function (pos) { return pos * pos; }; /** @id MochiKit.Visual.Transitions.spring */ MochiKit.Visual.Transitions.spring = function (pos) { return 1 - (Math.cos(pos * 2.5 * Math.PI) * Math.exp(-pos * 6)); }; /** @id MochiKit.Visual.Transitions.none */ MochiKit.Visual.Transitions.none = function (pos) { return 0; }; /** @id MochiKit.Visual.Transitions.full */ MochiKit.Visual.Transitions.full = function (pos) { return 1; }; /*** Core effects ***/ MochiKit.Visual.ScopedQueue = function () { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(); } this.__init__(); }; MochiKit.Visual.ScopedQueue.__export__ = false; MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, { __init__: function () { this.effects = []; this.interval = null; }, /** @id MochiKit.Visual.ScopedQueue.prototype.add */ add: function (effect) { var timestamp = new Date().getTime(); var position = (typeof(effect.options.queue) == 'string') ? effect.options.queue : effect.options.queue.position; var ma = MochiKit.Base.map; switch (position) { case 'front': // move unstarted effects after this effect ma(function (e) { if (e.state == 'idle') { e.startOn += effect.finishOn; e.finishOn += effect.finishOn; } }, this.effects); break; case 'end': var finish; // start effect after last queued effect has finished ma(function (e) { var i = e.finishOn; if (i >= (finish || i)) { finish = i; } }, this.effects); timestamp = finish || timestamp; break; case 'break': ma(function (e) { e.finalize(); }, this.effects); break; case 'replace': ma(function (e) { e.cancel(); }, this.effects); break; } effect.startOn += timestamp; effect.finishOn += timestamp; if (!effect.options.queue.limit || this.effects.length < effect.options.queue.limit) { this.effects.push(effect); } if (!this.interval) { this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this), 40); } }, /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */ startLoop: function (func, interval) { return setInterval(func, interval); }, /** @id MochiKit.Visual.ScopedQueue.prototype.remove */ remove: function (effect) { this.effects = MochiKit.Base.filter(function (e) { return e != effect; }, this.effects); if (!this.effects.length) { this.stopLoop(this.interval); this.interval = null; } }, /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */ stopLoop: function (interval) { clearInterval(interval); }, /** @id MochiKit.Visual.ScopedQueue.prototype.loop */ loop: function () { var timePos = new Date().getTime(); MochiKit.Base.map(function (effect) { effect.loop(timePos); }, this.effects); } }); MochiKit.Visual.Queues = { __export__: false, instances: {}, get: function (queueName) { if (typeof(queueName) != 'string') { return queueName; } if (!this.instances[queueName]) { this.instances[queueName] = new MochiKit.Visual.ScopedQueue(); } return this.instances[queueName]; } }; MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global'); MochiKit.Visual.Queue.__export__ = false; MochiKit.Visual.DefaultOptions = { __export__: false, transition: MochiKit.Visual.Transitions.sinoidal, duration: 1.0, // seconds fps: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation sync: false, // true for combining from: 0.0, to: 1.0, delay: 0.0, queue: 'parallel' }; MochiKit.Visual.Base = function () {}; MochiKit.Visual.Base.prototype = { /*** Basic class for all Effects. Define a looping mechanism called for each step of an effect. Don't instantiate it, only subclass it. ***/ __class__ : MochiKit.Visual.Base, /** @id MochiKit.Visual.Base.prototype.start */ start: function (options) { var v = MochiKit.Visual; this.options = MochiKit.Base.setdefault(options, v.DefaultOptions); this.currentFrame = 0; this.state = 'idle'; this.startOn = this.options.delay*1000; this.finishOn = this.startOn + (this.options.duration*1000); this.event('beforeStart'); if (!this.options.sync) { v.Queues.get(typeof(this.options.queue) == 'string' ? 'global' : this.options.queue.scope).add(this); } }, /** @id MochiKit.Visual.Base.prototype.loop */ loop: function (timePos) { if (timePos >= this.startOn) { if (timePos >= this.finishOn) { return this.finalize(); } var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); var frame = Math.round(pos * this.options.fps * this.options.duration); if (frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } } }, /** @id MochiKit.Visual.Base.prototype.render */ render: function (pos) { if (this.state == 'idle') { this.state = 'running'; this.event('beforeSetup'); this.setup(); this.event('afterSetup'); } if (this.state == 'running') { var trans = this.options.transition; if (typeof(trans) == "string") { trans = MochiKit.Visual.Transitions[trans]; } if (typeof(trans) == "function") { pos = trans(pos); } pos *= (this.options.to - this.options.from); pos += this.options.from; this.event('beforeUpdate'); this.update(pos); this.event('afterUpdate'); } }, /** @id MochiKit.Visual.Base.prototype.cancel */ cancel: function () { if (!this.options.sync) { MochiKit.Visual.Queues.get(typeof(this.options.queue) == 'string' ? 'global' : this.options.queue.scope).remove(this); } this.state = 'finished'; }, /** @id MochiKit.Visual.Base.prototype.finalize */ finalize: function () { this.render(1.0); this.cancel(); this.event('beforeFinish'); this.finish(); this.event('afterFinish'); }, setup: function () { }, finish: function () { }, update: function (position) { }, /** @id MochiKit.Visual.Base.prototype.event */ event: function (eventName) { if (this.options[eventName + 'Internal']) { this.options[eventName + 'Internal'](this); } if (this.options[eventName]) { this.options[eventName](this); } }, /** @id MochiKit.Visual.Base.prototype.repr */ repr: function () { return '[' + this.__class__.NAME + ', options:' + MochiKit.Base.repr(this.options) + ']'; } }; /** @id MochiKit.Visual.Parallel */ MochiKit.Visual.Parallel = function (effects, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(effects, options); } this.__init__(effects, options); }; MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, { /*** Run multiple effects at the same time. ***/ __class__ : MochiKit.Visual.Parallel, __init__: function (effects, options) { this.effects = effects || []; this.start(options); }, /** @id MochiKit.Visual.Parallel.prototype.update */ update: function (position) { MochiKit.Base.map(function (effect) { effect.render(position); }, this.effects); }, /** @id MochiKit.Visual.Parallel.prototype.finish */ finish: function () { MochiKit.Base.map(function (effect) { effect.finalize(); }, this.effects); } }); /** @id MochiKit.Visual.Sequence */ MochiKit.Visual.Sequence = function (effects, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(effects, options); } this.__init__(effects, options); }; MochiKit.Visual.Sequence.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Sequence.prototype, { __class__ : MochiKit.Visual.Sequence, __init__: function (effects, options) { var defs = { transition: MochiKit.Visual.Transitions.linear, duration: 0 }; this.effects = effects || []; MochiKit.Base.map(function (effect) { defs.duration += effect.options.duration; }, this.effects); MochiKit.Base.setdefault(options, defs); this.start(options); }, /** @id MochiKit.Visual.Sequence.prototype.update */ update: function (position) { var time = position * this.options.duration; for (var i = 0; i < this.effects.length; i++) { var effect = this.effects[i]; if (time <= effect.options.duration) { effect.render(time / effect.options.duration); break; } else { time -= effect.options.duration; } } }, /** @id MochiKit.Visual.Sequence.prototype.finish */ finish: function () { MochiKit.Base.map(function (effect) { effect.finalize(); }, this.effects); } }); /** @id MochiKit.Visual.Opacity */ MochiKit.Visual.Opacity = function (element, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, options); } this.__init__(element, options); }; MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, { /*** Change the opacity of an element. @param options: 'from' and 'to' change the starting and ending opacities. Must be between 0.0 and 1.0. Default to current opacity and 1.0. ***/ __class__ : MochiKit.Visual.Opacity, __init__: function (element, /* optional */options) { var b = MochiKit.Base; var s = MochiKit.Style; this.element = MochiKit.DOM.getElement(element); // make this work on IE on elements without 'layout' if (this.element.currentStyle && (!this.element.currentStyle.hasLayout)) { s.setStyle(this.element, {zoom: 1}); } options = b.update({ from: s.getStyle(this.element, 'opacity') || 0.0, to: 1.0 }, options); this.start(options); }, /** @id MochiKit.Visual.Opacity.prototype.update */ update: function (position) { MochiKit.Style.setStyle(this.element, {'opacity': position}); } }); /** @id MochiKit.Visual.Move.prototype */ MochiKit.Visual.Move = function (element, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, options); } this.__init__(element, options); }; MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Move.prototype, { /*** Move an element between its current position to a defined position @param options: 'x' and 'y' for final positions, default to 0, 0. ***/ __class__ : MochiKit.Visual.Move, __init__: function (element, /* optional */options) { this.element = MochiKit.DOM.getElement(element); options = MochiKit.Base.update({ x: 0, y: 0, mode: 'relative' }, options); this.start(options); }, /** @id MochiKit.Visual.Move.prototype.setup */ setup: function () { // Bug in Opera: Opera returns the 'real' position of a static element // or relative element that does not have top/left explicitly set. // ==> Always set top and left for position relative elements in your // stylesheets (to 0 if you do not need them) MochiKit.Style.makePositioned(this.element); var s = this.element.style; var originalVisibility = s.visibility; var originalDisplay = s.display; if (originalDisplay == 'none') { s.visibility = 'hidden'; s.display = ''; } this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0'); this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0'); if (this.options.mode == 'absolute') { // absolute movement, so we need to calc deltaX and deltaY this.options.x -= this.originalLeft; this.options.y -= this.originalTop; } if (originalDisplay == 'none') { s.visibility = originalVisibility; s.display = originalDisplay; } }, /** @id MochiKit.Visual.Move.prototype.update */ update: function (position) { MochiKit.Style.setStyle(this.element, { left: Math.round(this.options.x * position + this.originalLeft) + 'px', top: Math.round(this.options.y * position + this.originalTop) + 'px' }); } }); /** @id MochiKit.Visual.Scale */ MochiKit.Visual.Scale = function (element, percent, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, percent, options); } this.__init__(element, percent, options); }; MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Scale.prototype, { /*** Change the size of an element. @param percent: final_size = percent*original_size @param options: several options changing scale behaviour ***/ __class__ : MochiKit.Visual.Scale, __init__: function (element, percent, /* optional */options) { this.element = MochiKit.DOM.getElement(element); options = MochiKit.Base.update({ scaleX: true, scaleY: true, scaleContent: true, scaleFromCenter: false, scaleMode: 'box', // 'box' or 'contents' or {} with provided values scaleFrom: 100.0, scaleTo: percent }, options); this.start(options); }, /** @id MochiKit.Visual.Scale.prototype.setup */ setup: function () { this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = MochiKit.Style.getStyle(this.element, 'position'); var ma = MochiKit.Base.map; var b = MochiKit.Base.bind; this.originalStyle = {}; ma(b(function (k) { this.originalStyle[k] = this.element.style[k]; }, this), ['top', 'left', 'width', 'height', 'fontSize']); this.originalTop = this.element.offsetTop; this.originalLeft = this.element.offsetLeft; var fontSize = MochiKit.Style.getStyle(this.element, 'font-size') || '100%'; ma(b(function (fontSizeType) { if (fontSize.indexOf(fontSizeType) > 0) { this.fontSize = parseFloat(fontSize); this.fontSizeType = fontSizeType; } }, this), ['em', 'px', '%']); this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; if (/^content/.test(this.options.scaleMode)) { this.dims = [this.element.scrollHeight, this.element.scrollWidth]; } else if (this.options.scaleMode == 'box') { this.dims = [this.element.offsetHeight, this.element.offsetWidth]; } else { this.dims = [this.options.scaleMode.originalHeight, this.options.scaleMode.originalWidth]; } }, /** @id MochiKit.Visual.Scale.prototype.update */ update: function (position) { var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); if (this.options.scaleContent && this.fontSize) { MochiKit.Style.setStyle(this.element, { fontSize: this.fontSize * currentScale + this.fontSizeType }); } this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); }, /** @id MochiKit.Visual.Scale.prototype.finish */ finish: function () { if (this.restoreAfterFinish) { MochiKit.Style.setStyle(this.element, this.originalStyle); } }, /** @id MochiKit.Visual.Scale.prototype.setDimensions */ setDimensions: function (height, width) { var d = {}; var r = Math.round; if (/MSIE/.test(navigator.userAgent)) { r = Math.ceil; } if (this.options.scaleX) { d.width = r(width) + 'px'; } if (this.options.scaleY) { d.height = r(height) + 'px'; } if (this.options.scaleFromCenter) { var topd = (height - this.dims[0])/2; var leftd = (width - this.dims[1])/2; if (this.elementPositioning == 'absolute') { if (this.options.scaleY) { d.top = this.originalTop - topd + 'px'; } if (this.options.scaleX) { d.left = this.originalLeft - leftd + 'px'; } } else { if (this.options.scaleY) { d.top = -topd + 'px'; } if (this.options.scaleX) { d.left = -leftd + 'px'; } } } MochiKit.Style.setStyle(this.element, d); } }); /** @id MochiKit.Visual.Highlight */ MochiKit.Visual.Highlight = function (element, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, options); } this.__init__(element, options); }; MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, { /*** Highlight an item of the page. @param options: 'startcolor' for choosing highlighting color, default to '#ffff99'. ***/ __class__ : MochiKit.Visual.Highlight, __init__: function (element, /* optional */options) { this.element = MochiKit.DOM.getElement(element); options = MochiKit.Base.update({ startcolor: '#ffff99' }, options); this.start(options); }, /** @id MochiKit.Visual.Highlight.prototype.setup */ setup: function () { var b = MochiKit.Base; var s = MochiKit.Style; // Prevent executing on elements not in the layout flow if (s.getStyle(this.element, 'display') == 'none') { this.cancel(); return; } // Disable background image during the effect this.oldStyle = { backgroundImage: s.getStyle(this.element, 'background-image') }; s.setStyle(this.element, { backgroundImage: 'none' }); if (!this.options.endcolor) { this.options.endcolor = MochiKit.Color.Color.fromBackground(this.element).toHexString(); } if (b.isUndefinedOrNull(this.options.restorecolor)) { this.options.restorecolor = s.getStyle(this.element, 'background-color'); } // init color calculations this._base = b.map(b.bind(function (i) { return parseInt( this.options.startcolor.slice(i*2 + 1, i*2 + 3), 16); }, this), [0, 1, 2]); this._delta = b.map(b.bind(function (i) { return parseInt(this.options.endcolor.slice(i*2 + 1, i*2 + 3), 16) - this._base[i]; }, this), [0, 1, 2]); }, /** @id MochiKit.Visual.Highlight.prototype.update */ update: function (position) { var m = '#'; MochiKit.Base.map(MochiKit.Base.bind(function (i) { m += MochiKit.Color.toColorPart(Math.round(this._base[i] + this._delta[i]*position)); }, this), [0, 1, 2]); MochiKit.Style.setStyle(this.element, { backgroundColor: m }); }, /** @id MochiKit.Visual.Highlight.prototype.finish */ finish: function () { MochiKit.Style.setStyle(this.element, MochiKit.Base.update(this.oldStyle, { backgroundColor: this.options.restorecolor })); } }); /** @id MochiKit.Visual.ScrollTo */ MochiKit.Visual.ScrollTo = function (element, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, options); } this.__init__(element, options); }; MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, { /*** Scroll to an element in the page. ***/ __class__ : MochiKit.Visual.ScrollTo, __init__: function (element, /* optional */options) { this.element = MochiKit.DOM.getElement(element); this.start(options); }, /** @id MochiKit.Visual.ScrollTo.prototype.setup */ setup: function () { var p = MochiKit.Position; p.prepare(); var offsets = p.cumulativeOffset(this.element); if (this.options.offset) { offsets.y += this.options.offset; } var max; if (window.innerHeight) { max = window.innerHeight - window.height; } else if (document.documentElement && document.documentElement.clientHeight) { max = document.documentElement.clientHeight - document.body.scrollHeight; } else if (document.body) { max = document.body.clientHeight - document.body.scrollHeight; } this.scrollStart = p.windowOffset.y; this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart; }, /** @id MochiKit.Visual.ScrollTo.prototype.update */ update: function (position) { var p = MochiKit.Position; p.prepare(); window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta)); } }); MochiKit.Visual._CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; MochiKit.Visual.Morph = function (element, options) { var cls = arguments.callee; if (!(this instanceof cls)) { return new cls(element, options); } this.__init__(element, options); }; MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base(); MochiKit.Base.update(MochiKit.Visual.Morph.prototype, { /*** Morph effect: make a transformation from current style to the given style, automatically making a transition between the two. ***/ __class__ : MochiKit.Visual.Morph, __init__: function (element, /* optional */options) { this.element = MochiKit.DOM.getElement(element); this.start(options); }, /** @id MochiKit.Visual.Morph.prototype.setup */ setup: function () { var b = MochiKit.Base; var style = this.options.style; this.styleStart = {}; this.styleEnd = {}; this.units = {}; var value, unit; for (var s in style) { value = style[s]; s = b.camelize(s); if (MochiKit.Visual._CSS_LENGTH.test(value)) { var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); unit = (components.length == 3) ? components[2] : null; this.styleEnd[s] = value; this.units[s] = unit; value = MochiKit.Style.getStyle(this.element, s); components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); this.styleStart[s] = value; } else if (/[Cc]olor$/.test(s)) { var c = MochiKit.Color.Color; value = c.fromString(value); if (value) { this.units[s] = "color"; this.styleEnd[s] = value.toHexString(); value = MochiKit.Style.getStyle(this.element, s); this.styleStart[s] = c.fromString(value).toHexString(); this.styleStart[s] = b.map(b.bind(function (i) { return parseInt( this.styleStart[s].slice(i*2 + 1, i*2 + 3), 16); }, this), [0, 1, 2]); this.styleEnd[s] = b.map(b.bind(function (i) { return parseInt( this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16); }, this), [0, 1, 2]); } } else { // For non-length & non-color properties, we just set the value this.element.style[s] = value; } } }, /** @id MochiKit.Visual.Morph.prototype.update */ update: function (position) { var value; for (var s in this.styleStart) { if (this.units[s] == "color") { var m = '#'; var start = this.styleStart[s]; var end = this.styleEnd[s]; MochiKit.Base.map(MochiKit.Base.bind(function (i) { m += MochiKit.Color.toColorPart(Math.round(start[i] + (end[i] - start[i])*position)); }, this), [0, 1, 2]); this.element.style[s] = m; } else { value = this.styleStart[s] + Math.round((this.styleEnd[s] - this.styleStart[s]) * position * 1000) / 1000 + this.units[s]; this.element.style[s] = value; } } } }); /*** Combination effects. ***/ /** @id MochiKit.Visual.fade */ MochiKit.Visual.fade = function (element, /* optional */ options) { /*** Fade a given element: change its opacity and hide it in the end. @param options: 'to' and 'from' to change opacity. ***/ var s = MochiKit.Style; var oldOpacity = s.getStyle(element, 'opacity'); options = MochiKit.Base.update({ from: s.getStyle(element, 'opacity') || 1.0, to: 0.0, afterFinishInternal: function (effect) { if (effect.options.to !== 0) { return; } s.hideElement(effect.element); s.setStyle(effect.element, {'opacity': oldOpacity}); } }, options); return new MochiKit.Visual.Opacity(element, options); }; /** @id MochiKit.Visual.appear */ MochiKit.Visual.appear = function (element, /* optional */ options) { /*** Make an element appear. @param options: 'to' and 'from' to change opacity. ***/ var s = MochiKit.Style; var v = MochiKit.Visual; options = MochiKit.Base.update({ from: (s.getStyle(element, 'display') == 'none' ? 0.0 : s.getStyle(element, 'opacity') || 0.0), to: 1.0, // force Safari to render floated elements properly afterFinishInternal: function (effect) { v._forceRerendering(effect.element); }, beforeSetupInternal: function (effect) { s.setStyle(effect.element, {'opacity': effect.options.from}); s.showElement(effect.element); } }, options); return new v.Opacity(element, options); }; /** @id MochiKit.Visual.puff */ MochiKit.Visual.puff = function (element, /* optional */ options) { /*** 'Puff' an element: grow it to double size, fading it and make it hidden. ***/ var s = MochiKit.Style; var v = MochiKit.Visual; element = MochiKit.DOM.getElement(element); var elementDimensions = MochiKit.Style.getElementDimensions(element, true); var oldStyle = { position: s.getStyle(element, 'position'), top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height, opacity: s.getStyle(element, 'opacity') }; options = MochiKit.Base.update({ beforeSetupInternal: function (effect) { MochiKit.Position.absolutize(effect.effects[0].element); }, afterFinishInternal: function (effect) { s.hideElement(effect.effects[0].element); s.setStyle(effect.effects[0].element, oldStyle); }, scaleContent: true, scaleFromCenter: true }, options); return new v.Parallel( [new v.Scale(element, 200, {sync: true, scaleFromCenter: options.scaleFromCenter, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, scaleContent: options.scaleContent, restoreAfterFinish: true}), new v.Opacity(element, {sync: true, to: 0.0 })], options); }; /** @id MochiKit.Visual.blindUp */ MochiKit.Visual.blindUp = function (element, /* optional */ options) { /*** Blind an element up: change its vertical size to 0. ***/ var d = MochiKit.DOM; var s = MochiKit.Style; element = d.getElement(element); var elementDimensions = s.getElementDimensions(element, true); var elemClip = s.makeClipping(element); options = MochiKit.Base.update({ scaleContent: false, scaleX: false, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, restoreAfterFinish: true, afterFinishInternal: function (effect) { s.hideElement(effect.element); s.undoClipping(effect.element, elemClip); } }, options); return new MochiKit.Visual.Scale(element, 0, options); }; /** @id MochiKit.Visual.blindDown */ MochiKit.Visual.blindDown = function (element, /* optional */ options) { /*** Blind an element down: restore its vertical size. ***/ var d = MochiKit.DOM; var s = MochiKit.Style; element = d.getElement(element); var elementDimensions = s.getElementDimensions(element, true); var elemClip; options = MochiKit.Base.update({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, restoreAfterFinish: true, afterSetupInternal: function (effect) { elemClip = s.makeClipping(effect.element); s.setStyle(effect.element, {height: '0px'}); s.showElement(effect.element); }, afterFinishInternal: function (effect) { s.undoClipping(effect.element, elemClip); } }, options); return new MochiKit.Visual.Scale(element, 100, options); }; /** @id MochiKit.Visual.switchOff */ MochiKit.Visual.switchOff = function (element, /* optional */ options) { /*** Apply a switch-off-like effect. ***/ var d = MochiKit.DOM; var s = MochiKit.Style; element = d.getElement(element); var elementDimensions = s.getElementDimensions(element, true); var oldOpacity = s.getStyle(element, 'opacity'); var elemClip; options = MochiKit.Base.update({ duration: 0.7, restoreAfterFinish: true, beforeSetupInternal: function (effect) { s.makePositioned(element); elemClip = s.makeClipping(element); }, afterFinishInternal: function (effect) { s.hideElement(element); s.undoClipping(element, elemClip); s.undoPositioned(element); s.setStyle(element, {'opacity': oldOpacity}); } }, options); var v = MochiKit.Visual; return new v.Sequence( [new v.appear(element, { sync: true, duration: 0.57 * options.duration, from: 0, transition: v.Transitions.flicker }), new v.Scale(element, 1, { sync: true, duration: 0.43 * options.duration, scaleFromCenter: true, scaleX: false, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, scaleContent: false, restoreAfterFinish: true })], options); }; /** @id MochiKit.Visual.dropOut */ MochiKit.Visual.dropOut = function (element, /* optional */ options) { /*** Make an element fall and disappear. ***/ var d = MochiKit.DOM; var s = MochiKit.Style; element = d.getElement(element); var oldStyle = { top: s.getStyle(element, 'top'), left: s.getStyle(element, 'left'), opacity: s.getStyle(element, 'opacity') }; options = MochiKit.Base.update({ duration: 0.5, distance: 100, beforeSetupInternal: function (effect) { s.makePositioned(effect.effects[0].element); }, afterFinishInternal: function (effect) { s.hideElement(effect.effects[0].element); s.undoPositioned(effect.effects[0].element); s.setStyle(effect.effects[0].element, oldStyle); } }, options); var v = MochiKit.Visual; return new v.Parallel( [new v.Move(element, {x: 0, y: options.distance, sync: true}), new v.Opacity(element, {sync: true, to: 0.0})], options); }; /** @id MochiKit.Visual.shake */ MochiKit.Visual.shake = function (element, /* optional */ options) { /*** Move an element from left to right several times. ***/ var d = MochiKit.DOM; var v = MochiKit.Visual; var s = MochiKit.Style; element = d.getElement(element); var oldStyle = { top: s.getStyle(element, 'top'), left: s.getStyle(element, 'left') }; options = MochiKit.Base.update({ duration: 0.5, afterFinishInternal: function (effect) { s.undoPositioned(element); s.setStyle(element, oldStyle); } }, options); return new v.Sequence( [new v.Move(element, { sync: true, duration: 0.1 * options.duration, x: 20, y: 0 }), new v.Move(element, { sync: true, duration: 0.2 * options.duration, x: -40, y: 0 }), new v.Move(element, { sync: true, duration: 0.2 * options.duration, x: 40, y: 0 }), new v.Move(element, { sync: true, duration: 0.2 * options.duration, x: -40, y: 0 }), new v.Move(element, { sync: true, duration: 0.2 * options.duration, x: 40, y: 0 }), new v.Move(element, { sync: true, duration: 0.1 * options.duration, x: -20, y: 0 })], options); }; /** @id MochiKit.Visual.slideDown */ MochiKit.Visual.slideDown = function (element, /* optional */ options) { /*** Slide an element down. It needs to have the content of the element wrapped in a container element with fixed height. ***/ var d = MochiKit.DOM; var b = MochiKit.Base; var s = MochiKit.Style; element = d.getElement(element); if (!element.firstChild) { throw new Error("MochiKit.Visual.slideDown must be used on a element with a child"); } d.removeEmptyTextNodes(element); var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0; var elementDimensions = s.getElementDimensions(element, true); var elemClip; options = b.update({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, restoreAfterFinish: true, afterSetupInternal: function (effect) { s.makePositioned(effect.element); s.makePositioned(effect.element.firstChild); if (/Opera/.test(navigator.userAgent)) { s.setStyle(effect.element, {top: ''}); } elemClip = s.makeClipping(effect.element); s.setStyle(effect.element, {height: '0px'}); s.showElement(effect.element); }, afterUpdateInternal: function (effect) { var elementDimensions = s.getElementDimensions(effect.element, true); s.setStyle(effect.element.firstChild, {bottom: (effect.dims[0] - elementDimensions.h) + 'px'}); }, afterFinishInternal: function (effect) { s.undoClipping(effect.element, elemClip); // IE will crash if child is undoPositioned first if (/MSIE/.test(navigator.userAgent)) { s.undoPositioned(effect.element); s.undoPositioned(effect.element.firstChild); } else { s.undoPositioned(effect.element.firstChild); s.undoPositioned(effect.element); } s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); } }, options); return new MochiKit.Visual.Scale(element, 100, options); }; /** @id MochiKit.Visual.slideUp */ MochiKit.Visual.slideUp = function (element, /* optional */ options) { /*** Slide an element up. It needs to have the content of the element wrapped in a container element with fixed height. ***/ var d = MochiKit.DOM; var b = MochiKit.Base; var s = MochiKit.Style; element = d.getElement(element); if (!element.firstChild) { throw new Error("MochiKit.Visual.slideUp must be used on a element with a child"); } d.removeEmptyTextNodes(element); var oldInnerBottom = s.getStyle(element.firstChild, 'bottom'); var elementDimensions = s.getElementDimensions(element, true); var elemClip; options = b.update({ scaleContent: false, scaleX: false, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, scaleFrom: 100, restoreAfterFinish: true, beforeStartInternal: function (effect) { s.makePositioned(effect.element); s.makePositioned(effect.element.firstChild); if (/Opera/.test(navigator.userAgent)) { s.setStyle(effect.element, {top: ''}); } elemClip = s.makeClipping(effect.element); s.showElement(effect.element); }, afterUpdateInternal: function (effect) { var elementDimensions = s.getElementDimensions(effect.element, true); s.setStyle(effect.element.firstChild, {bottom: (effect.dims[0] - elementDimensions.h) + 'px'}); }, afterFinishInternal: function (effect) { s.hideElement(effect.element); s.undoClipping(effect.element, elemClip); s.undoPositioned(effect.element.firstChild); s.undoPositioned(effect.element); s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); } }, options); return new MochiKit.Visual.Scale(element, 0, options); }; // Bug in opera makes the TD containing this element expand for a instance // after finish /** @id MochiKit.Visual.squish */ MochiKit.Visual.squish = function (element, /* optional */ options) { /*** Reduce an element and make it disappear. ***/ var d = MochiKit.DOM; var b = MochiKit.Base; var s = MochiKit.Style; var elementDimensions = s.getElementDimensions(element, true); var elemClip; options = b.update({ restoreAfterFinish: true, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, beforeSetupInternal: function (effect) { elemClip = s.makeClipping(effect.element); }, afterFinishInternal: function (effect) { s.hideElement(effect.element); s.undoClipping(effect.element, elemClip); } }, options); return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options); }; /** @id MochiKit.Visual.grow */ MochiKit.Visual.grow = function (element, /* optional */ options) { /*** Grow an element to its original size. Make it zero-sized before if necessary. ***/ var d = MochiKit.DOM; var v = MochiKit.Visual; var s = MochiKit.Style; element = d.getElement(element); options = MochiKit.Base.update({ direction: 'center', moveTransition: v.Transitions.sinoidal, scaleTransition: v.Transitions.sinoidal, opacityTransition: v.Transitions.full, scaleContent: true, scaleFromCenter: false }, options); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: s.getStyle(element, 'opacity') }; var dims = s.getElementDimensions(element, true); var initialMoveX, initialMoveY; var moveX, moveY; switch (options.direction) { case 'top-left': initialMoveX = initialMoveY = moveX = moveY = 0; break; case 'top-right': initialMoveX = dims.w; initialMoveY = moveY = 0; moveX = -dims.w; break; case 'bottom-left': initialMoveX = moveX = 0; initialMoveY = dims.h; moveY = -dims.h; break; case 'bottom-right': initialMoveX = dims.w; initialMoveY = dims.h; moveX = -dims.w; moveY = -dims.h; break; case 'center': initialMoveX = dims.w / 2; initialMoveY = dims.h / 2; moveX = -dims.w / 2; moveY = -dims.h / 2; break; } var optionsParallel = MochiKit.Base.update({ beforeSetupInternal: function (effect) { s.setStyle(effect.effects[0].element, {height: '0px'}); s.showElement(effect.effects[0].element); }, afterFinishInternal: function (effect) { s.undoClipping(effect.effects[0].element); s.undoPositioned(effect.effects[0].element); s.setStyle(effect.effects[0].element, oldStyle); } }, options); return new v.Move(element, { x: initialMoveX, y: initialMoveY, duration: 0.01, beforeSetupInternal: function (effect) { s.hideElement(effect.element); s.makeClipping(effect.element); s.makePositioned(effect.element); }, afterFinishInternal: function (effect) { new v.Parallel( [new v.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), new v.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), new v.Scale(effect.element, 100, { scaleMode: {originalHeight: dims.h, originalWidth: dims.w}, sync: true, scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0, transition: options.scaleTransition, scaleContent: options.scaleContent, scaleFromCenter: options.scaleFromCenter, restoreAfterFinish: true }) ], optionsParallel ); } }); }; /** @id MochiKit.Visual.shrink */ MochiKit.Visual.shrink = function (element, /* optional */ options) { /*** Shrink an element and make it disappear. ***/ var d = MochiKit.DOM; var v = MochiKit.Visual; var s = MochiKit.Style; element = d.getElement(element); options = MochiKit.Base.update({ direction: 'center', moveTransition: v.Transitions.sinoidal, scaleTransition: v.Transitions.sinoidal, opacityTransition: v.Transitions.none, scaleContent: true, scaleFromCenter: false }, options); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: s.getStyle(element, 'opacity') }; var dims = s.getElementDimensions(element, true); var moveX, moveY; switch (options.direction) { case 'top-left': moveX = moveY = 0; break; case 'top-right': moveX = dims.w; moveY = 0; break; case 'bottom-left': moveX = 0; moveY = dims.h; break; case 'bottom-right': moveX = dims.w; moveY = dims.h; break; case 'center': moveX = dims.w / 2; moveY = dims.h / 2; break; } var elemClip; var optionsParallel = MochiKit.Base.update({ beforeStartInternal: function (effect) { s.makePositioned(effect.effects[0].element); elemClip = s.makeClipping(effect.effects[0].element); }, afterFinishInternal: function (effect) { s.hideElement(effect.effects[0].element); s.undoClipping(effect.effects[0].element, elemClip); s.undoPositioned(effect.effects[0].element); s.setStyle(effect.effects[0].element, oldStyle); } }, options); return new v.Parallel( [new v.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), new v.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, { scaleMode: {originalHeight: dims.h, originalWidth: dims.w}, sync: true, transition: options.scaleTransition, scaleContent: options.scaleContent, scaleFromCenter: options.scaleFromCenter, restoreAfterFinish: true }), new v.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) ], optionsParallel ); }; /** @id MochiKit.Visual.pulsate */ MochiKit.Visual.pulsate = function (element, /* optional */ options) { /*** Pulse an element between appear/fade. ***/ var d = MochiKit.DOM; var v = MochiKit.Visual; var b = MochiKit.Base; var oldOpacity = MochiKit.Style.getStyle(element, 'opacity'); options = b.update({ duration: 3.0, from: 0, afterFinishInternal: function (effect) { MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity}); } }, options); var transition = options.transition || v.Transitions.sinoidal; options.transition = function (pos) { return transition(1 - v.Transitions.pulse(pos, options.pulses)); }; return new v.Opacity(element, options); }; /** @id MochiKit.Visual.fold */ MochiKit.Visual.fold = function (element, /* optional */ options) { /*** Fold an element, first vertically, then horizontally. ***/ var d = MochiKit.DOM; var v = MochiKit.Visual; var s = MochiKit.Style; element = d.getElement(element); var elementDimensions = s.getElementDimensions(element, true); var oldStyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; var elemClip = s.makeClipping(element); options = MochiKit.Base.update({ scaleContent: false, scaleX: false, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, afterFinishInternal: function (effect) { new v.Scale(element, 1, { scaleContent: false, scaleY: false, scaleMode: {originalHeight: elementDimensions.h, originalWidth: elementDimensions.w}, afterFinishInternal: function (effect) { s.hideElement(effect.element); s.undoClipping(effect.element, elemClip); s.setStyle(effect.element, oldStyle); } }); } }, options); return new v.Scale(element, 5, options); }; MochiKit.Base.nameFunctions(MochiKit.Visual); MochiKit.Base._exportSymbols(this, MochiKit.Visual);