/* --- name: mooGrowl description: a MooTools 1.4 growl style notifications, powered by CSS3 and with scale transforms version: 1.01 authors: - Dimitar Christoff requires: - Core/Element.Event - Core/Element.Style - Core/Element.FX - Core/Element.Morph license: MIT-style license provides: [mooGrowl] ... */ (function() { // enable morph on CSS3 properties mootools does not support currently. Element.Styles.MozTransform = "rotate(@deg) scale(@)"; Element.Styles.MsTransform = "rotate(@deg) scale(@)"; Element.Styles.OTransform = "rotate(@deg) scale(@)"; Element.Styles.WebkitTransform = "rotate(@deg) scale(@)"; Object.append(Fx.CSS.Parsers, { TransformScale: { parse: function(value) { return ((value = value.match(/^scale\((([0-9]*\.)?[0-9]+)\)$/i))) ? parseFloat(value[1]) : false; }, compute: function(from, to, delta) { return Fx.compute(from, to, delta); }, serve: function(value) { return 'scale(' + value + ')'; } } }); var useCSS3Transforms = new Class({ detectTransforms: function() { var transforms = { computed: ['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform'], raw: ['transform', '-webkit-transform', '-moz-transform', '-o-transform', 'msTransform'] }; // do some feature detection to determine what scale transform methods are available var testEl = new Element("div"), self = this; this.scaleTransform = transforms.computed.some(function(el, index) { var test = el in testEl.style; if (test) { self.prop = transforms.raw[index]; } return test; }); if (!this.prop) { this.prop = "opacity"; } } }); var growl = this.mooGrowl = new Class({ Implements: [Options,Events,useCSS3Transforms], options: { notificationDelay: 5000, styles: { right: { position: "fixed", top: 50, right: 50, width: 250, background: "transparent", zIndex: 10000 }, left: { position: "fixed", top: 50, left: 50, width: 250, background: "transparent", zIndex: 10000 } }, position: "right" }, initialize: function(options) { this.setOptions(options); this.detectTransforms(); this.setupContainer(); this.messages = []; }, setupContainer: function() { this.element = new Element("div#growlContainer", { styles: this.options.styles[this.options.position] || this.options.style.right }).inject(document.body); var self = this, timer; this.element.addEvents({ "mouseenter:relay(div.growlWrap)": function(e, el) { clearTimeout(timer); var msgObj = el.retrieve("msgObj"); if (!msgObj.sticky) { clearTimeout(el.retrieve("timer")); } }, "mouseleave:relay(div.growlWrap)": function(e, el) { timer = setTimeout(function() { var msgObj = el.retrieve("msgObj"); if (!msgObj.sticky) { self.setHide(el); } }, 500); } }); }, notify: function(msgObj) { msgObj.delay = msgObj.delay || 0; (function() { if (msgObj.title) msgObj.title = ["<strong>", msgObj.title, "</strong>"].join(""); var msg = new Element("div.hide.growlWrap".substitute(msgObj), { html: "<div class='growlInner'><strong>{title}</strong>{text}</div>".substitute(msgObj) }).inject(this.element).store("msgObj", msgObj); if (msgObj.className) { msg.addClass(msgObj.className) } this.messages.push(msgObj); this.show(msg, msgObj.sticky); if (!msgObj.sticky) { this.setHide(msg); } else { msg.addEvent("click", this.hide.bind(this, msg)); } }).delay(msgObj.delay, this); }, setHide: function(msg) { msg.store("timer", setTimeout(function() { this.hide(msg); }.bind(this), this.options.notificationDelay)); }, show: function(el, sticky) { var self = this, obj = { opacity: [0, .95], marginTop: [300,0] }; if (this.scaleTransform) { obj[self.prop] = ["scale(0)", "scale(1)"]; } el.set("morph", { onStart: function() { this.element.setStyle("opacity", 0).removeClass("hide"); }, onComplete: function() { this.removeEvents("complete"); this.removeEvents("start"); self.fireEvent("open", this.element); } }).morph(obj); if (sticky) { el.set({ styles: { cursor: "pointer" }, title: "click to dismiss" }).addClass("sticky"); } }, hide: function(el) { var self = this, obj = { opacity: [.95, 0], marginTop: [0, -300] }; if (this.scaleTransform) { obj[self.prop] = ["scale(1)", "scale(0)"]; } el.set("morph", { onStart: function() { this.element.setStyle("position", "absolute"); // self.element.setStyle("padding-top", this.element.getSize().y).tween("padding-top", 0); }, onComplete: function() { this.removeEvents("complete"); self.fireEvent("close", this.element); (function() { this.element.destroy(); }).delay(500, this); } }).morph(obj); }, toElement: function() { return this.element; } }); })();