testing/mochitest/tests/MochiKit-1.4.2/MochiKit/Visual.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial