dom/tests/mochitest/ajax/mochikit/MochiKit/Visual.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /***
michael@0 2
michael@0 3 MochiKit.Visual 1.4
michael@0 4
michael@0 5 See <http://mochikit.com/> for documentation, downloads, license, etc.
michael@0 6
michael@0 7 (c) 2005 Bob Ippolito and others. All rights Reserved.
michael@0 8
michael@0 9 ***/
michael@0 10
michael@0 11 if (typeof(dojo) != 'undefined') {
michael@0 12 dojo.provide('MochiKit.Visual');
michael@0 13 dojo.require('MochiKit.Base');
michael@0 14 dojo.require('MochiKit.DOM');
michael@0 15 dojo.require('MochiKit.Style');
michael@0 16 dojo.require('MochiKit.Color');
michael@0 17 dojo.require('MochiKit.Position');
michael@0 18 }
michael@0 19
michael@0 20 if (typeof(JSAN) != 'undefined') {
michael@0 21 JSAN.use("MochiKit.Base", []);
michael@0 22 JSAN.use("MochiKit.DOM", []);
michael@0 23 JSAN.use("MochiKit.Style", []);
michael@0 24 JSAN.use("MochiKit.Color", []);
michael@0 25 JSAN.use("MochiKit.Position", []);
michael@0 26 }
michael@0 27
michael@0 28 try {
michael@0 29 if (typeof(MochiKit.Base) === 'undefined' ||
michael@0 30 typeof(MochiKit.DOM) === 'undefined' ||
michael@0 31 typeof(MochiKit.Style) === 'undefined' ||
michael@0 32 typeof(MochiKit.Position) === 'undefined' ||
michael@0 33 typeof(MochiKit.Color) === 'undefined') {
michael@0 34 throw "";
michael@0 35 }
michael@0 36 } catch (e) {
michael@0 37 throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM, MochiKit.Style, MochiKit.Position and MochiKit.Color!";
michael@0 38 }
michael@0 39
michael@0 40 if (typeof(MochiKit.Visual) == "undefined") {
michael@0 41 MochiKit.Visual = {};
michael@0 42 }
michael@0 43
michael@0 44 MochiKit.Visual.NAME = "MochiKit.Visual";
michael@0 45 MochiKit.Visual.VERSION = "1.4";
michael@0 46
michael@0 47 MochiKit.Visual.__repr__ = function () {
michael@0 48 return "[" + this.NAME + " " + this.VERSION + "]";
michael@0 49 };
michael@0 50
michael@0 51 MochiKit.Visual.toString = function () {
michael@0 52 return this.__repr__();
michael@0 53 };
michael@0 54
michael@0 55 MochiKit.Visual._RoundCorners = function (e, options) {
michael@0 56 e = MochiKit.DOM.getElement(e);
michael@0 57 this._setOptions(options);
michael@0 58 if (this.options.__unstable__wrapElement) {
michael@0 59 e = this._doWrap(e);
michael@0 60 }
michael@0 61
michael@0 62 var color = this.options.color;
michael@0 63 var C = MochiKit.Color.Color;
michael@0 64 if (this.options.color === "fromElement") {
michael@0 65 color = C.fromBackground(e);
michael@0 66 } else if (!(color instanceof C)) {
michael@0 67 color = C.fromString(color);
michael@0 68 }
michael@0 69 this.isTransparent = (color.asRGB().a <= 0);
michael@0 70
michael@0 71 var bgColor = this.options.bgColor;
michael@0 72 if (this.options.bgColor === "fromParent") {
michael@0 73 bgColor = C.fromBackground(e.offsetParent);
michael@0 74 } else if (!(bgColor instanceof C)) {
michael@0 75 bgColor = C.fromString(bgColor);
michael@0 76 }
michael@0 77
michael@0 78 this._roundCornersImpl(e, color, bgColor);
michael@0 79 };
michael@0 80
michael@0 81 MochiKit.Visual._RoundCorners.prototype = {
michael@0 82 _doWrap: function (e) {
michael@0 83 var parent = e.parentNode;
michael@0 84 var doc = MochiKit.DOM.currentDocument();
michael@0 85 if (typeof(doc.defaultView) === "undefined"
michael@0 86 || doc.defaultView === null) {
michael@0 87 return e;
michael@0 88 }
michael@0 89 var style = doc.defaultView.getComputedStyle(e, null);
michael@0 90 if (typeof(style) === "undefined" || style === null) {
michael@0 91 return e;
michael@0 92 }
michael@0 93 var wrapper = MochiKit.DOM.DIV({"style": {
michael@0 94 display: "block",
michael@0 95 // convert padding to margin
michael@0 96 marginTop: style.getPropertyValue("padding-top"),
michael@0 97 marginRight: style.getPropertyValue("padding-right"),
michael@0 98 marginBottom: style.getPropertyValue("padding-bottom"),
michael@0 99 marginLeft: style.getPropertyValue("padding-left"),
michael@0 100 // remove padding so the rounding looks right
michael@0 101 padding: "0px"
michael@0 102 /*
michael@0 103 paddingRight: "0px",
michael@0 104 paddingLeft: "0px"
michael@0 105 */
michael@0 106 }});
michael@0 107 wrapper.innerHTML = e.innerHTML;
michael@0 108 e.innerHTML = "";
michael@0 109 e.appendChild(wrapper);
michael@0 110 return e;
michael@0 111 },
michael@0 112
michael@0 113 _roundCornersImpl: function (e, color, bgColor) {
michael@0 114 if (this.options.border) {
michael@0 115 this._renderBorder(e, bgColor);
michael@0 116 }
michael@0 117 if (this._isTopRounded()) {
michael@0 118 this._roundTopCorners(e, color, bgColor);
michael@0 119 }
michael@0 120 if (this._isBottomRounded()) {
michael@0 121 this._roundBottomCorners(e, color, bgColor);
michael@0 122 }
michael@0 123 },
michael@0 124
michael@0 125 _renderBorder: function (el, bgColor) {
michael@0 126 var borderValue = "1px solid " + this._borderColor(bgColor);
michael@0 127 var borderL = "border-left: " + borderValue;
michael@0 128 var borderR = "border-right: " + borderValue;
michael@0 129 var style = "style='" + borderL + ";" + borderR + "'";
michael@0 130 el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>";
michael@0 131 },
michael@0 132
michael@0 133 _roundTopCorners: function (el, color, bgColor) {
michael@0 134 var corner = this._createCorner(bgColor);
michael@0 135 for (var i = 0; i < this.options.numSlices; i++) {
michael@0 136 corner.appendChild(
michael@0 137 this._createCornerSlice(color, bgColor, i, "top")
michael@0 138 );
michael@0 139 }
michael@0 140 el.style.paddingTop = 0;
michael@0 141 el.insertBefore(corner, el.firstChild);
michael@0 142 },
michael@0 143
michael@0 144 _roundBottomCorners: function (el, color, bgColor) {
michael@0 145 var corner = this._createCorner(bgColor);
michael@0 146 for (var i = (this.options.numSlices - 1); i >= 0; i--) {
michael@0 147 corner.appendChild(
michael@0 148 this._createCornerSlice(color, bgColor, i, "bottom")
michael@0 149 );
michael@0 150 }
michael@0 151 el.style.paddingBottom = 0;
michael@0 152 el.appendChild(corner);
michael@0 153 },
michael@0 154
michael@0 155 _createCorner: function (bgColor) {
michael@0 156 var dom = MochiKit.DOM;
michael@0 157 return dom.DIV({style: {backgroundColor: bgColor.toString()}});
michael@0 158 },
michael@0 159
michael@0 160 _createCornerSlice: function (color, bgColor, n, position) {
michael@0 161 var slice = MochiKit.DOM.SPAN();
michael@0 162
michael@0 163 var inStyle = slice.style;
michael@0 164 inStyle.backgroundColor = color.toString();
michael@0 165 inStyle.display = "block";
michael@0 166 inStyle.height = "1px";
michael@0 167 inStyle.overflow = "hidden";
michael@0 168 inStyle.fontSize = "1px";
michael@0 169
michael@0 170 var borderColor = this._borderColor(color, bgColor);
michael@0 171 if (this.options.border && n === 0) {
michael@0 172 inStyle.borderTopStyle = "solid";
michael@0 173 inStyle.borderTopWidth = "1px";
michael@0 174 inStyle.borderLeftWidth = "0px";
michael@0 175 inStyle.borderRightWidth = "0px";
michael@0 176 inStyle.borderBottomWidth = "0px";
michael@0 177 // assumes css compliant box model
michael@0 178 inStyle.height = "0px";
michael@0 179 inStyle.borderColor = borderColor.toString();
michael@0 180 } else if (borderColor) {
michael@0 181 inStyle.borderColor = borderColor.toString();
michael@0 182 inStyle.borderStyle = "solid";
michael@0 183 inStyle.borderWidth = "0px 1px";
michael@0 184 }
michael@0 185
michael@0 186 if (!this.options.compact && (n == (this.options.numSlices - 1))) {
michael@0 187 inStyle.height = "2px";
michael@0 188 }
michael@0 189
michael@0 190 this._setMargin(slice, n, position);
michael@0 191 this._setBorder(slice, n, position);
michael@0 192
michael@0 193 return slice;
michael@0 194 },
michael@0 195
michael@0 196 _setOptions: function (options) {
michael@0 197 this.options = {
michael@0 198 corners: "all",
michael@0 199 color: "fromElement",
michael@0 200 bgColor: "fromParent",
michael@0 201 blend: true,
michael@0 202 border: false,
michael@0 203 compact: false,
michael@0 204 __unstable__wrapElement: false
michael@0 205 };
michael@0 206 MochiKit.Base.update(this.options, options);
michael@0 207
michael@0 208 this.options.numSlices = (this.options.compact ? 2 : 4);
michael@0 209 },
michael@0 210
michael@0 211 _whichSideTop: function () {
michael@0 212 var corners = this.options.corners;
michael@0 213 if (this._hasString(corners, "all", "top")) {
michael@0 214 return "";
michael@0 215 }
michael@0 216
michael@0 217 var has_tl = (corners.indexOf("tl") != -1);
michael@0 218 var has_tr = (corners.indexOf("tr") != -1);
michael@0 219 if (has_tl && has_tr) {
michael@0 220 return "";
michael@0 221 }
michael@0 222 if (has_tl) {
michael@0 223 return "left";
michael@0 224 }
michael@0 225 if (has_tr) {
michael@0 226 return "right";
michael@0 227 }
michael@0 228 return "";
michael@0 229 },
michael@0 230
michael@0 231 _whichSideBottom: function () {
michael@0 232 var corners = this.options.corners;
michael@0 233 if (this._hasString(corners, "all", "bottom")) {
michael@0 234 return "";
michael@0 235 }
michael@0 236
michael@0 237 var has_bl = (corners.indexOf('bl') != -1);
michael@0 238 var has_br = (corners.indexOf('br') != -1);
michael@0 239 if (has_bl && has_br) {
michael@0 240 return "";
michael@0 241 }
michael@0 242 if (has_bl) {
michael@0 243 return "left";
michael@0 244 }
michael@0 245 if (has_br) {
michael@0 246 return "right";
michael@0 247 }
michael@0 248 return "";
michael@0 249 },
michael@0 250
michael@0 251 _borderColor: function (color, bgColor) {
michael@0 252 if (color == "transparent") {
michael@0 253 return bgColor;
michael@0 254 } else if (this.options.border) {
michael@0 255 return this.options.border;
michael@0 256 } else if (this.options.blend) {
michael@0 257 return bgColor.blendedColor(color);
michael@0 258 }
michael@0 259 return "";
michael@0 260 },
michael@0 261
michael@0 262
michael@0 263 _setMargin: function (el, n, corners) {
michael@0 264 var marginSize = this._marginSize(n) + "px";
michael@0 265 var whichSide = (
michael@0 266 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
michael@0 267 );
michael@0 268 var style = el.style;
michael@0 269
michael@0 270 if (whichSide == "left") {
michael@0 271 style.marginLeft = marginSize;
michael@0 272 style.marginRight = "0px";
michael@0 273 } else if (whichSide == "right") {
michael@0 274 style.marginRight = marginSize;
michael@0 275 style.marginLeft = "0px";
michael@0 276 } else {
michael@0 277 style.marginLeft = marginSize;
michael@0 278 style.marginRight = marginSize;
michael@0 279 }
michael@0 280 },
michael@0 281
michael@0 282 _setBorder: function (el, n, corners) {
michael@0 283 var borderSize = this._borderSize(n) + "px";
michael@0 284 var whichSide = (
michael@0 285 corners == "top" ? this._whichSideTop() : this._whichSideBottom()
michael@0 286 );
michael@0 287
michael@0 288 var style = el.style;
michael@0 289 if (whichSide == "left") {
michael@0 290 style.borderLeftWidth = borderSize;
michael@0 291 style.borderRightWidth = "0px";
michael@0 292 } else if (whichSide == "right") {
michael@0 293 style.borderRightWidth = borderSize;
michael@0 294 style.borderLeftWidth = "0px";
michael@0 295 } else {
michael@0 296 style.borderLeftWidth = borderSize;
michael@0 297 style.borderRightWidth = borderSize;
michael@0 298 }
michael@0 299 },
michael@0 300
michael@0 301 _marginSize: function (n) {
michael@0 302 if (this.isTransparent) {
michael@0 303 return 0;
michael@0 304 }
michael@0 305
michael@0 306 var o = this.options;
michael@0 307 if (o.compact && o.blend) {
michael@0 308 var smBlendedMarginSizes = [1, 0];
michael@0 309 return smBlendedMarginSizes[n];
michael@0 310 } else if (o.compact) {
michael@0 311 var compactMarginSizes = [2, 1];
michael@0 312 return compactMarginSizes[n];
michael@0 313 } else if (o.blend) {
michael@0 314 var blendedMarginSizes = [3, 2, 1, 0];
michael@0 315 return blendedMarginSizes[n];
michael@0 316 } else {
michael@0 317 var marginSizes = [5, 3, 2, 1];
michael@0 318 return marginSizes[n];
michael@0 319 }
michael@0 320 },
michael@0 321
michael@0 322 _borderSize: function (n) {
michael@0 323 var o = this.options;
michael@0 324 var borderSizes;
michael@0 325 if (o.compact && (o.blend || this.isTransparent)) {
michael@0 326 return 1;
michael@0 327 } else if (o.compact) {
michael@0 328 borderSizes = [1, 0];
michael@0 329 } else if (o.blend) {
michael@0 330 borderSizes = [2, 1, 1, 1];
michael@0 331 } else if (o.border) {
michael@0 332 borderSizes = [0, 2, 0, 0];
michael@0 333 } else if (this.isTransparent) {
michael@0 334 borderSizes = [5, 3, 2, 1];
michael@0 335 } else {
michael@0 336 return 0;
michael@0 337 }
michael@0 338 return borderSizes[n];
michael@0 339 },
michael@0 340
michael@0 341 _hasString: function (str) {
michael@0 342 for (var i = 1; i< arguments.length; i++) {
michael@0 343 if (str.indexOf(arguments[i]) != -1) {
michael@0 344 return true;
michael@0 345 }
michael@0 346 }
michael@0 347 return false;
michael@0 348 },
michael@0 349
michael@0 350 _isTopRounded: function () {
michael@0 351 return this._hasString(this.options.corners,
michael@0 352 "all", "top", "tl", "tr"
michael@0 353 );
michael@0 354 },
michael@0 355
michael@0 356 _isBottomRounded: function () {
michael@0 357 return this._hasString(this.options.corners,
michael@0 358 "all", "bottom", "bl", "br"
michael@0 359 );
michael@0 360 },
michael@0 361
michael@0 362 _hasSingleTextChild: function (el) {
michael@0 363 return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
michael@0 364 }
michael@0 365 };
michael@0 366
michael@0 367 /** @id MochiKit.Visual.roundElement */
michael@0 368 MochiKit.Visual.roundElement = function (e, options) {
michael@0 369 new MochiKit.Visual._RoundCorners(e, options);
michael@0 370 };
michael@0 371
michael@0 372 /** @id MochiKit.Visual.roundClass */
michael@0 373 MochiKit.Visual.roundClass = function (tagName, className, options) {
michael@0 374 var elements = MochiKit.DOM.getElementsByTagAndClassName(
michael@0 375 tagName, className
michael@0 376 );
michael@0 377 for (var i = 0; i < elements.length; i++) {
michael@0 378 MochiKit.Visual.roundElement(elements[i], options);
michael@0 379 }
michael@0 380 };
michael@0 381
michael@0 382 /** @id MochiKit.Visual.tagifyText */
michael@0 383 MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) {
michael@0 384 /***
michael@0 385
michael@0 386 Change a node text to character in tags.
michael@0 387
michael@0 388 @param tagifyStyle: the style to apply to character nodes, default to
michael@0 389 'position: relative'.
michael@0 390
michael@0 391 ***/
michael@0 392 tagifyStyle = tagifyStyle || 'position:relative';
michael@0 393 if (/MSIE/.test(navigator.userAgent)) {
michael@0 394 tagifyStyle += ';zoom:1';
michael@0 395 }
michael@0 396 element = MochiKit.DOM.getElement(element);
michael@0 397 var ma = MochiKit.Base.map;
michael@0 398 ma(function (child) {
michael@0 399 if (child.nodeType == 3) {
michael@0 400 ma(function (character) {
michael@0 401 element.insertBefore(
michael@0 402 MochiKit.DOM.SPAN({style: tagifyStyle},
michael@0 403 character == ' ' ? String.fromCharCode(160) : character), child);
michael@0 404 }, child.nodeValue.split(''));
michael@0 405 MochiKit.DOM.removeElement(child);
michael@0 406 }
michael@0 407 }, element.childNodes);
michael@0 408 };
michael@0 409
michael@0 410 /** @id MochiKit.Visual.forceRerendering */
michael@0 411 MochiKit.Visual.forceRerendering = function (element) {
michael@0 412 try {
michael@0 413 element = MochiKit.DOM.getElement(element);
michael@0 414 var n = document.createTextNode(' ');
michael@0 415 element.appendChild(n);
michael@0 416 element.removeChild(n);
michael@0 417 } catch(e) {
michael@0 418 }
michael@0 419 };
michael@0 420
michael@0 421 /** @id MochiKit.Visual.multiple */
michael@0 422 MochiKit.Visual.multiple = function (elements, effect, /* optional */options) {
michael@0 423 /***
michael@0 424
michael@0 425 Launch the same effect subsequently on given elements.
michael@0 426
michael@0 427 ***/
michael@0 428 options = MochiKit.Base.update({
michael@0 429 speed: 0.1, delay: 0.0
michael@0 430 }, options || {});
michael@0 431 var masterDelay = options.delay;
michael@0 432 var index = 0;
michael@0 433 MochiKit.Base.map(function (innerelement) {
michael@0 434 options.delay = index * options.speed + masterDelay;
michael@0 435 new effect(innerelement, options);
michael@0 436 index += 1;
michael@0 437 }, elements);
michael@0 438 };
michael@0 439
michael@0 440 MochiKit.Visual.PAIRS = {
michael@0 441 'slide': ['slideDown', 'slideUp'],
michael@0 442 'blind': ['blindDown', 'blindUp'],
michael@0 443 'appear': ['appear', 'fade'],
michael@0 444 'size': ['grow', 'shrink']
michael@0 445 };
michael@0 446
michael@0 447 /** @id MochiKit.Visual.toggle */
michael@0 448 MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) {
michael@0 449 /***
michael@0 450
michael@0 451 Toggle an item between two state depending of its visibility, making
michael@0 452 a effect between these states. Default effect is 'appear', can be
michael@0 453 'slide' or 'blind'.
michael@0 454
michael@0 455 ***/
michael@0 456 element = MochiKit.DOM.getElement(element);
michael@0 457 effect = (effect || 'appear').toLowerCase();
michael@0 458 options = MochiKit.Base.update({
michael@0 459 queue: {position: 'end', scope: (element.id || 'global'), limit: 1}
michael@0 460 }, options || {});
michael@0 461 var v = MochiKit.Visual;
michael@0 462 v[MochiKit.Style.getStyle(element, 'display') != 'none' ?
michael@0 463 v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options);
michael@0 464 };
michael@0 465
michael@0 466 /***
michael@0 467
michael@0 468 Transitions: define functions calculating variations depending of a position.
michael@0 469
michael@0 470 ***/
michael@0 471
michael@0 472 MochiKit.Visual.Transitions = {};
michael@0 473
michael@0 474 /** @id MochiKit.Visual.Transitions.linear */
michael@0 475 MochiKit.Visual.Transitions.linear = function (pos) {
michael@0 476 return pos;
michael@0 477 };
michael@0 478
michael@0 479 /** @id MochiKit.Visual.Transitions.sinoidal */
michael@0 480 MochiKit.Visual.Transitions.sinoidal = function (pos) {
michael@0 481 return (-Math.cos(pos*Math.PI)/2) + 0.5;
michael@0 482 };
michael@0 483
michael@0 484 /** @id MochiKit.Visual.Transitions.reverse */
michael@0 485 MochiKit.Visual.Transitions.reverse = function (pos) {
michael@0 486 return 1 - pos;
michael@0 487 };
michael@0 488
michael@0 489 /** @id MochiKit.Visual.Transitions.flicker */
michael@0 490 MochiKit.Visual.Transitions.flicker = function (pos) {
michael@0 491 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
michael@0 492 };
michael@0 493
michael@0 494 /** @id MochiKit.Visual.Transitions.wobble */
michael@0 495 MochiKit.Visual.Transitions.wobble = function (pos) {
michael@0 496 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
michael@0 497 };
michael@0 498
michael@0 499 /** @id MochiKit.Visual.Transitions.pulse */
michael@0 500 MochiKit.Visual.Transitions.pulse = function (pos, pulses) {
michael@0 501 if (!pulses) {
michael@0 502 return (Math.floor(pos*10) % 2 === 0 ?
michael@0 503 (pos*10 - Math.floor(pos*10)) : 1 - (pos*10 - Math.floor(pos*10)));
michael@0 504 }
michael@0 505 return (Math.round((pos % (1/pulses)) * pulses) == 0 ?
michael@0 506 ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
michael@0 507 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)));
michael@0 508 };
michael@0 509
michael@0 510 /** @id MochiKit.Visual.Transitions.none */
michael@0 511 MochiKit.Visual.Transitions.none = function (pos) {
michael@0 512 return 0;
michael@0 513 };
michael@0 514
michael@0 515 /** @id MochiKit.Visual.Transitions.full */
michael@0 516 MochiKit.Visual.Transitions.full = function (pos) {
michael@0 517 return 1;
michael@0 518 };
michael@0 519
michael@0 520 /***
michael@0 521
michael@0 522 Core effects
michael@0 523
michael@0 524 ***/
michael@0 525
michael@0 526 MochiKit.Visual.ScopedQueue = function () {
michael@0 527 var cls = arguments.callee;
michael@0 528 if (!(this instanceof cls)) {
michael@0 529 return new cls();
michael@0 530 }
michael@0 531 this.__init__();
michael@0 532 };
michael@0 533
michael@0 534 MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, {
michael@0 535 __init__: function () {
michael@0 536 this.effects = [];
michael@0 537 this.interval = null;
michael@0 538 },
michael@0 539
michael@0 540 /** @id MochiKit.Visual.ScopedQueue.prototype.add */
michael@0 541 add: function (effect) {
michael@0 542 var timestamp = new Date().getTime();
michael@0 543
michael@0 544 var position = (typeof(effect.options.queue) == 'string') ?
michael@0 545 effect.options.queue : effect.options.queue.position;
michael@0 546
michael@0 547 var ma = MochiKit.Base.map;
michael@0 548 switch (position) {
michael@0 549 case 'front':
michael@0 550 // move unstarted effects after this effect
michael@0 551 ma(function (e) {
michael@0 552 if (e.state == 'idle') {
michael@0 553 e.startOn += effect.finishOn;
michael@0 554 e.finishOn += effect.finishOn;
michael@0 555 }
michael@0 556 }, this.effects);
michael@0 557 break;
michael@0 558 case 'end':
michael@0 559 var finish;
michael@0 560 // start effect after last queued effect has finished
michael@0 561 ma(function (e) {
michael@0 562 var i = e.finishOn;
michael@0 563 if (i >= (finish || i)) {
michael@0 564 finish = i;
michael@0 565 }
michael@0 566 }, this.effects);
michael@0 567 timestamp = finish || timestamp;
michael@0 568 break;
michael@0 569 case 'break':
michael@0 570 ma(function (e) {
michael@0 571 e.finalize();
michael@0 572 }, this.effects);
michael@0 573 break;
michael@0 574 }
michael@0 575
michael@0 576 effect.startOn += timestamp;
michael@0 577 effect.finishOn += timestamp;
michael@0 578 if (!effect.options.queue.limit ||
michael@0 579 this.effects.length < effect.options.queue.limit) {
michael@0 580 this.effects.push(effect);
michael@0 581 }
michael@0 582
michael@0 583 if (!this.interval) {
michael@0 584 this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this),
michael@0 585 40);
michael@0 586 }
michael@0 587 },
michael@0 588
michael@0 589 /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
michael@0 590 startLoop: function (func, interval) {
michael@0 591 return setInterval(func, interval);
michael@0 592 },
michael@0 593
michael@0 594 /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
michael@0 595 remove: function (effect) {
michael@0 596 this.effects = MochiKit.Base.filter(function (e) {
michael@0 597 return e != effect;
michael@0 598 }, this.effects);
michael@0 599 if (!this.effects.length) {
michael@0 600 this.stopLoop(this.interval);
michael@0 601 this.interval = null;
michael@0 602 }
michael@0 603 },
michael@0 604
michael@0 605 /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
michael@0 606 stopLoop: function (interval) {
michael@0 607 clearInterval(interval);
michael@0 608 },
michael@0 609
michael@0 610 /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
michael@0 611 loop: function () {
michael@0 612 var timePos = new Date().getTime();
michael@0 613 MochiKit.Base.map(function (effect) {
michael@0 614 effect.loop(timePos);
michael@0 615 }, this.effects);
michael@0 616 }
michael@0 617 });
michael@0 618
michael@0 619 MochiKit.Visual.Queues = {
michael@0 620 instances: {},
michael@0 621
michael@0 622 get: function (queueName) {
michael@0 623 if (typeof(queueName) != 'string') {
michael@0 624 return queueName;
michael@0 625 }
michael@0 626
michael@0 627 if (!this.instances[queueName]) {
michael@0 628 this.instances[queueName] = new MochiKit.Visual.ScopedQueue();
michael@0 629 }
michael@0 630 return this.instances[queueName];
michael@0 631 }
michael@0 632 };
michael@0 633
michael@0 634 MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global');
michael@0 635
michael@0 636 MochiKit.Visual.DefaultOptions = {
michael@0 637 transition: MochiKit.Visual.Transitions.sinoidal,
michael@0 638 duration: 1.0, // seconds
michael@0 639 fps: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
michael@0 640 sync: false, // true for combining
michael@0 641 from: 0.0,
michael@0 642 to: 1.0,
michael@0 643 delay: 0.0,
michael@0 644 queue: 'parallel'
michael@0 645 };
michael@0 646
michael@0 647 MochiKit.Visual.Base = function () {};
michael@0 648
michael@0 649 MochiKit.Visual.Base.prototype = {
michael@0 650 /***
michael@0 651
michael@0 652 Basic class for all Effects. Define a looping mechanism called for each step
michael@0 653 of an effect. Don't instantiate it, only subclass it.
michael@0 654
michael@0 655 ***/
michael@0 656
michael@0 657 __class__ : MochiKit.Visual.Base,
michael@0 658
michael@0 659 /** @id MochiKit.Visual.Base.prototype.start */
michael@0 660 start: function (options) {
michael@0 661 var v = MochiKit.Visual;
michael@0 662 this.options = MochiKit.Base.setdefault(options || {},
michael@0 663 v.DefaultOptions);
michael@0 664 this.currentFrame = 0;
michael@0 665 this.state = 'idle';
michael@0 666 this.startOn = this.options.delay*1000;
michael@0 667 this.finishOn = this.startOn + (this.options.duration*1000);
michael@0 668 this.event('beforeStart');
michael@0 669 if (!this.options.sync) {
michael@0 670 v.Queues.get(typeof(this.options.queue) == 'string' ?
michael@0 671 'global' : this.options.queue.scope).add(this);
michael@0 672 }
michael@0 673 },
michael@0 674
michael@0 675 /** @id MochiKit.Visual.Base.prototype.loop */
michael@0 676 loop: function (timePos) {
michael@0 677 if (timePos >= this.startOn) {
michael@0 678 if (timePos >= this.finishOn) {
michael@0 679 return this.finalize();
michael@0 680 }
michael@0 681 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
michael@0 682 var frame =
michael@0 683 Math.round(pos * this.options.fps * this.options.duration);
michael@0 684 if (frame > this.currentFrame) {
michael@0 685 this.render(pos);
michael@0 686 this.currentFrame = frame;
michael@0 687 }
michael@0 688 }
michael@0 689 },
michael@0 690
michael@0 691 /** @id MochiKit.Visual.Base.prototype.render */
michael@0 692 render: function (pos) {
michael@0 693 if (this.state == 'idle') {
michael@0 694 this.state = 'running';
michael@0 695 this.event('beforeSetup');
michael@0 696 this.setup();
michael@0 697 this.event('afterSetup');
michael@0 698 }
michael@0 699 if (this.state == 'running') {
michael@0 700 if (this.options.transition) {
michael@0 701 pos = this.options.transition(pos);
michael@0 702 }
michael@0 703 pos *= (this.options.to - this.options.from);
michael@0 704 pos += this.options.from;
michael@0 705 this.event('beforeUpdate');
michael@0 706 this.update(pos);
michael@0 707 this.event('afterUpdate');
michael@0 708 }
michael@0 709 },
michael@0 710
michael@0 711 /** @id MochiKit.Visual.Base.prototype.cancel */
michael@0 712 cancel: function () {
michael@0 713 if (!this.options.sync) {
michael@0 714 MochiKit.Visual.Queues.get(typeof(this.options.queue) == 'string' ?
michael@0 715 'global' : this.options.queue.scope).remove(this);
michael@0 716 }
michael@0 717 this.state = 'finished';
michael@0 718 },
michael@0 719
michael@0 720 /** @id MochiKit.Visual.Base.prototype.finalize */
michael@0 721 finalize: function () {
michael@0 722 this.render(1.0);
michael@0 723 this.cancel();
michael@0 724 this.event('beforeFinish');
michael@0 725 this.finish();
michael@0 726 this.event('afterFinish');
michael@0 727 },
michael@0 728
michael@0 729 setup: function () {
michael@0 730 },
michael@0 731
michael@0 732 finish: function () {
michael@0 733 },
michael@0 734
michael@0 735 update: function (position) {
michael@0 736 },
michael@0 737
michael@0 738 /** @id MochiKit.Visual.Base.prototype.event */
michael@0 739 event: function (eventName) {
michael@0 740 if (this.options[eventName + 'Internal']) {
michael@0 741 this.options[eventName + 'Internal'](this);
michael@0 742 }
michael@0 743 if (this.options[eventName]) {
michael@0 744 this.options[eventName](this);
michael@0 745 }
michael@0 746 },
michael@0 747
michael@0 748 /** @id MochiKit.Visual.Base.prototype.repr */
michael@0 749 repr: function () {
michael@0 750 return '[' + this.__class__.NAME + ', options:' +
michael@0 751 MochiKit.Base.repr(this.options) + ']';
michael@0 752 }
michael@0 753 };
michael@0 754
michael@0 755 /** @id MochiKit.Visual.Parallel */
michael@0 756 MochiKit.Visual.Parallel = function (effects, options) {
michael@0 757 var cls = arguments.callee;
michael@0 758 if (!(this instanceof cls)) {
michael@0 759 return new cls(effects, options);
michael@0 760 }
michael@0 761
michael@0 762 this.__init__(effects, options);
michael@0 763 };
michael@0 764
michael@0 765 MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base();
michael@0 766
michael@0 767 MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, {
michael@0 768 /***
michael@0 769
michael@0 770 Run multiple effects at the same time.
michael@0 771
michael@0 772 ***/
michael@0 773
michael@0 774 __class__ : MochiKit.Visual.Parallel,
michael@0 775
michael@0 776 __init__: function (effects, options) {
michael@0 777 this.effects = effects || [];
michael@0 778 this.start(options);
michael@0 779 },
michael@0 780
michael@0 781 /** @id MochiKit.Visual.Parallel.prototype.update */
michael@0 782 update: function (position) {
michael@0 783 MochiKit.Base.map(function (effect) {
michael@0 784 effect.render(position);
michael@0 785 }, this.effects);
michael@0 786 },
michael@0 787
michael@0 788 /** @id MochiKit.Visual.Parallel.prototype.finish */
michael@0 789 finish: function () {
michael@0 790 MochiKit.Base.map(function (effect) {
michael@0 791 effect.finalize();
michael@0 792 }, this.effects);
michael@0 793 }
michael@0 794 });
michael@0 795
michael@0 796 /** @id MochiKit.Visual.Opacity */
michael@0 797 MochiKit.Visual.Opacity = function (element, options) {
michael@0 798 var cls = arguments.callee;
michael@0 799 if (!(this instanceof cls)) {
michael@0 800 return new cls(element, options);
michael@0 801 }
michael@0 802 this.__init__(element, options);
michael@0 803 };
michael@0 804
michael@0 805 MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base();
michael@0 806
michael@0 807 MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, {
michael@0 808 /***
michael@0 809
michael@0 810 Change the opacity of an element.
michael@0 811
michael@0 812 @param options: 'from' and 'to' change the starting and ending opacities.
michael@0 813 Must be between 0.0 and 1.0. Default to current opacity and 1.0.
michael@0 814
michael@0 815 ***/
michael@0 816
michael@0 817 __class__ : MochiKit.Visual.Opacity,
michael@0 818
michael@0 819 __init__: function (element, /* optional */options) {
michael@0 820 var b = MochiKit.Base;
michael@0 821 var s = MochiKit.Style;
michael@0 822 this.element = MochiKit.DOM.getElement(element);
michael@0 823 // make this work on IE on elements without 'layout'
michael@0 824 if (this.element.currentStyle &&
michael@0 825 (!this.element.currentStyle.hasLayout)) {
michael@0 826 s.setStyle(this.element, {zoom: 1});
michael@0 827 }
michael@0 828 options = b.update({
michael@0 829 from: s.getStyle(this.element, 'opacity') || 0.0,
michael@0 830 to: 1.0
michael@0 831 }, options || {});
michael@0 832 this.start(options);
michael@0 833 },
michael@0 834
michael@0 835 /** @id MochiKit.Visual.Opacity.prototype.update */
michael@0 836 update: function (position) {
michael@0 837 MochiKit.Style.setStyle(this.element, {'opacity': position});
michael@0 838 }
michael@0 839 });
michael@0 840
michael@0 841 /** @id MochiKit.Visual.Move.prototype */
michael@0 842 MochiKit.Visual.Move = function (element, options) {
michael@0 843 var cls = arguments.callee;
michael@0 844 if (!(this instanceof cls)) {
michael@0 845 return new cls(element, options);
michael@0 846 }
michael@0 847 this.__init__(element, options);
michael@0 848 };
michael@0 849
michael@0 850 MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base();
michael@0 851
michael@0 852 MochiKit.Base.update(MochiKit.Visual.Move.prototype, {
michael@0 853 /***
michael@0 854
michael@0 855 Move an element between its current position to a defined position
michael@0 856
michael@0 857 @param options: 'x' and 'y' for final positions, default to 0, 0.
michael@0 858
michael@0 859 ***/
michael@0 860
michael@0 861 __class__ : MochiKit.Visual.Move,
michael@0 862
michael@0 863 __init__: function (element, /* optional */options) {
michael@0 864 this.element = MochiKit.DOM.getElement(element);
michael@0 865 options = MochiKit.Base.update({
michael@0 866 x: 0,
michael@0 867 y: 0,
michael@0 868 mode: 'relative'
michael@0 869 }, options || {});
michael@0 870 this.start(options);
michael@0 871 },
michael@0 872
michael@0 873 /** @id MochiKit.Visual.Move.prototype.setup */
michael@0 874 setup: function () {
michael@0 875 // Bug in Opera: Opera returns the 'real' position of a static element
michael@0 876 // or relative element that does not have top/left explicitly set.
michael@0 877 // ==> Always set top and left for position relative elements in your
michael@0 878 // stylesheets (to 0 if you do not need them)
michael@0 879 MochiKit.DOM.makePositioned(this.element);
michael@0 880
michael@0 881 var s = this.element.style;
michael@0 882 var originalVisibility = s.visibility;
michael@0 883 var originalDisplay = s.display;
michael@0 884 if (originalDisplay == 'none') {
michael@0 885 s.visibility = 'hidden';
michael@0 886 s.display = '';
michael@0 887 }
michael@0 888
michael@0 889 this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0');
michael@0 890 this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0');
michael@0 891
michael@0 892 if (this.options.mode == 'absolute') {
michael@0 893 // absolute movement, so we need to calc deltaX and deltaY
michael@0 894 this.options.x -= this.originalLeft;
michael@0 895 this.options.y -= this.originalTop;
michael@0 896 }
michael@0 897 if (originalDisplay == 'none') {
michael@0 898 s.visibility = originalVisibility;
michael@0 899 s.display = originalDisplay;
michael@0 900 }
michael@0 901 },
michael@0 902
michael@0 903 /** @id MochiKit.Visual.Move.prototype.update */
michael@0 904 update: function (position) {
michael@0 905 MochiKit.Style.setStyle(this.element, {
michael@0 906 left: Math.round(this.options.x * position + this.originalLeft) + 'px',
michael@0 907 top: Math.round(this.options.y * position + this.originalTop) + 'px'
michael@0 908 });
michael@0 909 }
michael@0 910 });
michael@0 911
michael@0 912 /** @id MochiKit.Visual.Scale */
michael@0 913 MochiKit.Visual.Scale = function (element, percent, options) {
michael@0 914 var cls = arguments.callee;
michael@0 915 if (!(this instanceof cls)) {
michael@0 916 return new cls(element, percent, options);
michael@0 917 }
michael@0 918 this.__init__(element, percent, options);
michael@0 919 };
michael@0 920
michael@0 921 MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base();
michael@0 922
michael@0 923 MochiKit.Base.update(MochiKit.Visual.Scale.prototype, {
michael@0 924 /***
michael@0 925
michael@0 926 Change the size of an element.
michael@0 927
michael@0 928 @param percent: final_size = percent*original_size
michael@0 929
michael@0 930 @param options: several options changing scale behaviour
michael@0 931
michael@0 932 ***/
michael@0 933
michael@0 934 __class__ : MochiKit.Visual.Scale,
michael@0 935
michael@0 936 __init__: function (element, percent, /* optional */options) {
michael@0 937 this.element = MochiKit.DOM.getElement(element);
michael@0 938 options = MochiKit.Base.update({
michael@0 939 scaleX: true,
michael@0 940 scaleY: true,
michael@0 941 scaleContent: true,
michael@0 942 scaleFromCenter: false,
michael@0 943 scaleMode: 'box', // 'box' or 'contents' or {} with provided values
michael@0 944 scaleFrom: 100.0,
michael@0 945 scaleTo: percent
michael@0 946 }, options || {});
michael@0 947 this.start(options);
michael@0 948 },
michael@0 949
michael@0 950 /** @id MochiKit.Visual.Scale.prototype.setup */
michael@0 951 setup: function () {
michael@0 952 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
michael@0 953 this.elementPositioning = MochiKit.Style.getStyle(this.element,
michael@0 954 'position');
michael@0 955
michael@0 956 var ma = MochiKit.Base.map;
michael@0 957 var b = MochiKit.Base.bind;
michael@0 958 this.originalStyle = {};
michael@0 959 ma(b(function (k) {
michael@0 960 this.originalStyle[k] = this.element.style[k];
michael@0 961 }, this), ['top', 'left', 'width', 'height', 'fontSize']);
michael@0 962
michael@0 963 this.originalTop = this.element.offsetTop;
michael@0 964 this.originalLeft = this.element.offsetLeft;
michael@0 965
michael@0 966 var fontSize = MochiKit.Style.getStyle(this.element,
michael@0 967 'font-size') || '100%';
michael@0 968 ma(b(function (fontSizeType) {
michael@0 969 if (fontSize.indexOf(fontSizeType) > 0) {
michael@0 970 this.fontSize = parseFloat(fontSize);
michael@0 971 this.fontSizeType = fontSizeType;
michael@0 972 }
michael@0 973 }, this), ['em', 'px', '%']);
michael@0 974
michael@0 975 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
michael@0 976
michael@0 977 if (/^content/.test(this.options.scaleMode)) {
michael@0 978 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
michael@0 979 } else if (this.options.scaleMode == 'box') {
michael@0 980 this.dims = [this.element.offsetHeight, this.element.offsetWidth];
michael@0 981 } else {
michael@0 982 this.dims = [this.options.scaleMode.originalHeight,
michael@0 983 this.options.scaleMode.originalWidth];
michael@0 984 }
michael@0 985 },
michael@0 986
michael@0 987 /** @id MochiKit.Visual.Scale.prototype.update */
michael@0 988 update: function (position) {
michael@0 989 var currentScale = (this.options.scaleFrom/100.0) +
michael@0 990 (this.factor * position);
michael@0 991 if (this.options.scaleContent && this.fontSize) {
michael@0 992 MochiKit.Style.setStyle(this.element, {
michael@0 993 fontSize: this.fontSize * currentScale + this.fontSizeType
michael@0 994 });
michael@0 995 }
michael@0 996 this.setDimensions(this.dims[0] * currentScale,
michael@0 997 this.dims[1] * currentScale);
michael@0 998 },
michael@0 999
michael@0 1000 /** @id MochiKit.Visual.Scale.prototype.finish */
michael@0 1001 finish: function () {
michael@0 1002 if (this.restoreAfterFinish) {
michael@0 1003 MochiKit.Style.setStyle(this.element, this.originalStyle);
michael@0 1004 }
michael@0 1005 },
michael@0 1006
michael@0 1007 /** @id MochiKit.Visual.Scale.prototype.setDimensions */
michael@0 1008 setDimensions: function (height, width) {
michael@0 1009 var d = {};
michael@0 1010 var r = Math.round;
michael@0 1011 if (/MSIE/.test(navigator.userAgent)) {
michael@0 1012 r = Math.ceil;
michael@0 1013 }
michael@0 1014 if (this.options.scaleX) {
michael@0 1015 d.width = r(width) + 'px';
michael@0 1016 }
michael@0 1017 if (this.options.scaleY) {
michael@0 1018 d.height = r(height) + 'px';
michael@0 1019 }
michael@0 1020 if (this.options.scaleFromCenter) {
michael@0 1021 var topd = (height - this.dims[0])/2;
michael@0 1022 var leftd = (width - this.dims[1])/2;
michael@0 1023 if (this.elementPositioning == 'absolute') {
michael@0 1024 if (this.options.scaleY) {
michael@0 1025 d.top = this.originalTop - topd + 'px';
michael@0 1026 }
michael@0 1027 if (this.options.scaleX) {
michael@0 1028 d.left = this.originalLeft - leftd + 'px';
michael@0 1029 }
michael@0 1030 } else {
michael@0 1031 if (this.options.scaleY) {
michael@0 1032 d.top = -topd + 'px';
michael@0 1033 }
michael@0 1034 if (this.options.scaleX) {
michael@0 1035 d.left = -leftd + 'px';
michael@0 1036 }
michael@0 1037 }
michael@0 1038 }
michael@0 1039 MochiKit.Style.setStyle(this.element, d);
michael@0 1040 }
michael@0 1041 });
michael@0 1042
michael@0 1043 /** @id MochiKit.Visual.Highlight */
michael@0 1044 MochiKit.Visual.Highlight = function (element, options) {
michael@0 1045 var cls = arguments.callee;
michael@0 1046 if (!(this instanceof cls)) {
michael@0 1047 return new cls(element, options);
michael@0 1048 }
michael@0 1049 this.__init__(element, options);
michael@0 1050 };
michael@0 1051
michael@0 1052 MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base();
michael@0 1053
michael@0 1054 MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, {
michael@0 1055 /***
michael@0 1056
michael@0 1057 Highlight an item of the page.
michael@0 1058
michael@0 1059 @param options: 'startcolor' for choosing highlighting color, default
michael@0 1060 to '#ffff99'.
michael@0 1061
michael@0 1062 ***/
michael@0 1063
michael@0 1064 __class__ : MochiKit.Visual.Highlight,
michael@0 1065
michael@0 1066 __init__: function (element, /* optional */options) {
michael@0 1067 this.element = MochiKit.DOM.getElement(element);
michael@0 1068 options = MochiKit.Base.update({
michael@0 1069 startcolor: '#ffff99'
michael@0 1070 }, options || {});
michael@0 1071 this.start(options);
michael@0 1072 },
michael@0 1073
michael@0 1074 /** @id MochiKit.Visual.Highlight.prototype.setup */
michael@0 1075 setup: function () {
michael@0 1076 var b = MochiKit.Base;
michael@0 1077 var s = MochiKit.Style;
michael@0 1078 // Prevent executing on elements not in the layout flow
michael@0 1079 if (s.getStyle(this.element, 'display') == 'none') {
michael@0 1080 this.cancel();
michael@0 1081 return;
michael@0 1082 }
michael@0 1083 // Disable background image during the effect
michael@0 1084 this.oldStyle = {
michael@0 1085 backgroundImage: s.getStyle(this.element, 'background-image')
michael@0 1086 };
michael@0 1087 s.setStyle(this.element, {
michael@0 1088 backgroundImage: 'none'
michael@0 1089 });
michael@0 1090
michael@0 1091 if (!this.options.endcolor) {
michael@0 1092 this.options.endcolor =
michael@0 1093 MochiKit.Color.Color.fromBackground(this.element).toHexString();
michael@0 1094 }
michael@0 1095 if (b.isUndefinedOrNull(this.options.restorecolor)) {
michael@0 1096 this.options.restorecolor = s.getStyle(this.element,
michael@0 1097 'background-color');
michael@0 1098 }
michael@0 1099 // init color calculations
michael@0 1100 this._base = b.map(b.bind(function (i) {
michael@0 1101 return parseInt(
michael@0 1102 this.options.startcolor.slice(i*2 + 1, i*2 + 3), 16);
michael@0 1103 }, this), [0, 1, 2]);
michael@0 1104 this._delta = b.map(b.bind(function (i) {
michael@0 1105 return parseInt(this.options.endcolor.slice(i*2 + 1, i*2 + 3), 16)
michael@0 1106 - this._base[i];
michael@0 1107 }, this), [0, 1, 2]);
michael@0 1108 },
michael@0 1109
michael@0 1110 /** @id MochiKit.Visual.Highlight.prototype.update */
michael@0 1111 update: function (position) {
michael@0 1112 var m = '#';
michael@0 1113 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
michael@0 1114 m += MochiKit.Color.toColorPart(Math.round(this._base[i] +
michael@0 1115 this._delta[i]*position));
michael@0 1116 }, this), [0, 1, 2]);
michael@0 1117 MochiKit.Style.setStyle(this.element, {
michael@0 1118 backgroundColor: m
michael@0 1119 });
michael@0 1120 },
michael@0 1121
michael@0 1122 /** @id MochiKit.Visual.Highlight.prototype.finish */
michael@0 1123 finish: function () {
michael@0 1124 MochiKit.Style.setStyle(this.element,
michael@0 1125 MochiKit.Base.update(this.oldStyle, {
michael@0 1126 backgroundColor: this.options.restorecolor
michael@0 1127 }));
michael@0 1128 }
michael@0 1129 });
michael@0 1130
michael@0 1131 /** @id MochiKit.Visual.ScrollTo */
michael@0 1132 MochiKit.Visual.ScrollTo = function (element, options) {
michael@0 1133 var cls = arguments.callee;
michael@0 1134 if (!(this instanceof cls)) {
michael@0 1135 return new cls(element, options);
michael@0 1136 }
michael@0 1137 this.__init__(element, options);
michael@0 1138 };
michael@0 1139
michael@0 1140 MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base();
michael@0 1141
michael@0 1142 MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, {
michael@0 1143 /***
michael@0 1144
michael@0 1145 Scroll to an element in the page.
michael@0 1146
michael@0 1147 ***/
michael@0 1148
michael@0 1149 __class__ : MochiKit.Visual.ScrollTo,
michael@0 1150
michael@0 1151 __init__: function (element, /* optional */options) {
michael@0 1152 this.element = MochiKit.DOM.getElement(element);
michael@0 1153 this.start(options || {});
michael@0 1154 },
michael@0 1155
michael@0 1156 /** @id MochiKit.Visual.ScrollTo.prototype.setup */
michael@0 1157 setup: function () {
michael@0 1158 var p = MochiKit.Position;
michael@0 1159 p.prepare();
michael@0 1160 var offsets = p.cumulativeOffset(this.element);
michael@0 1161 if (this.options.offset) {
michael@0 1162 offsets.y += this.options.offset;
michael@0 1163 }
michael@0 1164 var max;
michael@0 1165 if (window.innerHeight) {
michael@0 1166 max = window.innerHeight - window.height;
michael@0 1167 } else if (document.documentElement &&
michael@0 1168 document.documentElement.clientHeight) {
michael@0 1169 max = document.documentElement.clientHeight -
michael@0 1170 document.body.scrollHeight;
michael@0 1171 } else if (document.body) {
michael@0 1172 max = document.body.clientHeight - document.body.scrollHeight;
michael@0 1173 }
michael@0 1174 this.scrollStart = p.windowOffset.y;
michael@0 1175 this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart;
michael@0 1176 },
michael@0 1177
michael@0 1178 /** @id MochiKit.Visual.ScrollTo.prototype.update */
michael@0 1179 update: function (position) {
michael@0 1180 var p = MochiKit.Position;
michael@0 1181 p.prepare();
michael@0 1182 window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta));
michael@0 1183 }
michael@0 1184 });
michael@0 1185
michael@0 1186 MochiKit.Visual.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
michael@0 1187
michael@0 1188 MochiKit.Visual.Morph = function (element, options) {
michael@0 1189 var cls = arguments.callee;
michael@0 1190 if (!(this instanceof cls)) {
michael@0 1191 return new cls(element, options);
michael@0 1192 }
michael@0 1193 this.__init__(element, options);
michael@0 1194 };
michael@0 1195
michael@0 1196 MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base();
michael@0 1197
michael@0 1198 MochiKit.Base.update(MochiKit.Visual.Morph.prototype, {
michael@0 1199 /***
michael@0 1200
michael@0 1201 Morph effect: make a transformation from current style to the given style,
michael@0 1202 automatically making a transition between the two.
michael@0 1203
michael@0 1204 ***/
michael@0 1205
michael@0 1206 __class__ : MochiKit.Visual.Morph,
michael@0 1207
michael@0 1208 __init__: function (element, /* optional */options) {
michael@0 1209 this.element = MochiKit.DOM.getElement(element);
michael@0 1210 this.start(options || {});
michael@0 1211 },
michael@0 1212
michael@0 1213 /** @id MochiKit.Visual.Morph.prototype.setup */
michael@0 1214 setup: function () {
michael@0 1215 var b = MochiKit.Base;
michael@0 1216 var style = this.options.style;
michael@0 1217 this.styleStart = {};
michael@0 1218 this.styleEnd = {};
michael@0 1219 this.units = {};
michael@0 1220 var value, unit;
michael@0 1221 for (var s in style) {
michael@0 1222 value = style[s];
michael@0 1223 s = b.camelize(s);
michael@0 1224 if (MochiKit.Visual.CSS_LENGTH.test(value)) {
michael@0 1225 var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
michael@0 1226 value = parseFloat(components[1]);
michael@0 1227 unit = (components.length == 3) ? components[2] : null;
michael@0 1228 this.styleEnd[s] = value;
michael@0 1229 this.units[s] = unit;
michael@0 1230 value = MochiKit.Style.getStyle(this.element, s);
michael@0 1231 components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
michael@0 1232 value = parseFloat(components[1]);
michael@0 1233 this.styleStart[s] = value;
michael@0 1234 } else {
michael@0 1235 var c = MochiKit.Color.Color;
michael@0 1236 value = c.fromString(value);
michael@0 1237 if (value) {
michael@0 1238 this.units[s] = "color";
michael@0 1239 this.styleEnd[s] = value.toHexString();
michael@0 1240 value = MochiKit.Style.getStyle(this.element, s);
michael@0 1241 this.styleStart[s] = c.fromString(value).toHexString();
michael@0 1242
michael@0 1243 this.styleStart[s] = b.map(b.bind(function (i) {
michael@0 1244 return parseInt(
michael@0 1245 this.styleStart[s].slice(i*2 + 1, i*2 + 3), 16);
michael@0 1246 }, this), [0, 1, 2]);
michael@0 1247 this.styleEnd[s] = b.map(b.bind(function (i) {
michael@0 1248 return parseInt(
michael@0 1249 this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16);
michael@0 1250 }, this), [0, 1, 2]);
michael@0 1251 }
michael@0 1252 }
michael@0 1253 }
michael@0 1254 },
michael@0 1255
michael@0 1256 /** @id MochiKit.Visual.Morph.prototype.update */
michael@0 1257 update: function (position) {
michael@0 1258 var value;
michael@0 1259 for (var s in this.styleStart) {
michael@0 1260 if (this.units[s] == "color") {
michael@0 1261 var m = '#';
michael@0 1262 var start = this.styleStart[s];
michael@0 1263 var end = this.styleEnd[s];
michael@0 1264 MochiKit.Base.map(MochiKit.Base.bind(function (i) {
michael@0 1265 m += MochiKit.Color.toColorPart(Math.round(start[i] +
michael@0 1266 (end[i] - start[i])*position));
michael@0 1267 }, this), [0, 1, 2]);
michael@0 1268 this.element.style[s] = m;
michael@0 1269 } else {
michael@0 1270 value = this.styleStart[s] + Math.round((this.styleEnd[s] - this.styleStart[s]) * position * 1000) / 1000 + this.units[s];
michael@0 1271 this.element.style[s] = value;
michael@0 1272 }
michael@0 1273 }
michael@0 1274 }
michael@0 1275 });
michael@0 1276
michael@0 1277 /***
michael@0 1278
michael@0 1279 Combination effects.
michael@0 1280
michael@0 1281 ***/
michael@0 1282
michael@0 1283 /** @id MochiKit.Visual.fade */
michael@0 1284 MochiKit.Visual.fade = function (element, /* optional */ options) {
michael@0 1285 /***
michael@0 1286
michael@0 1287 Fade a given element: change its opacity and hide it in the end.
michael@0 1288
michael@0 1289 @param options: 'to' and 'from' to change opacity.
michael@0 1290
michael@0 1291 ***/
michael@0 1292 var s = MochiKit.Style;
michael@0 1293 var oldOpacity = s.getStyle(element, 'opacity');
michael@0 1294 options = MochiKit.Base.update({
michael@0 1295 from: s.getStyle(element, 'opacity') || 1.0,
michael@0 1296 to: 0.0,
michael@0 1297 afterFinishInternal: function (effect) {
michael@0 1298 if (effect.options.to !== 0) {
michael@0 1299 return;
michael@0 1300 }
michael@0 1301 s.hideElement(effect.element);
michael@0 1302 s.setStyle(effect.element, {'opacity': oldOpacity});
michael@0 1303 }
michael@0 1304 }, options || {});
michael@0 1305 return new MochiKit.Visual.Opacity(element, options);
michael@0 1306 };
michael@0 1307
michael@0 1308 /** @id MochiKit.Visual.appear */
michael@0 1309 MochiKit.Visual.appear = function (element, /* optional */ options) {
michael@0 1310 /***
michael@0 1311
michael@0 1312 Make an element appear.
michael@0 1313
michael@0 1314 @param options: 'to' and 'from' to change opacity.
michael@0 1315
michael@0 1316 ***/
michael@0 1317 var s = MochiKit.Style;
michael@0 1318 var v = MochiKit.Visual;
michael@0 1319 options = MochiKit.Base.update({
michael@0 1320 from: (s.getStyle(element, 'display') == 'none' ? 0.0 :
michael@0 1321 s.getStyle(element, 'opacity') || 0.0),
michael@0 1322 to: 1.0,
michael@0 1323 // force Safari to render floated elements properly
michael@0 1324 afterFinishInternal: function (effect) {
michael@0 1325 v.forceRerendering(effect.element);
michael@0 1326 },
michael@0 1327 beforeSetupInternal: function (effect) {
michael@0 1328 s.setStyle(effect.element, {'opacity': effect.options.from});
michael@0 1329 s.showElement(effect.element);
michael@0 1330 }
michael@0 1331 }, options || {});
michael@0 1332 return new v.Opacity(element, options);
michael@0 1333 };
michael@0 1334
michael@0 1335 /** @id MochiKit.Visual.puff */
michael@0 1336 MochiKit.Visual.puff = function (element, /* optional */ options) {
michael@0 1337 /***
michael@0 1338
michael@0 1339 'Puff' an element: grow it to double size, fading it and make it hidden.
michael@0 1340
michael@0 1341 ***/
michael@0 1342 var s = MochiKit.Style;
michael@0 1343 var v = MochiKit.Visual;
michael@0 1344 element = MochiKit.DOM.getElement(element);
michael@0 1345 var oldStyle = {
michael@0 1346 position: s.getStyle(element, 'position'),
michael@0 1347 top: element.style.top,
michael@0 1348 left: element.style.left,
michael@0 1349 width: element.style.width,
michael@0 1350 height: element.style.height,
michael@0 1351 opacity: s.getStyle(element, 'opacity')
michael@0 1352 };
michael@0 1353 options = MochiKit.Base.update({
michael@0 1354 beforeSetupInternal: function (effect) {
michael@0 1355 MochiKit.Position.absolutize(effect.effects[0].element);
michael@0 1356 },
michael@0 1357 afterFinishInternal: function (effect) {
michael@0 1358 s.hideElement(effect.effects[0].element);
michael@0 1359 s.setStyle(effect.effects[0].element, oldStyle);
michael@0 1360 },
michael@0 1361 scaleContent: true,
michael@0 1362 scaleFromCenter: true
michael@0 1363 }, options || {});
michael@0 1364 return new v.Parallel(
michael@0 1365 [new v.Scale(element, 200,
michael@0 1366 {sync: true, scaleFromCenter: options.scaleFromCenter,
michael@0 1367 scaleContent: options.scaleContent, restoreAfterFinish: true}),
michael@0 1368 new v.Opacity(element, {sync: true, to: 0.0 })],
michael@0 1369 options);
michael@0 1370 };
michael@0 1371
michael@0 1372 /** @id MochiKit.Visual.blindUp */
michael@0 1373 MochiKit.Visual.blindUp = function (element, /* optional */ options) {
michael@0 1374 /***
michael@0 1375
michael@0 1376 Blind an element up: change its vertical size to 0.
michael@0 1377
michael@0 1378 ***/
michael@0 1379 var d = MochiKit.DOM;
michael@0 1380 element = d.getElement(element);
michael@0 1381 var elemClip = d.makeClipping(element);
michael@0 1382 options = MochiKit.Base.update({
michael@0 1383 scaleContent: false,
michael@0 1384 scaleX: false,
michael@0 1385 restoreAfterFinish: true,
michael@0 1386 afterFinishInternal: function (effect) {
michael@0 1387 MochiKit.Style.hideElement(effect.element);
michael@0 1388 d.undoClipping(effect.element, elemClip);
michael@0 1389 }
michael@0 1390 }, options || {});
michael@0 1391
michael@0 1392 return new MochiKit.Visual.Scale(element, 0, options);
michael@0 1393 };
michael@0 1394
michael@0 1395 /** @id MochiKit.Visual.blindDown */
michael@0 1396 MochiKit.Visual.blindDown = function (element, /* optional */ options) {
michael@0 1397 /***
michael@0 1398
michael@0 1399 Blind an element down: restore its vertical size.
michael@0 1400
michael@0 1401 ***/
michael@0 1402 var d = MochiKit.DOM;
michael@0 1403 var s = MochiKit.Style;
michael@0 1404 element = d.getElement(element);
michael@0 1405 var elementDimensions = s.getElementDimensions(element);
michael@0 1406 var elemClip;
michael@0 1407 options = MochiKit.Base.update({
michael@0 1408 scaleContent: false,
michael@0 1409 scaleX: false,
michael@0 1410 scaleFrom: 0,
michael@0 1411 scaleMode: {originalHeight: elementDimensions.h,
michael@0 1412 originalWidth: elementDimensions.w},
michael@0 1413 restoreAfterFinish: true,
michael@0 1414 afterSetupInternal: function (effect) {
michael@0 1415 elemClip = d.makeClipping(effect.element);
michael@0 1416 s.setStyle(effect.element, {height: '0px'});
michael@0 1417 s.showElement(effect.element);
michael@0 1418 },
michael@0 1419 afterFinishInternal: function (effect) {
michael@0 1420 d.undoClipping(effect.element, elemClip);
michael@0 1421 }
michael@0 1422 }, options || {});
michael@0 1423 return new MochiKit.Visual.Scale(element, 100, options);
michael@0 1424 };
michael@0 1425
michael@0 1426 /** @id MochiKit.Visual.switchOff */
michael@0 1427 MochiKit.Visual.switchOff = function (element, /* optional */ options) {
michael@0 1428 /***
michael@0 1429
michael@0 1430 Apply a switch-off-like effect.
michael@0 1431
michael@0 1432 ***/
michael@0 1433 var d = MochiKit.DOM;
michael@0 1434 element = d.getElement(element);
michael@0 1435 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
michael@0 1436 var elemClip;
michael@0 1437 options = MochiKit.Base.update({
michael@0 1438 duration: 0.3,
michael@0 1439 scaleFromCenter: true,
michael@0 1440 scaleX: false,
michael@0 1441 scaleContent: false,
michael@0 1442 restoreAfterFinish: true,
michael@0 1443 beforeSetupInternal: function (effect) {
michael@0 1444 d.makePositioned(effect.element);
michael@0 1445 elemClip = d.makeClipping(effect.element);
michael@0 1446 },
michael@0 1447 afterFinishInternal: function (effect) {
michael@0 1448 MochiKit.Style.hideElement(effect.element);
michael@0 1449 d.undoClipping(effect.element, elemClip);
michael@0 1450 d.undoPositioned(effect.element);
michael@0 1451 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
michael@0 1452 }
michael@0 1453 }, options || {});
michael@0 1454 var v = MochiKit.Visual;
michael@0 1455 return new v.appear(element, {
michael@0 1456 duration: 0.4,
michael@0 1457 from: 0,
michael@0 1458 transition: v.Transitions.flicker,
michael@0 1459 afterFinishInternal: function (effect) {
michael@0 1460 new v.Scale(effect.element, 1, options);
michael@0 1461 }
michael@0 1462 });
michael@0 1463 };
michael@0 1464
michael@0 1465 /** @id MochiKit.Visual.dropOut */
michael@0 1466 MochiKit.Visual.dropOut = function (element, /* optional */ options) {
michael@0 1467 /***
michael@0 1468
michael@0 1469 Make an element fall and disappear.
michael@0 1470
michael@0 1471 ***/
michael@0 1472 var d = MochiKit.DOM;
michael@0 1473 var s = MochiKit.Style;
michael@0 1474 element = d.getElement(element);
michael@0 1475 var oldStyle = {
michael@0 1476 top: s.getStyle(element, 'top'),
michael@0 1477 left: s.getStyle(element, 'left'),
michael@0 1478 opacity: s.getStyle(element, 'opacity')
michael@0 1479 };
michael@0 1480
michael@0 1481 options = MochiKit.Base.update({
michael@0 1482 duration: 0.5,
michael@0 1483 distance: 100,
michael@0 1484 beforeSetupInternal: function (effect) {
michael@0 1485 d.makePositioned(effect.effects[0].element);
michael@0 1486 },
michael@0 1487 afterFinishInternal: function (effect) {
michael@0 1488 s.hideElement(effect.effects[0].element);
michael@0 1489 d.undoPositioned(effect.effects[0].element);
michael@0 1490 s.setStyle(effect.effects[0].element, oldStyle);
michael@0 1491 }
michael@0 1492 }, options || {});
michael@0 1493 var v = MochiKit.Visual;
michael@0 1494 return new v.Parallel(
michael@0 1495 [new v.Move(element, {x: 0, y: options.distance, sync: true}),
michael@0 1496 new v.Opacity(element, {sync: true, to: 0.0})],
michael@0 1497 options);
michael@0 1498 };
michael@0 1499
michael@0 1500 /** @id MochiKit.Visual.shake */
michael@0 1501 MochiKit.Visual.shake = function (element, /* optional */ options) {
michael@0 1502 /***
michael@0 1503
michael@0 1504 Move an element from left to right several times.
michael@0 1505
michael@0 1506 ***/
michael@0 1507 var d = MochiKit.DOM;
michael@0 1508 var v = MochiKit.Visual;
michael@0 1509 var s = MochiKit.Style;
michael@0 1510 element = d.getElement(element);
michael@0 1511 options = MochiKit.Base.update({
michael@0 1512 x: -20,
michael@0 1513 y: 0,
michael@0 1514 duration: 0.05,
michael@0 1515 afterFinishInternal: function (effect) {
michael@0 1516 d.undoPositioned(effect.element);
michael@0 1517 s.setStyle(effect.element, oldStyle);
michael@0 1518 }
michael@0 1519 }, options || {});
michael@0 1520 var oldStyle = {
michael@0 1521 top: s.getStyle(element, 'top'),
michael@0 1522 left: s.getStyle(element, 'left') };
michael@0 1523 return new v.Move(element,
michael@0 1524 {x: 20, y: 0, duration: 0.05, afterFinishInternal: function (effect) {
michael@0 1525 new v.Move(effect.element,
michael@0 1526 {x: -40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
michael@0 1527 new v.Move(effect.element,
michael@0 1528 {x: 40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
michael@0 1529 new v.Move(effect.element,
michael@0 1530 {x: -40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
michael@0 1531 new v.Move(effect.element,
michael@0 1532 {x: 40, y: 0, duration: 0.1, afterFinishInternal: function (effect) {
michael@0 1533 new v.Move(effect.element, options
michael@0 1534 ) }}) }}) }}) }}) }});
michael@0 1535 };
michael@0 1536
michael@0 1537 /** @id MochiKit.Visual.slideDown */
michael@0 1538 MochiKit.Visual.slideDown = function (element, /* optional */ options) {
michael@0 1539 /***
michael@0 1540
michael@0 1541 Slide an element down.
michael@0 1542 It needs to have the content of the element wrapped in a container
michael@0 1543 element with fixed height.
michael@0 1544
michael@0 1545 ***/
michael@0 1546 var d = MochiKit.DOM;
michael@0 1547 var b = MochiKit.Base;
michael@0 1548 var s = MochiKit.Style;
michael@0 1549 element = d.getElement(element);
michael@0 1550 if (!element.firstChild) {
michael@0 1551 throw "MochiKit.Visual.slideDown must be used on a element with a child";
michael@0 1552 }
michael@0 1553 d.removeEmptyTextNodes(element);
michael@0 1554 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0;
michael@0 1555 var elementDimensions = s.getElementDimensions(element);
michael@0 1556 var elemClip;
michael@0 1557 options = b.update({
michael@0 1558 scaleContent: false,
michael@0 1559 scaleX: false,
michael@0 1560 scaleFrom: 0,
michael@0 1561 scaleMode: {originalHeight: elementDimensions.h,
michael@0 1562 originalWidth: elementDimensions.w},
michael@0 1563 restoreAfterFinish: true,
michael@0 1564 afterSetupInternal: function (effect) {
michael@0 1565 d.makePositioned(effect.element);
michael@0 1566 d.makePositioned(effect.element.firstChild);
michael@0 1567 if (/Opera/.test(navigator.userAgent)) {
michael@0 1568 s.setStyle(effect.element, {top: ''});
michael@0 1569 }
michael@0 1570 elemClip = d.makeClipping(effect.element);
michael@0 1571 s.setStyle(effect.element, {height: '0px'});
michael@0 1572 s.showElement(effect.element);
michael@0 1573 },
michael@0 1574 afterUpdateInternal: function (effect) {
michael@0 1575 s.setStyle(effect.element.firstChild,
michael@0 1576 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
michael@0 1577 },
michael@0 1578 afterFinishInternal: function (effect) {
michael@0 1579 d.undoClipping(effect.element, elemClip);
michael@0 1580 // IE will crash if child is undoPositioned first
michael@0 1581 if (/MSIE/.test(navigator.userAgent)) {
michael@0 1582 d.undoPositioned(effect.element);
michael@0 1583 d.undoPositioned(effect.element.firstChild);
michael@0 1584 } else {
michael@0 1585 d.undoPositioned(effect.element.firstChild);
michael@0 1586 d.undoPositioned(effect.element);
michael@0 1587 }
michael@0 1588 s.setStyle(effect.element.firstChild,
michael@0 1589 {bottom: oldInnerBottom});
michael@0 1590 }
michael@0 1591 }, options || {});
michael@0 1592
michael@0 1593 return new MochiKit.Visual.Scale(element, 100, options);
michael@0 1594 };
michael@0 1595
michael@0 1596 /** @id MochiKit.Visual.slideUp */
michael@0 1597 MochiKit.Visual.slideUp = function (element, /* optional */ options) {
michael@0 1598 /***
michael@0 1599
michael@0 1600 Slide an element up.
michael@0 1601 It needs to have the content of the element wrapped in a container
michael@0 1602 element with fixed height.
michael@0 1603
michael@0 1604 ***/
michael@0 1605 var d = MochiKit.DOM;
michael@0 1606 var b = MochiKit.Base;
michael@0 1607 var s = MochiKit.Style;
michael@0 1608 element = d.getElement(element);
michael@0 1609 if (!element.firstChild) {
michael@0 1610 throw "MochiKit.Visual.slideUp must be used on a element with a child";
michael@0 1611 }
michael@0 1612 d.removeEmptyTextNodes(element);
michael@0 1613 var oldInnerBottom = s.getStyle(element.firstChild, 'bottom');
michael@0 1614 var elemClip;
michael@0 1615 options = b.update({
michael@0 1616 scaleContent: false,
michael@0 1617 scaleX: false,
michael@0 1618 scaleMode: 'box',
michael@0 1619 scaleFrom: 100,
michael@0 1620 restoreAfterFinish: true,
michael@0 1621 beforeStartInternal: function (effect) {
michael@0 1622 d.makePositioned(effect.element);
michael@0 1623 d.makePositioned(effect.element.firstChild);
michael@0 1624 if (/Opera/.test(navigator.userAgent)) {
michael@0 1625 s.setStyle(effect.element, {top: ''});
michael@0 1626 }
michael@0 1627 elemClip = d.makeClipping(effect.element);
michael@0 1628 s.showElement(effect.element);
michael@0 1629 },
michael@0 1630 afterUpdateInternal: function (effect) {
michael@0 1631 s.setStyle(effect.element.firstChild,
michael@0 1632 {bottom: (effect.dims[0] - effect.element.clientHeight) + 'px'});
michael@0 1633 },
michael@0 1634 afterFinishInternal: function (effect) {
michael@0 1635 s.hideElement(effect.element);
michael@0 1636 d.undoClipping(effect.element, elemClip);
michael@0 1637 d.undoPositioned(effect.element.firstChild);
michael@0 1638 d.undoPositioned(effect.element);
michael@0 1639 s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
michael@0 1640 }
michael@0 1641 }, options || {});
michael@0 1642 return new MochiKit.Visual.Scale(element, 0, options);
michael@0 1643 };
michael@0 1644
michael@0 1645 // Bug in opera makes the TD containing this element expand for a instance
michael@0 1646 // after finish
michael@0 1647 /** @id MochiKit.Visual.squish */
michael@0 1648 MochiKit.Visual.squish = function (element, /* optional */ options) {
michael@0 1649 /***
michael@0 1650
michael@0 1651 Reduce an element and make it disappear.
michael@0 1652
michael@0 1653 ***/
michael@0 1654 var d = MochiKit.DOM;
michael@0 1655 var b = MochiKit.Base;
michael@0 1656 var elemClip;
michael@0 1657 options = b.update({
michael@0 1658 restoreAfterFinish: true,
michael@0 1659 beforeSetupInternal: function (effect) {
michael@0 1660 elemClip = d.makeClipping(effect.element);
michael@0 1661 },
michael@0 1662 afterFinishInternal: function (effect) {
michael@0 1663 MochiKit.Style.hideElement(effect.element);
michael@0 1664 d.undoClipping(effect.element, elemClip);
michael@0 1665 }
michael@0 1666 }, options || {});
michael@0 1667
michael@0 1668 return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options);
michael@0 1669 };
michael@0 1670
michael@0 1671 /** @id MochiKit.Visual.grow */
michael@0 1672 MochiKit.Visual.grow = function (element, /* optional */ options) {
michael@0 1673 /***
michael@0 1674
michael@0 1675 Grow an element to its original size. Make it zero-sized before
michael@0 1676 if necessary.
michael@0 1677
michael@0 1678 ***/
michael@0 1679 var d = MochiKit.DOM;
michael@0 1680 var v = MochiKit.Visual;
michael@0 1681 var s = MochiKit.Style;
michael@0 1682 element = d.getElement(element);
michael@0 1683 options = MochiKit.Base.update({
michael@0 1684 direction: 'center',
michael@0 1685 moveTransition: v.Transitions.sinoidal,
michael@0 1686 scaleTransition: v.Transitions.sinoidal,
michael@0 1687 opacityTransition: v.Transitions.full,
michael@0 1688 scaleContent: true,
michael@0 1689 scaleFromCenter: false
michael@0 1690 }, options || {});
michael@0 1691 var oldStyle = {
michael@0 1692 top: element.style.top,
michael@0 1693 left: element.style.left,
michael@0 1694 height: element.style.height,
michael@0 1695 width: element.style.width,
michael@0 1696 opacity: s.getStyle(element, 'opacity')
michael@0 1697 };
michael@0 1698
michael@0 1699 var dims = s.getElementDimensions(element);
michael@0 1700 var initialMoveX, initialMoveY;
michael@0 1701 var moveX, moveY;
michael@0 1702
michael@0 1703 switch (options.direction) {
michael@0 1704 case 'top-left':
michael@0 1705 initialMoveX = initialMoveY = moveX = moveY = 0;
michael@0 1706 break;
michael@0 1707 case 'top-right':
michael@0 1708 initialMoveX = dims.w;
michael@0 1709 initialMoveY = moveY = 0;
michael@0 1710 moveX = -dims.w;
michael@0 1711 break;
michael@0 1712 case 'bottom-left':
michael@0 1713 initialMoveX = moveX = 0;
michael@0 1714 initialMoveY = dims.h;
michael@0 1715 moveY = -dims.h;
michael@0 1716 break;
michael@0 1717 case 'bottom-right':
michael@0 1718 initialMoveX = dims.w;
michael@0 1719 initialMoveY = dims.h;
michael@0 1720 moveX = -dims.w;
michael@0 1721 moveY = -dims.h;
michael@0 1722 break;
michael@0 1723 case 'center':
michael@0 1724 initialMoveX = dims.w / 2;
michael@0 1725 initialMoveY = dims.h / 2;
michael@0 1726 moveX = -dims.w / 2;
michael@0 1727 moveY = -dims.h / 2;
michael@0 1728 break;
michael@0 1729 }
michael@0 1730
michael@0 1731 var optionsParallel = MochiKit.Base.update({
michael@0 1732 beforeSetupInternal: function (effect) {
michael@0 1733 s.setStyle(effect.effects[0].element, {height: '0px'});
michael@0 1734 s.showElement(effect.effects[0].element);
michael@0 1735 },
michael@0 1736 afterFinishInternal: function (effect) {
michael@0 1737 d.undoClipping(effect.effects[0].element);
michael@0 1738 d.undoPositioned(effect.effects[0].element);
michael@0 1739 s.setStyle(effect.effects[0].element, oldStyle);
michael@0 1740 }
michael@0 1741 }, options || {});
michael@0 1742
michael@0 1743 return new v.Move(element, {
michael@0 1744 x: initialMoveX,
michael@0 1745 y: initialMoveY,
michael@0 1746 duration: 0.01,
michael@0 1747 beforeSetupInternal: function (effect) {
michael@0 1748 s.hideElement(effect.element);
michael@0 1749 d.makeClipping(effect.element);
michael@0 1750 d.makePositioned(effect.element);
michael@0 1751 },
michael@0 1752 afterFinishInternal: function (effect) {
michael@0 1753 new v.Parallel(
michael@0 1754 [new v.Opacity(effect.element, {
michael@0 1755 sync: true, to: 1.0, from: 0.0,
michael@0 1756 transition: options.opacityTransition
michael@0 1757 }),
michael@0 1758 new v.Move(effect.element, {
michael@0 1759 x: moveX, y: moveY, sync: true,
michael@0 1760 transition: options.moveTransition
michael@0 1761 }),
michael@0 1762 new v.Scale(effect.element, 100, {
michael@0 1763 scaleMode: {originalHeight: dims.h,
michael@0 1764 originalWidth: dims.w},
michael@0 1765 sync: true,
michael@0 1766 scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0,
michael@0 1767 transition: options.scaleTransition,
michael@0 1768 scaleContent: options.scaleContent,
michael@0 1769 scaleFromCenter: options.scaleFromCenter,
michael@0 1770 restoreAfterFinish: true
michael@0 1771 })
michael@0 1772 ], optionsParallel
michael@0 1773 );
michael@0 1774 }
michael@0 1775 });
michael@0 1776 };
michael@0 1777
michael@0 1778 /** @id MochiKit.Visual.shrink */
michael@0 1779 MochiKit.Visual.shrink = function (element, /* optional */ options) {
michael@0 1780 /***
michael@0 1781
michael@0 1782 Shrink an element and make it disappear.
michael@0 1783
michael@0 1784 ***/
michael@0 1785 var d = MochiKit.DOM;
michael@0 1786 var v = MochiKit.Visual;
michael@0 1787 var s = MochiKit.Style;
michael@0 1788 element = d.getElement(element);
michael@0 1789 options = MochiKit.Base.update({
michael@0 1790 direction: 'center',
michael@0 1791 moveTransition: v.Transitions.sinoidal,
michael@0 1792 scaleTransition: v.Transitions.sinoidal,
michael@0 1793 opacityTransition: v.Transitions.none,
michael@0 1794 scaleContent: true,
michael@0 1795 scaleFromCenter: false
michael@0 1796 }, options || {});
michael@0 1797 var oldStyle = {
michael@0 1798 top: element.style.top,
michael@0 1799 left: element.style.left,
michael@0 1800 height: element.style.height,
michael@0 1801 width: element.style.width,
michael@0 1802 opacity: s.getStyle(element, 'opacity')
michael@0 1803 };
michael@0 1804
michael@0 1805 var dims = s.getElementDimensions(element);
michael@0 1806 var moveX, moveY;
michael@0 1807
michael@0 1808 switch (options.direction) {
michael@0 1809 case 'top-left':
michael@0 1810 moveX = moveY = 0;
michael@0 1811 break;
michael@0 1812 case 'top-right':
michael@0 1813 moveX = dims.w;
michael@0 1814 moveY = 0;
michael@0 1815 break;
michael@0 1816 case 'bottom-left':
michael@0 1817 moveX = 0;
michael@0 1818 moveY = dims.h;
michael@0 1819 break;
michael@0 1820 case 'bottom-right':
michael@0 1821 moveX = dims.w;
michael@0 1822 moveY = dims.h;
michael@0 1823 break;
michael@0 1824 case 'center':
michael@0 1825 moveX = dims.w / 2;
michael@0 1826 moveY = dims.h / 2;
michael@0 1827 break;
michael@0 1828 }
michael@0 1829 var elemClip;
michael@0 1830
michael@0 1831 var optionsParallel = MochiKit.Base.update({
michael@0 1832 beforeStartInternal: function (effect) {
michael@0 1833 elemClip = d.makePositioned(effect.effects[0].element);
michael@0 1834 d.makeClipping(effect.effects[0].element);
michael@0 1835 },
michael@0 1836 afterFinishInternal: function (effect) {
michael@0 1837 s.hideElement(effect.effects[0].element);
michael@0 1838 d.undoClipping(effect.effects[0].element, elemClip);
michael@0 1839 d.undoPositioned(effect.effects[0].element);
michael@0 1840 s.setStyle(effect.effects[0].element, oldStyle);
michael@0 1841 }
michael@0 1842 }, options || {});
michael@0 1843
michael@0 1844 return new v.Parallel(
michael@0 1845 [new v.Opacity(element, {
michael@0 1846 sync: true, to: 0.0, from: 1.0,
michael@0 1847 transition: options.opacityTransition
michael@0 1848 }),
michael@0 1849 new v.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, {
michael@0 1850 sync: true, transition: options.scaleTransition,
michael@0 1851 scaleContent: options.scaleContent,
michael@0 1852 scaleFromCenter: options.scaleFromCenter,
michael@0 1853 restoreAfterFinish: true
michael@0 1854 }),
michael@0 1855 new v.Move(element, {
michael@0 1856 x: moveX, y: moveY, sync: true, transition: options.moveTransition
michael@0 1857 })
michael@0 1858 ], optionsParallel
michael@0 1859 );
michael@0 1860 };
michael@0 1861
michael@0 1862 /** @id MochiKit.Visual.pulsate */
michael@0 1863 MochiKit.Visual.pulsate = function (element, /* optional */ options) {
michael@0 1864 /***
michael@0 1865
michael@0 1866 Pulse an element between appear/fade.
michael@0 1867
michael@0 1868 ***/
michael@0 1869 var d = MochiKit.DOM;
michael@0 1870 var v = MochiKit.Visual;
michael@0 1871 var b = MochiKit.Base;
michael@0 1872 var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
michael@0 1873 options = b.update({
michael@0 1874 duration: 3.0,
michael@0 1875 from: 0,
michael@0 1876 afterFinishInternal: function (effect) {
michael@0 1877 MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
michael@0 1878 }
michael@0 1879 }, options || {});
michael@0 1880 var transition = options.transition || v.Transitions.sinoidal;
michael@0 1881 var reverser = b.bind(function (pos) {
michael@0 1882 return transition(1 - v.Transitions.pulse(pos, options.pulses));
michael@0 1883 }, transition);
michael@0 1884 b.bind(reverser, transition);
michael@0 1885 return new v.Opacity(element, b.update({
michael@0 1886 transition: reverser}, options));
michael@0 1887 };
michael@0 1888
michael@0 1889 /** @id MochiKit.Visual.fold */
michael@0 1890 MochiKit.Visual.fold = function (element, /* optional */ options) {
michael@0 1891 /***
michael@0 1892
michael@0 1893 Fold an element, first vertically, then horizontally.
michael@0 1894
michael@0 1895 ***/
michael@0 1896 var d = MochiKit.DOM;
michael@0 1897 var v = MochiKit.Visual;
michael@0 1898 var s = MochiKit.Style;
michael@0 1899 element = d.getElement(element);
michael@0 1900 var oldStyle = {
michael@0 1901 top: element.style.top,
michael@0 1902 left: element.style.left,
michael@0 1903 width: element.style.width,
michael@0 1904 height: element.style.height
michael@0 1905 };
michael@0 1906 var elemClip = d.makeClipping(element);
michael@0 1907 options = MochiKit.Base.update({
michael@0 1908 scaleContent: false,
michael@0 1909 scaleX: false,
michael@0 1910 afterFinishInternal: function (effect) {
michael@0 1911 new v.Scale(element, 1, {
michael@0 1912 scaleContent: false,
michael@0 1913 scaleY: false,
michael@0 1914 afterFinishInternal: function (effect) {
michael@0 1915 s.hideElement(effect.element);
michael@0 1916 d.undoClipping(effect.element, elemClip);
michael@0 1917 s.setStyle(effect.element, oldStyle);
michael@0 1918 }
michael@0 1919 });
michael@0 1920 }
michael@0 1921 }, options || {});
michael@0 1922 return new v.Scale(element, 5, options);
michael@0 1923 };
michael@0 1924
michael@0 1925
michael@0 1926 // Compatibility with MochiKit 1.0
michael@0 1927 MochiKit.Visual.Color = MochiKit.Color.Color;
michael@0 1928 MochiKit.Visual.getElementsComputedStyle = MochiKit.DOM.computedStyle;
michael@0 1929
michael@0 1930 /* end of Rico adaptation */
michael@0 1931
michael@0 1932 MochiKit.Visual.__new__ = function () {
michael@0 1933 var m = MochiKit.Base;
michael@0 1934
michael@0 1935 m.nameFunctions(this);
michael@0 1936
michael@0 1937 this.EXPORT_TAGS = {
michael@0 1938 ":common": this.EXPORT,
michael@0 1939 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
michael@0 1940 };
michael@0 1941
michael@0 1942 };
michael@0 1943
michael@0 1944 MochiKit.Visual.EXPORT = [
michael@0 1945 "roundElement",
michael@0 1946 "roundClass",
michael@0 1947 "tagifyText",
michael@0 1948 "multiple",
michael@0 1949 "toggle",
michael@0 1950 "Parallel",
michael@0 1951 "Opacity",
michael@0 1952 "Move",
michael@0 1953 "Scale",
michael@0 1954 "Highlight",
michael@0 1955 "ScrollTo",
michael@0 1956 "Morph",
michael@0 1957 "fade",
michael@0 1958 "appear",
michael@0 1959 "puff",
michael@0 1960 "blindUp",
michael@0 1961 "blindDown",
michael@0 1962 "switchOff",
michael@0 1963 "dropOut",
michael@0 1964 "shake",
michael@0 1965 "slideDown",
michael@0 1966 "slideUp",
michael@0 1967 "squish",
michael@0 1968 "grow",
michael@0 1969 "shrink",
michael@0 1970 "pulsate",
michael@0 1971 "fold"
michael@0 1972 ];
michael@0 1973
michael@0 1974 MochiKit.Visual.EXPORT_OK = [
michael@0 1975 "Base",
michael@0 1976 "PAIRS"
michael@0 1977 ];
michael@0 1978
michael@0 1979 MochiKit.Visual.__new__();
michael@0 1980
michael@0 1981 MochiKit.Base._exportSymbols(this, MochiKit.Visual);

mercurial