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