From 1d9c3f9ce943116f5ff54871f2aa1d45184035a5 Mon Sep 17 00:00:00 2001 From: Jaime Pillora Date: Fri, 5 Apr 2013 11:53:48 +1100 Subject: [PATCH] styling + positioning --- dist/notify.js | 194 +++++++++++++++++++++++++++------------------ dist/notify.min.js | 4 +- src/notify.coffee | 176 +++++++++++++++++++++++++--------------- 3 files changed, 231 insertions(+), 143 deletions(-) diff --git a/dist/notify.js b/dist/notify.js index d1e5203..5406083 100644 --- a/dist/notify.js +++ b/dist/notify.js @@ -1,11 +1,11 @@ -/** Notify.js - v0.0.1 - 2013/04/04 +/** Notify.js - v0.0.1 - 2013/04/05 * http://notifyjs.com/ * Copyright (c) 2013 Jaime Pillora - MIT */ (function(window,document,undefined) { 'use strict'; -var Notification, Options, arrowDirs, className, cornerElem, create, getAnchorElement, pluginName, pluginOptions, styles; +var Notification, arrowDirs, bootstrapDetected, className, cornerElem, create, getAnchorElement, inherit, insertCSS, pluginName, pluginOptions, styles; pluginName = 'notify'; @@ -20,8 +20,8 @@ arrowDirs = { styles = { core: { - html: "
\n
\n
\n
", - css: "." + className + "Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n." + className + "Corner ." + className + "Wrapper,\n." + className + "Corner ." + className + "Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n\n}\n\n." + className + "Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n opacity: 0.85;\n}\n\n." + className + "Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n." + className + "Text {\n position: relative;\n}" + html: "
\n
\n
\n
", + css: "." + className + "Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n." + className + "Corner ." + className + "Wrapper,\n." + className + "Corner ." + className + "Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n}\n\n." + className + "Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n opacity: 0.85;\n}\n\n." + className + "Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n." + className + "Text {\n position: relative;\n}\n\n." + className + "Arrow {\n margin-top: " + (2 + (document.documentMode === 5 ? size * -4 : 0)) + ";\n position: absolute;\n z-index: 2;\n margin-left: 10px;\n width: 0;\n height: 0;\n}\n" }, user: { "default": { @@ -29,8 +29,8 @@ styles = { css: "." + className + "Default {\n background: #fff;\n font-size: 11px;\n box-shadow: 0 0 6px #000;\n -moz-box-shadow: 0 0 6px #000;\n -webkit-box-shadow: 0 0 6px #000;\n padding: 4px 10px 4px 8px;\n border-radius: 6px;\n border-style: solid;\n border-width: 2px;\n -moz-border-radius: 6px;\n -webkit-border-radius: 6px;\n white-space: nowrap;\n}" }, bootstrap: { - html: "
\n Warning! \n
", - css: "." + className + "Bootstrap {\n white-space: nowrap;\n}", + html: "
\n \n
", + css: "." + className + "Bootstrap {\n white-space: nowrap;\n margin-bottom: 5px !important;\n padding-left: 25px !important;\n background-repeat: no-repeat;\n background-position: 3px 7px;\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtRJREFUeNqkVc1u00AQHq+dOD+0poIQfkIjalW0SEGqRMuRnHos3DjwAH0ArlyQeANOOSMeAA5VjyBxKBQhgSpVUKKQNGloFdw4cWw2jtfMOna6JOUArDTazXi/b3dm55socPqQhFka++aHBsI8GsopRJERNFlY88FCEk9Yiwf8RhgRyaHFQpPHCDmZG5oX2ui2yilkcTT1AcDsbYC1NMAyOi7zTX2Agx7A9luAl88BauiiQ/cJaZQfIpAlngDcvZZMrl8vFPK5+XktrWlx3/ehZ5r9+t6e+WVnp1pxnNIjgBe4/6dAysQc8dsmHwPcW9C0h3fW1hans1ltwJhy0GxK7XZbUlMp5Ww2eyan6+ft/f2FAqXGK4CvQk5HueFz7D6GOZtIrK+srupdx1GRBBqNBtzc2AiMr7nPplRdKhb1q6q6zjFhrklEFOUutoQ50xcX86ZlqaZpQrfbBdu2R6/G19zX6XSgh6RX5ubyHCM8nqSID6ICrGiZjGYYxojEsiw4PDwMSL5VKsC8Yf4VRYFzMzMaxwjlJSlCyAQ9l0CW44PBADzXhe7xMdi9HtTrdYjFYkDQL0cn4Xdq2/EAE+InCnvADTf2eah4Sx9vExQjkqXT6aAERICMewd/UAp/IeYANM2joxt+q5VI+ieq2i0Wg3l6DNzHwTERPgo1ko7XBXj3vdlsT2F+UuhIhYkp7u7CarkcrFOCtR3H5JiwbAIeImjT/YQKKBtGjRFCU5IUgFRe7fF4cCNVIPMYo3VKqxwjyNAXNepuopyqnld602qVsfRpEkkz+GFL1wPj6ySXBpJtWVa5xlhpcyhBNwpZHmtX8AGgfIExo0ZpzkWVTBGiXCSEaHh62/PoR0p/vHaczxXGnj4bSo+G78lELU80h1uogBwWLf5YlsPmgDEd4M236xjm+8nm4IuE/9u+/PH2JXZfbwz4zw1WbO+SQPpXfwG/BBgAhCNZiSb/pOQAAAAASUVORK5CYII=);\n}", colors: { red: '#eed3d7' } @@ -38,13 +38,15 @@ styles = { } }; +bootstrapDetected = false; + pluginOptions = { autoHide: false, autoHideDelay: 2000, arrowShow: true, arrowSize: 5, - arrowPosition: 'top', - style: 'default', + position: null, + style: null, color: 'red', colors: { red: '#b94a48', @@ -53,22 +55,24 @@ pluginOptions = { blue: '#00f' }, showAnimation: 'slideDown', - showDuration: 200, + showDuration: 400, hideAnimation: 'slideUp', - hideDuration: 600, - gap: 2 + hideDuration: 200, + offsetY: 2, + offsetX: 0 }; create = function(tag) { return $(document.createElement(tag)); }; -Options = function(options) { - return $.extend(this, options); +inherit = function(a, b) { + var F; + F = function() {}; + F.prototype = a; + return $.extend(true, new F(), b); }; -Options.prototype = pluginOptions; - cornerElem = create("div").addClass("" + className + "Corner"); getAnchorElement = function(element) { @@ -86,19 +90,35 @@ getAnchorElement = function(element) { return element; }; +insertCSS = function(style) { + var elem; + if (!(style && style.css)) { + return; + } + elem = style.cssElem; + if (elem) { + return elem.html(style.css); + } else { + elem = create("style").attr('type', 'text/css').html(style.css); + $("head").append(elem); + return style.cssElem = elem; + } +}; + Notification = (function() { function Notification(elem, data, options) { - if ($.type(options) === 'string') { + if (typeof options === 'string') { options = { color: options }; } - this.options = new Options($.isPlainObject(options) ? options : {}); + this.options = inherit(pluginOptions, $.isPlainObject(options) ? options : {}); this.loadCSS(); this.loadHTML(); this.wrapper = $(styles.core.html); this.wrapper.data(pluginName, this); + this.arrow = this.wrapper.find("." + className + "Arrow"); this.container = this.wrapper.find("." + className + "Container"); this.container.append(this.userContainer); if (elem && elem.length) { @@ -107,7 +127,6 @@ Notification = (function() { this.elem = getAnchorElement(elem); this.elem.data(pluginName, this); this.elem.before(this.wrapper); - this.container.css(this.calculateCSS()); } else { this.options.arrowShow = false; cornerElem.prepend(this.wrapper); @@ -117,17 +136,12 @@ Notification = (function() { } Notification.prototype.loadCSS = function(style) { - var elem, name; - name = this.options.style; - style = this.getStyle(name); - elem = style.cssElem; - if (elem) { - return elem.html(style.css); - } else { - elem = create("style").attr('id', "" + name + "-styles").html(style.css); - $("head").append(elem); - return style.cssElem = elem; + var name; + if (!style) { + name = this.options.style; + style = this.getStyle(name); } + return insertCSS(style); }; Notification.prototype.loadHTML = function(style) { @@ -140,33 +154,6 @@ Notification = (function() { return this.text.addClass("" + className + "Text"); }; - Notification.prototype.buildArrow = function() { - var alt, d, dir, showArrow, size; - dir = this.options.arrowPosition; - size = this.options.arrowSize; - alt = arrowDirs[dir]; - this.arrow = create("div"); - this.arrow.addClass(className + 'Arrow').css({ - 'margin-top': 2 + (document.documentMode === 5 ? size * -4 : 0), - 'position': 'relative', - 'z-index': '2', - 'margin-left': 10, - 'width': 0, - 'height': 0 - }).css('border-' + alt, size + 'px solid ' + this.getColor()); - for (d in arrowDirs) { - if (d !== dir && d !== alt) { - this.arrow.css('border-' + d, size + 'px solid transparent'); - } - } - showArrow = this.options.arrowShow && this.elementType !== 'radio'; - if (showArrow) { - return this.arrow.show(); - } else { - return this.arrow.hide(); - } - }; - Notification.prototype.show = function(show) { var hidden; hidden = this.container.parent().parents(':hidden').length > 0; @@ -184,19 +171,67 @@ Notification = (function() { } }; - Notification.prototype.calculateCSS = function() { - var elementPosition, height, left, mainPosition; + Notification.prototype.updatePosition = function() { + var arrowPosition, elementPosition, height, left, mainPosition, position; + if (!this.elem) { + return; + } elementPosition = this.elem.position(); - mainPosition = this.container.parent().position(); - height = this.elem.outerHeight(); - left = elementPosition.left - mainPosition.left; + mainPosition = this.wrapper.position(); + position = this.getPosition(); + arrowPosition = this.updateArrow(position); + left = 0; + height = 0; + switch (position) { + case 'bottom': + height = this.elem.outerHeight(); + break; + case 'right': + left = this.elem.width(); + break; + default: + throw "Unknown position: " + position; + } + left += elementPosition.left - mainPosition.left; if (!navigator.userAgent.match(/MSIE/)) { height += elementPosition.top - mainPosition.top; } - return { - top: height + this.options.gap, - left: left + return this.container.css({ + top: height + this.options.offsetY + arrowPosition.top, + left: left + this.options.offsetX + arrowPosition.left + }); + }; + + Notification.prototype.updateArrow = function(position) { + var d, dir, offsets, size; + offsets = { + top: 0, + left: 0 }; + if (!(this.options.arrowShow && this.elementType !== 'radio')) { + this.arrow.hide(); + return offsets; + } + dir = arrowDirs[position]; + size = this.options.arrowSize; + this.arrow.css('border-' + position, size + 'px solid ' + this.getColor()); + for (d in arrowDirs) { + if (d !== dir && d !== position) { + this.arrow.css('border-' + d, size + 'px solid transparent'); + } + } + this.arrow.show(); + return offsets; + }; + + Notification.prototype.getPosition = function() { + if (this.options.position) { + return this.options.position; + } + if (this.elem.position().left + this.elem.width() + this.wrapper.width() < $(window).width()) { + return 'right'; + } + return 'bottom'; }; Notification.prototype.getColor = function() { @@ -210,6 +245,12 @@ Notification = (function() { if (!name) { name = this.options.style; } + if (bootstrapDetected && !name) { + name = 'bootstrap'; + } + if (!name) { + name = 'default'; + } style = styles.user[name]; if (!style) { throw "Missing style: " + name; @@ -217,8 +258,15 @@ Notification = (function() { return style; }; + Notification.prototype.updateStyle = function() { + var _this = this; + return this.wrapper.find('[data-notify-style]').each(function(i, e) { + return $(e).attr('style', $(e).attr('data-notify-style').replace(/\{\{\s*color\s*\}\}/ig, _this.getColor()).replace(/\{\{\s*position\s*\}\}/ig, _this.getPosition())); + }); + }; + Notification.prototype.run = function(data, options) { - var autohideTimer, color, + var autohideTimer, _this = this; if ($.isPlainObject(options)) { $.extend(this.options, options); @@ -236,17 +284,7 @@ Notification = (function() { } else { this.text.empty().append(data); } - color = this.getColor(); - this.container.find('[data-notify-style]').each(function() { - var s; - s = $(this).attr('data-notify-style'); - return $(this).attr('style', s.replace(/\{\{\s*color\s*\}\}/ig, color)); - }); - if (this.arrow) { - this.arrow.remove(); - } - this.buildArrow(); - this.container.prepend(this.arrow); + this.updatePosition(); this.show(true); if (this.options.autoHide) { clearTimeout(this.autohideTimer); @@ -266,13 +304,11 @@ $(function() { var src; src = $(this).attr('href'); if (src.match(/bootstrap[^\/]*\.css/)) { - $[pluginName].options({ - style: 'bootstrap' - }); + bootstrapDetected = true; return false; } }); - $("head").append(create("style").html(styles.core.css)); + insertCSS(styles.core); return $(document).on('click', "." + className + "Wrapper", function() { var inst; inst = $(this).data(pluginName); diff --git a/dist/notify.min.js b/dist/notify.min.js index b260ea1..bb59c8d 100644 --- a/dist/notify.min.js +++ b/dist/notify.min.js @@ -1,4 +1,4 @@ -/** Notify.js - v0.0.1 - 2013/04/04 +/** Notify.js - v0.0.1 - 2013/04/05 * http://notifyjs.com/ * Copyright (c) 2013 Jaime Pillora - MIT - */(function(t,n){"use strict";var i,e,o,r,s,a,h,p,d,l;p="notify",r="__"+p,o={top:"bottom",bottom:"top",left:"right",right:"left"},l={core:{html:'
\n
\n
\n
',css:"."+r+"Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n."+r+"Corner ."+r+"Wrapper,\n."+r+"Corner ."+r+"Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n\n}\n\n."+r+"Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n opacity: 0.85;\n}\n\n."+r+"Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n."+r+"Text {\n position: relative;\n}"},user:{"default":{html:'
\n \n
',css:"."+r+"Default {\n background: #fff;\n font-size: 11px;\n box-shadow: 0 0 6px #000;\n -moz-box-shadow: 0 0 6px #000;\n -webkit-box-shadow: 0 0 6px #000;\n padding: 4px 10px 4px 8px;\n border-radius: 6px;\n border-style: solid;\n border-width: 2px;\n -moz-border-radius: 6px;\n -webkit-border-radius: 6px;\n white-space: nowrap;\n}"},bootstrap:{html:'
\n Warning! \n
',css:"."+r+"Bootstrap {\n white-space: nowrap;\n}",colors:{red:"#eed3d7"}}}},d={autoHide:!1,autoHideDelay:2e3,arrowShow:!0,arrowSize:5,arrowPosition:"top",style:"default",color:"red",colors:{red:"#b94a48",green:"#33be40",black:"#393939",blue:"#00f"},showAnimation:"slideDown",showDuration:200,hideAnimation:"slideUp",hideDuration:600,gap:2},a=function(t){return $(n.createElement(t))},e=function(t){return $.extend(this,t)},e.prototype=d,s=a("div").addClass(""+r+"Corner"),h=function(t){var n,i;return t.is("[type=radio]")&&(i=t.parents("form:first").find("[type=radio]").filter(function(n,i){return $(i).attr("name")===t.attr("name")}),t=i.first()),n=t.prev(),n.is("span.styled,span.OBS_checkbox")&&(t=n),t},i=function(){function t(t,n,i){"string"===$.type(i)&&(i={color:i}),this.options=new e($.isPlainObject(i)?i:{}),this.loadCSS(),this.loadHTML(),this.wrapper=$(l.core.html),this.wrapper.data(p,this),this.container=this.wrapper.find("."+r+"Container"),this.container.append(this.userContainer),t&&t.length?(this.elementType=t.attr("type"),this.originalElement=t,this.elem=h(t),this.elem.data(p,this),this.elem.before(this.wrapper),this.container.css(this.calculateCSS())):(this.options.arrowShow=!1,s.prepend(this.wrapper)),this.container.hide(),this.run(n)}return t.prototype.loadCSS=function(t){var n,i;return i=this.options.style,t=this.getStyle(i),n=t.cssElem,n?n.html(t.css):(n=a("style").attr("id",""+i+"-styles").html(t.css),$("head").append(n),t.cssElem=n)},t.prototype.loadHTML=function(t){if(t=this.getStyle(name),this.userContainer=$(t.html),this.text=this.userContainer.find("[data-notify=text]"),0===this.text.length)throw"style: "+name+" HTML is missing the: data-notify='text' attribute";return this.text.addClass(""+r+"Text")},t.prototype.buildArrow=function(){var t,i,e,s,h;e=this.options.arrowPosition,h=this.options.arrowSize,t=o[e],this.arrow=a("div"),this.arrow.addClass(r+"Arrow").css({"margin-top":2+(5===n.documentMode?-4*h:0),position:"relative","z-index":"2","margin-left":10,width:0,height:0}).css("border-"+t,h+"px solid "+this.getColor());for(i in o)i!==e&&i!==t&&this.arrow.css("border-"+i,h+"px solid transparent");return s=this.options.arrowShow&&"radio"!==this.elementType,s?this.arrow.show():this.arrow.hide()},t.prototype.show=function(t){var n;return n=this.container.parent().parents(":hidden").length>0,n&&t&&this.container.show(),n&&!t&&this.container.hide(),!n&&t&&this.container[this.options.showAnimation](this.options.showDuration),n||t?undefined:this.container[this.options.hideAnimation](this.options.hideDuration)},t.prototype.calculateCSS=function(){var t,n,i,e;return t=this.elem.position(),e=this.container.parent().position(),n=this.elem.outerHeight(),i=t.left-e.left,navigator.userAgent.match(/MSIE/)||(n+=t.top-e.top),{top:n+this.options.gap,left:i}},t.prototype.getColor=function(){var t;return t=this.getStyle().colors,t&&t[this.options.color]||this.options.colors[this.options.color]||this.options.color},t.prototype.getStyle=function(t){var n;if(t||(t=this.options.style),n=l.user[t],!n)throw"Missing style: "+t;return n},t.prototype.run=function(t,n){var i,e,o=this;return $.isPlainObject(n)?$.extend(this.options,n):"string"===$.type(n)&&(this.options.color=n),this.container&&!t?(this.show(!1),undefined):this.container||t?("string"===$.type(t)?this.text.html(t.replace("\n","
")):this.text.empty().append(t),e=this.getColor(),this.container.find("[data-notify-style]").each(function(){var t;return t=$(this).attr("data-notify-style"),$(this).attr("style",t.replace(/\{\{\s*color\s*\}\}/gi,e))}),this.arrow&&this.arrow.remove(),this.buildArrow(),this.container.prepend(this.arrow),this.show(!0),this.options.autoHide?(clearTimeout(this.autohideTimer),i=setTimeout(function(){return o.show(!1)},this.options.autoHideDelay)):undefined):undefined},t}(),$(function(){return $("body").append(s),$("link").each(function(){var t;return t=$(this).attr("href"),t.match(/bootstrap[^\/]*\.css/)?($[p].options({style:"bootstrap"}),!1):undefined}),$("head").append(a("style").html(l.core.css)),$(n).on("click","."+r+"Wrapper",function(){var t;return t=$(this).data(p),t?t.show(!1):undefined})}),$[p]=function(t,n,e){return t instanceof HTMLElement||t.jquery?$(t)[p](n,e):(e=n,n=t,new i(null,n,e))},$[p].options=function(t){return $.extend(d,t)},$[p].addStyle=function(t){return $.extend(!0,l.user,t)},$.fn[p]=function(t,n){return $(this).each(function(){var e;return e=h($(this)).data(p),e?e.run(t,n):new i($(this),t,n)})}})(window,document); \ No newline at end of file + */(function(t,n){"use strict";var i,o,e,r,s,a,p,h,d,l,u,c;l="notify",r="__"+l,o={top:"bottom",bottom:"top",left:"right",right:"left"},c={core:{html:'
\n
\n
\n
',css:"."+r+"Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n."+r+"Corner ."+r+"Wrapper,\n."+r+"Corner ."+r+"Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n}\n\n."+r+"Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n opacity: 0.85;\n}\n\n."+r+"Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n."+r+"Text {\n position: relative;\n}\n\n."+r+"Arrow {\n margin-top: "+(2+(5===n.documentMode?-4*size:0))+";\n position: absolute;\n z-index: 2;\n margin-left: 10px;\n width: 0;\n height: 0;\n}\n"},user:{"default":{html:'
\n \n
',css:"."+r+"Default {\n background: #fff;\n font-size: 11px;\n box-shadow: 0 0 6px #000;\n -moz-box-shadow: 0 0 6px #000;\n -webkit-box-shadow: 0 0 6px #000;\n padding: 4px 10px 4px 8px;\n border-radius: 6px;\n border-style: solid;\n border-width: 2px;\n -moz-border-radius: 6px;\n -webkit-border-radius: 6px;\n white-space: nowrap;\n}"},bootstrap:{html:'
\n \n
',css:"."+r+"Bootstrap {\n white-space: nowrap;\n margin-bottom: 5px !important;\n padding-left: 25px !important;\n background-repeat: no-repeat;\n background-position: 3px 7px;\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtRJREFUeNqkVc1u00AQHq+dOD+0poIQfkIjalW0SEGqRMuRnHos3DjwAH0ArlyQeANOOSMeAA5VjyBxKBQhgSpVUKKQNGloFdw4cWw2jtfMOna6JOUArDTazXi/b3dm55socPqQhFka++aHBsI8GsopRJERNFlY88FCEk9Yiwf8RhgRyaHFQpPHCDmZG5oX2ui2yilkcTT1AcDsbYC1NMAyOi7zTX2Agx7A9luAl88BauiiQ/cJaZQfIpAlngDcvZZMrl8vFPK5+XktrWlx3/ehZ5r9+t6e+WVnp1pxnNIjgBe4/6dAysQc8dsmHwPcW9C0h3fW1hans1ltwJhy0GxK7XZbUlMp5Ww2eyan6+ft/f2FAqXGK4CvQk5HueFz7D6GOZtIrK+srupdx1GRBBqNBtzc2AiMr7nPplRdKhb1q6q6zjFhrklEFOUutoQ50xcX86ZlqaZpQrfbBdu2R6/G19zX6XSgh6RX5ubyHCM8nqSID6ICrGiZjGYYxojEsiw4PDwMSL5VKsC8Yf4VRYFzMzMaxwjlJSlCyAQ9l0CW44PBADzXhe7xMdi9HtTrdYjFYkDQL0cn4Xdq2/EAE+InCnvADTf2eah4Sx9vExQjkqXT6aAERICMewd/UAp/IeYANM2joxt+q5VI+ieq2i0Wg3l6DNzHwTERPgo1ko7XBXj3vdlsT2F+UuhIhYkp7u7CarkcrFOCtR3H5JiwbAIeImjT/YQKKBtGjRFCU5IUgFRe7fF4cCNVIPMYo3VKqxwjyNAXNepuopyqnld602qVsfRpEkkz+GFL1wPj6ySXBpJtWVa5xlhpcyhBNwpZHmtX8AGgfIExo0ZpzkWVTBGiXCSEaHh62/PoR0p/vHaczxXGnj4bSo+G78lELU80h1uogBwWLf5YlsPmgDEd4M236xjm+8nm4IuE/9u+/PH2JXZfbwz4zw1WbO+SQPpXfwG/BBgAhCNZiSb/pOQAAAAASUVORK5CYII=);\n}",colors:{red:"#eed3d7"}}}},e=!1,u={autoHide:!1,autoHideDelay:2e3,arrowShow:!0,arrowSize:5,position:null,style:null,color:"red",colors:{red:"#b94a48",green:"#33be40",black:"#393939",blue:"#00f"},showAnimation:"slideDown",showDuration:400,hideAnimation:"slideUp",hideDuration:200,offsetY:2,offsetX:0},a=function(t){return $(n.createElement(t))},h=function(t,n){var i;return i=function(){},i.prototype=t,$.extend(!0,new i,n)},s=a("div").addClass(""+r+"Corner"),p=function(t){var n,i;return t.is("[type=radio]")&&(i=t.parents("form:first").find("[type=radio]").filter(function(n,i){return $(i).attr("name")===t.attr("name")}),t=i.first()),n=t.prev(),n.is("span.styled,span.OBS_checkbox")&&(t=n),t},d=function(t){var n;if(t&&t.css)return n=t.cssElem,n?n.html(t.css):(n=a("style").attr("type","text/css").html(t.css),$("head").append(n),t.cssElem=n)},i=function(){function n(t,n,i){"string"==typeof i&&(i={color:i}),this.options=h(u,$.isPlainObject(i)?i:{}),this.loadCSS(),this.loadHTML(),this.wrapper=$(c.core.html),this.wrapper.data(l,this),this.arrow=this.wrapper.find("."+r+"Arrow"),this.container=this.wrapper.find("."+r+"Container"),this.container.append(this.userContainer),t&&t.length?(this.elementType=t.attr("type"),this.originalElement=t,this.elem=p(t),this.elem.data(l,this),this.elem.before(this.wrapper)):(this.options.arrowShow=!1,s.prepend(this.wrapper)),this.container.hide(),this.run(n)}return n.prototype.loadCSS=function(t){var n;return t||(n=this.options.style,t=this.getStyle(n)),d(t)},n.prototype.loadHTML=function(t){if(t=this.getStyle(name),this.userContainer=$(t.html),this.text=this.userContainer.find("[data-notify=text]"),0===this.text.length)throw"style: "+name+" HTML is missing the: data-notify='text' attribute";return this.text.addClass(""+r+"Text")},n.prototype.show=function(t){var n;return n=this.container.parent().parents(":hidden").length>0,n&&t&&this.container.show(),n&&!t&&this.container.hide(),!n&&t&&this.container[this.options.showAnimation](this.options.showDuration),n||t?undefined:this.container[this.options.hideAnimation](this.options.hideDuration)},n.prototype.updatePosition=function(){var t,n,i,o,e,r;if(this.elem){switch(n=this.elem.position(),e=this.wrapper.position(),r=this.getPosition(),t=this.updateArrow(r),o=0,i=0,r){case"bottom":i=this.elem.outerHeight();break;case"right":o=this.elem.width();break;default:throw"Unknown position: "+r}return o+=n.left-e.left,navigator.userAgent.match(/MSIE/)||(i+=n.top-e.top),this.container.css({top:i+this.options.offsetY+t.top,left:o+this.options.offsetX+t.left})}},n.prototype.updateArrow=function(t){var n,i,e,r;if(e={top:0,left:0},!this.options.arrowShow||"radio"===this.elementType)return this.arrow.hide(),e;i=o[t],r=this.options.arrowSize,this.arrow.css("border-"+t,r+"px solid "+this.getColor());for(n in o)n!==i&&n!==t&&this.arrow.css("border-"+n,r+"px solid transparent");return this.arrow.show(),e},n.prototype.getPosition=function(){return this.options.position?this.options.position:this.elem.position().left+this.elem.width()+this.wrapper.width()<$(t).width()?"right":"bottom"},n.prototype.getColor=function(){var t;return t=this.getStyle().colors,t&&t[this.options.color]||this.options.colors[this.options.color]||this.options.color},n.prototype.getStyle=function(t){var n;if(t||(t=this.options.style),e&&!t&&(t="bootstrap"),t||(t="default"),n=c.user[t],!n)throw"Missing style: "+t;return n},n.prototype.updateStyle=function(){var t=this;return this.wrapper.find("[data-notify-style]").each(function(n,i){return $(i).attr("style",$(i).attr("data-notify-style").replace(/\{\{\s*color\s*\}\}/gi,t.getColor()).replace(/\{\{\s*position\s*\}\}/gi,t.getPosition()))})},n.prototype.run=function(t,n){var i,o=this;return $.isPlainObject(n)?$.extend(this.options,n):"string"===$.type(n)&&(this.options.color=n),this.container&&!t?(this.show(!1),undefined):this.container||t?("string"===$.type(t)?this.text.html(t.replace("\n","
")):this.text.empty().append(t),this.updatePosition(),this.show(!0),this.options.autoHide?(clearTimeout(this.autohideTimer),i=setTimeout(function(){return o.show(!1)},this.options.autoHideDelay)):undefined):undefined},n}(),$(function(){return $("body").append(s),$("link").each(function(){var t;return t=$(this).attr("href"),t.match(/bootstrap[^\/]*\.css/)?(e=!0,!1):undefined}),d(c.core),$(n).on("click","."+r+"Wrapper",function(){var t;return t=$(this).data(l),t?t.show(!1):undefined})}),$[l]=function(t,n,o){return t instanceof HTMLElement||t.jquery?$(t)[l](n,o):(o=n,n=t,new i(null,n,o))},$[l].options=function(t){return $.extend(u,t)},$[l].addStyle=function(t){return $.extend(!0,c.user,t)},$.fn[l]=function(t,n){return $(this).each(function(){var o;return o=p($(this)).data(l),o?o.run(t,n):new i($(this),t,n)})}})(window,document); \ No newline at end of file diff --git a/src/notify.coffee b/src/notify.coffee index fc713e0..fba37d8 100644 --- a/src/notify.coffee +++ b/src/notify.coffee @@ -15,8 +15,8 @@ styles = core: html: """
-
-
+
+
""" css: """ @@ -34,7 +34,6 @@ styles = display: block; height: inherit; width: inherit; - } .#{className}Wrapper { @@ -56,6 +55,16 @@ styles = .#{className}Text { position: relative; } + + .#{className}Arrow { + margin-top: #{2 + (if document.documentMode is 5 then (size*-4) else 0)}; + position: absolute; + z-index: 2; + margin-left: 10px; + width: 0; + height: 0; + } + """ user: default: @@ -88,26 +97,33 @@ styles = bootstrap: html: """
- Warning! +
""" css: """ .#{className}Bootstrap { white-space: nowrap; + margin-bottom: 5px !important; + padding-left: 25px !important; + background-repeat: no-repeat; + background-position: 3px 7px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtRJREFUeNqkVc1u00AQHq+dOD+0poIQfkIjalW0SEGqRMuRnHos3DjwAH0ArlyQeANOOSMeAA5VjyBxKBQhgSpVUKKQNGloFdw4cWw2jtfMOna6JOUArDTazXi/b3dm55socPqQhFka++aHBsI8GsopRJERNFlY88FCEk9Yiwf8RhgRyaHFQpPHCDmZG5oX2ui2yilkcTT1AcDsbYC1NMAyOi7zTX2Agx7A9luAl88BauiiQ/cJaZQfIpAlngDcvZZMrl8vFPK5+XktrWlx3/ehZ5r9+t6e+WVnp1pxnNIjgBe4/6dAysQc8dsmHwPcW9C0h3fW1hans1ltwJhy0GxK7XZbUlMp5Ww2eyan6+ft/f2FAqXGK4CvQk5HueFz7D6GOZtIrK+srupdx1GRBBqNBtzc2AiMr7nPplRdKhb1q6q6zjFhrklEFOUutoQ50xcX86ZlqaZpQrfbBdu2R6/G19zX6XSgh6RX5ubyHCM8nqSID6ICrGiZjGYYxojEsiw4PDwMSL5VKsC8Yf4VRYFzMzMaxwjlJSlCyAQ9l0CW44PBADzXhe7xMdi9HtTrdYjFYkDQL0cn4Xdq2/EAE+InCnvADTf2eah4Sx9vExQjkqXT6aAERICMewd/UAp/IeYANM2joxt+q5VI+ieq2i0Wg3l6DNzHwTERPgo1ko7XBXj3vdlsT2F+UuhIhYkp7u7CarkcrFOCtR3H5JiwbAIeImjT/YQKKBtGjRFCU5IUgFRe7fF4cCNVIPMYo3VKqxwjyNAXNepuopyqnld602qVsfRpEkkz+GFL1wPj6ySXBpJtWVa5xlhpcyhBNwpZHmtX8AGgfIExo0ZpzkWVTBGiXCSEaHh62/PoR0p/vHaczxXGnj4bSo+G78lELU80h1uogBwWLf5YlsPmgDEd4M236xjm+8nm4IuE/9u+/PH2JXZfbwz4zw1WbO+SQPpXfwG/BBgAhCNZiSb/pOQAAAAASUVORK5CYII=); } """ colors: red: '#eed3d7' + +bootstrapDetected = false #overridable options pluginOptions = autoHide: false autoHideDelay: 2000 arrowShow: true arrowSize: 5 - arrowPosition: 'top' + position: null # Default style - style: 'default' + style: null # Default color color: 'red' # Color mappings @@ -117,11 +133,12 @@ pluginOptions = black: '#393939' blue: '#00f' showAnimation: 'slideDown' - showDuration: 200 + showDuration: 400 hideAnimation: 'slideUp' - hideDuration: 600 + hideDuration: 200 # Gap between main and element - gap: 2 + offsetY: 2 + offsetX: 0 #TODO add z-index watches #parents: { '.ui-dialog': 5001 } @@ -129,9 +146,10 @@ pluginOptions = create = (tag) -> $ document.createElement(tag) -# inherit plugin options -Options = (options) -> $.extend @, options -Options:: = pluginOptions +inherit = (a, b) -> + F = () -> + F.prototype = a + $.extend true, new F(), b # container for element-less notifications cornerElem = create("div").addClass("#{className}Corner") @@ -148,13 +166,23 @@ getAnchorElement = (element) -> element = fBefore if fBefore.is('span.styled,span.OBS_checkbox') element +insertCSS = (style) -> + return unless style and style.css + elem = style.cssElem + if elem + elem.html style.css + else + elem = create("style").attr('type','text/css').html style.css + $("head").append elem + style.cssElem = elem + #define plugin class Notification #setup instance variables constructor: (elem, data, options) -> - options = {color: options} if $.type(options) is 'string' - @options = new Options if $.isPlainObject(options) then options else {} + options = {color: options} if typeof options is 'string' + @options = inherit pluginOptions, if $.isPlainObject(options) then options else {} #load user css into dom @loadCSS() @@ -163,6 +191,7 @@ class Notification @wrapper = $(styles.core.html) @wrapper.data pluginName, @ + @arrow = @wrapper.find ".#{className}Arrow" @container = @wrapper.find ".#{className}Container" @container.append @userContainer @@ -173,7 +202,6 @@ class Notification @elem.data pluginName, @ # add into dom above elem @elem.before @wrapper - @container.css @calculateCSS() else # @options.autoHide = true @options.arrowShow = false @@ -183,15 +211,11 @@ class Notification @run(data) loadCSS: (style) -> - name = @options.style - style = @getStyle(name) - elem = style.cssElem - if elem - elem.html style.css - else - elem = create("style").attr('id', "#{name}-styles").html style.css - $("head").append elem - style.cssElem = elem + unless style + name = @options.style + style = @getStyle(name) + #insert + insertCSS style loadHTML: (style) -> style = @getStyle(name) @@ -201,27 +225,6 @@ class Notification throw "style: #{name} HTML is missing the: data-notify='text' attribute" @text.addClass "#{className}Text" - buildArrow: -> - dir = @options.arrowPosition - size = @options.arrowSize - alt = arrowDirs[dir] - @arrow = create("div") - @arrow.addClass(className + 'Arrow').css( - 'margin-top': 2 + (if document.documentMode is 5 then (size*-4) else 0) - 'position': 'relative' - 'z-index': '2' - 'margin-left': 10 - 'width': 0 - 'height': 0 - ).css( - 'border-' + alt, size + 'px solid ' + @getColor() - ) - for d of arrowDirs - @arrow.css 'border-' + d, size + 'px solid transparent' if d isnt dir and d isnt alt - - showArrow = @options.arrowShow and @elementType isnt 'radio' - if showArrow then @arrow.show() else @arrow.hide() - show: (show) -> hidden = @container.parent().parents(':hidden').length > 0 @container.show() if hidden and show @@ -229,16 +232,61 @@ class Notification @container[@options.showAnimation] @options.showDuration if not hidden and show @container[@options.hideAnimation] @options.hideDuration if not hidden and not show - calculateCSS: () -> + updatePosition: -> + return unless @elem + # elementPosition = @elem.position() - mainPosition = @container.parent().position() - height = @elem.outerHeight() - left = elementPosition.left - mainPosition.left + mainPosition = @wrapper.position() + + # + position = @getPosition() + arrowPosition = @updateArrow(position) + + #start calculations + left = 0 + height = 0 + switch position + when 'bottom' + height = @elem.outerHeight() + when 'right' + left = @elem.width() + else + throw "Unknown position: #{position}" + + #elem vs wrapper corrections + left += elementPosition.left - mainPosition.left height += (elementPosition.top - mainPosition.top) unless navigator.userAgent.match /MSIE/ - return { - top: height + @options.gap - left: left - } + + #set with user offset, with arrow offet + @container.css + top: height + @options.offsetY + arrowPosition.top + left: left + @options.offsetX + arrowPosition.left + + updateArrow: (position) -> + + offsets = {top: 0, left: 0} + + unless @options.arrowShow and @elementType isnt 'radio' + @arrow.hide() + return offsets + + dir = arrowDirs[position] + size = @options.arrowSize + + @arrow.css 'border-' + position, size + 'px solid ' + @getColor() + for d of arrowDirs + if d isnt dir and d isnt position + @arrow.css 'border-' + d, size + 'px solid transparent' + + @arrow.show() + offsets + + + getPosition: -> + return @options.position if @options.position + if @elem.position().left + @elem.width() + @wrapper.width() < $(window).width() + return 'right' + return 'bottom' getColor: -> styleColors = @getStyle().colors @@ -249,10 +297,19 @@ class Notification getStyle: (name) -> name = @options.style unless name + name = 'bootstrap' if bootstrapDetected and not name + name = 'default' unless name style = styles.user[name] throw "Missing style: #{name}" unless style style + updateStyle: -> + #update colors + @wrapper.find('[data-notify-style]').each (i,e) => + $(e).attr 'style', $(e).attr('data-notify-style'). + replace(/\{\{\s*color\s*\}\}/ig, @getColor()). + replace(/\{\{\s*position\s*\}\}/ig, @getPosition()) + #run plugin run: (data, options) -> #update options @@ -274,14 +331,8 @@ class Notification else @text.empty().append(data) - color = @getColor() - @container.find('[data-notify-style]').each -> - s = $(@).attr 'data-notify-style' - $(@).attr 'style', s.replace /\{\{\s*color\s*\}\}/ig, color - @arrow.remove() if @arrow - @buildArrow() - @container.prepend @arrow + @updatePosition() @show true @@ -300,10 +351,11 @@ $ -> $("link").each -> src = $(@).attr 'href' if src.match /bootstrap[^\/]*\.css/ - $[pluginName].options {style:'bootstrap'} + bootstrapDetected = true return false #add core styles - $("head").append(create("style").html(styles.core.css)) + insertCSS styles.core + #watch all notifications clicks $(document).on 'click', ".#{className}Wrapper", -> inst = $(@).data pluginName