From 930f9903c5ef90bdc0d7273f05dcd84b04c823ce Mon Sep 17 00:00:00 2001 From: Jaime Pillora Date: Fri, 31 May 2013 13:18:43 +1000 Subject: [PATCH] work in progress, positioning --- dist/notify.js | 158 +++++++++++++++++++++------------------ dist/notify.min.js | 4 +- examples/position.html | 6 +- src/notify.coffee | 165 +++++++++++++++++++++++------------------ 4 files changed, 184 insertions(+), 149 deletions(-) diff --git a/dist/notify.js b/dist/notify.js index b7162c5..922c134 100644 --- a/dist/notify.js +++ b/dist/notify.js @@ -1,11 +1,12 @@ -/** Notify.js - v0.0.1 - 2013/05/30 +/** Notify.js - v0.0.1 - 2013/05/31 * http://notifyjs.com/ * Copyright (c) 2013 Jaime Pillora - MIT */ (function(window,document,undefined) { 'use strict'; -var Notification, className, cornerElem, createElem, getAnchorElement, incr, inherit, insertCSS, opposites, parsePosition, pluginName, pluginOptions, positions, styles; +var Notification, className, cornerElem, createElem, getAnchorElement, hPositions, incr, inherit, insertCSS, mainPositions, opposites, parsePosition, pluginName, pluginOptions, positions, realign, styles, vPositions, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; pluginName = 'notify'; @@ -20,6 +21,12 @@ positions = { r: 'right' }; +hPositions = ['l', 'c', 'r']; + +vPositions = ['t', 'm', 'b']; + +mainPositions = ['t', 'b', 'l', 'r']; + opposites = { t: 'b', m: null, @@ -44,8 +51,8 @@ parsePosition = function(str) { 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." + className + "Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n border: thin solid red;\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: 2px;\n position: absolute;\n z-index: 2;\n margin-left: 10px;\n width: 0;\n height: 0;\n}\n" + html: "
\n
\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}\n\n." + className + "Debug {\n position: absolute;\n border: 3px solid red;\n height: 0;\n width: 0;\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 position: absolute;\n z-index: 2;\n width: 0;\n height: 0;\n}\n" }, user: { "default": { @@ -65,7 +72,7 @@ styles = { pluginOptions = { autoHide: false, autoHideDelay: 2000, - arrowShow: false, + arrowShow: true, arrowSize: 5, position: 'bottom', style: 'default', @@ -80,7 +87,7 @@ pluginOptions = { showDuration: 400, hideAnimation: 'slideUp', hideDuration: 200, - offsetY: 2, + offsetY: 0, offsetX: 0 }; @@ -108,11 +115,8 @@ getAnchorElement = function(element) { return element; }; -incr = function(obj, pos, val, useOpposite) { +incr = function(obj, pos, val) { var opp, temp; - if (useOpposite == null) { - useOpposite = true; - } if (typeof val === 'string') { val = parseInt(val, 10); } else if (typeof val !== 'number') { @@ -124,9 +128,6 @@ incr = function(obj, pos, val, useOpposite) { opp = positions[opposites[pos.charAt(0)]]; temp = pos; if (obj[opp] !== undefined) { - if (!useOpposite) { - return; - } pos = positions[opp.charAt(0)]; val *= -1; } @@ -135,10 +136,20 @@ incr = function(obj, pos, val, useOpposite) { } else { obj[pos] += val; } - console.log("incr (" + opp + ">>" + temp + ") " + pos + " by " + val); return null; }; +realign = function(alignment, inner, outer) { + if (alignment === 'l' || alignment === 't') { + return 0; + } else if (alignment === 'c' || alignment === 'm') { + return outer / 2 - inner / 2; + } else if (alignment === 'r' || alignment === 'b') { + return outer - inner; + } + throw "Invalid alignment"; +}; + insertCSS = function(style) { var elem; if (!(style && style.css)) { @@ -226,82 +237,88 @@ Notification = (function() { } else if (!hidden && !show) { fn = this.options.hideAnimation; args.push(this.options.hideDuration); + } else { + return callback(); } args.push(callback); return elems[fn].apply(elems, args); }; Notification.prototype.updatePosition = function() { - var elementPosition, p, position, wrapperPosition; + var arrowCss, color, contH, contW, css, elemH, elemPos, elemW, mainFull, margin, opp, oppFull, pAlign, pArrow, pMain, padding, pos, posFull, position, size, wrapPos, _i, _len; if (!this.elem) { return; } - elementPosition = this.elem.position(); - wrapperPosition = this.wrapper.position(); + elemPos = this.elem.position(); + elemH = this.elem.outerHeight(); + elemW = this.elem.outerWidth(); + wrapPos = this.wrapper.position(); + contH = this.container.height(); + contW = this.container.width(); position = this.getPosition(); - console.log(this.elem[0]); - console.log("update position", position, " elem ", elementPosition, " main ", wrapperPosition); - p = {}; - switch (position[0]) { - case 'b': - incr(p, 'top', this.elem.outerHeight()); - break; - case 't': - incr(p, 'bottom', 0); - break; - case 'l': - incr(p, 'right', 0); - break; - case 'r': - incr(p, 'left', this.elem.outerWidth()); - break; - default: - throw "Unknown position: " + position; + console.log(position); + pMain = position[0]; + pAlign = position[1]; + pArrow = position[2] || pAlign; + mainFull = positions[pMain]; + opp = opposites[pMain]; + oppFull = positions[opp]; + css = {}; + css[oppFull] = pMain === 'b' ? elemH : pMain === 'r' ? elemW : 0; + incr(css, 'left', elemPos.left - wrapPos.left); + margin = parseInt(this.elem.css("margin-left"), 10); + if (margin) { + incr(css, 'left', margin); } - if (!navigator.userAgent.match(/MSIE/)) { - incr(p, 'top', elementPosition.top - wrapperPosition.top); - } - incr(p, 'left', elementPosition.left - wrapperPosition.left); - return this.container.css(p); - }; - - Notification.prototype.updateArrow = function(p, position) { - var d, dir, size; - if (!(this.options.arrowShow && this.elementType !== 'radio')) { - this.arrow.hide(); - return; - } - dir = arrowDirs[position]; - size = this.options.arrowSize; - this.arrow.css('border-' + position, size + 'px solid ' + this.getColor()); - this.arrow.css(p); - for (d in arrowDirs) { - if (d !== dir && d !== position) { - this.arrow.css('border-' + d, size + 'px solid transparent'); + if (/^inline/.test(this.elem.css('display'))) { + padding = parseInt(this.elem.css("padding-top"), 10); + if (padding) { + incr(css, 'top', -padding); } } - switch (position) { - case 'bottom': - p.top += size; - break; - case 'right': - p.left += size; + incr(css, 'top', this.options.offsetY); + incr(css, 'left', this.options.offsetX); + if (!this.options.arrowShow) { + this.arrow.hide(); + } else { + size = this.options.arrowSize; + arrowCss = $.extend({}, css); + for (_i = 0, _len = mainPositions.length; _i < _len; _i++) { + pos = mainPositions[_i]; + posFull = positions[pos]; + if (pos === opp) { + continue; + } + color = posFull === mainFull ? this.getColor() : 'transparent'; + arrowCss["border-" + posFull] = "" + size + "px solid " + color; + } + incr(css, positions[opp], size); + this.arrow.css(arrowCss).show(); } - return this.arrow.show(); + if (__indexOf.call(vPositions, pMain) >= 0) { + incr(css, 'left', realign(pAlign, contW, elemW)); + } + if (__indexOf.call(hPositions, pMain) >= 0) { + incr(css, 'top', realign(pAlign, contH, elemH)); + } + if (this.container.is(":visible")) { + css.display = 'block'; + } + return this.container.removeAttr('style').css(css); }; Notification.prototype.getPosition = function() { - var pos, text; + var pos, text, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; text = this.options.position; pos = parsePosition(text); if (pos.length === 0) { - pos.push('b'); + pos[0] = 'b'; } - if (pos.length === 1 && pos[0] === 'l' || pos[0] === 'r') { - pos.push('m'); + if (_ref = pos[0], __indexOf.call(mainPositions, _ref) < 0) { + throw "Must be one of [" + mainPositions + "]"; } - if (pos.length === 1) { - pos.push('l'); + if (pos.length === 1 || ((_ref1 = pos[0], __indexOf.call(vPositions, _ref1) >= 0) && (_ref2 = pos[1], __indexOf.call(hPositions, _ref2) < 0)) || ((_ref3 = pos[0], __indexOf.call(hPositions, _ref3) >= 0) && (_ref4 = pos[1], __indexOf.call(vPositions, _ref4) < 0))) { + pos[1] = (_ref5 = pos[0], __indexOf.call(hPositions, _ref5) >= 0) ? 'm' : 'l'; } if (!this.options.autoReposition) { return pos; @@ -338,8 +355,7 @@ Notification = (function() { }; Notification.prototype.run = function(data, options) { - var autohideTimer, - _this = this; + var _this = this; if ($.isPlainObject(options)) { $.extend(this.options, options); } else if ($.type(options) === 'string') { @@ -360,7 +376,7 @@ Notification = (function() { this.show(true); if (this.options.autoHide) { clearTimeout(this.autohideTimer); - return autohideTimer = setTimeout(function() { + return this.autohideTimer = setTimeout(function() { return _this.show(false); }, this.options.autoHideDelay); } diff --git a/dist/notify.min.js b/dist/notify.min.js index 122a72b..58a87fb 100644 --- a/dist/notify.min.js +++ b/dist/notify.min.js @@ -1,4 +1,4 @@ -/** Notify.js - v0.0.1 - 2013/05/30 +/** Notify.js - v0.0.1 - 2013/05/31 * http://notifyjs.com/ * Copyright (c) 2013 Jaime Pillora - MIT - */(function(t,n,o){"use strict";var e,i,r,s,a,p,h,l,u,d,c,f,w,y;c="notify",i="__"+c,w={t:"top",m:"middle",b:"bottom",l:"left",c:"center",r:"right"},u={t:"b",m:null,b:"t",l:"r",c:null,r:"l"},d=function(t){var n;return n=[],$.each(t.split(/\W+/),function(t,e){var i;return i=e.toLowerCase().charAt(0),w[i]?n.push(i):o}),n},y={core:{html:'
\n
\n
\n
',css:"."+i+"Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n."+i+"Corner ."+i+"Wrapper,\n."+i+"Corner ."+i+"Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n}\n\n."+i+"Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n border: thin solid red;\n}\n\n."+i+"Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n."+i+"Text {\n position: relative;\n}\n\n."+i+"Arrow {\n margin-top: 2px;\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:"."+i+"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:"."+i+"Bootstrap {\n white-space: nowrap;\n margin: 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"}}}},f={autoHide:!1,autoHideDelay:2e3,arrowShow:!1,arrowSize:5,position:"bottom",style:"default",color:"red",colors:{red:"#b94a48",green:"#33be40",black:"#393939",blue:"#00f"},showAnimation:"slideDown",showDuration:400,hideAnimation:"slideUp",hideDuration:200,offsetY:2,offsetX:0},s=function(t){return $("<"+t+">")},h=function(t,n){var o;return o=function(){},o.prototype=t,$.extend(!0,new o,n)},r=s("div").addClass(""+i+"Corner"),a=function(t){var n;return t.is("[type=radio]")&&(n=t.parents("form:first").find("[type=radio]").filter(function(n,o){return $(o).attr("name")===t.attr("name")}),t=n.first()),t},p=function(t,n,e,i){var r,s;if(null==i&&(i=!0),"string"==typeof e)e=parseInt(e,10);else if("number"!=typeof e)return;if(!isNaN(e)){if(r=w[u[n.charAt(0)]],s=n,t[r]!==o){if(!i)return;n=w[r.charAt(0)],e*=-1}return t[n]===o?t[n]=e:t[n]+=e,console.log("incr ("+r+">>"+s+") "+n+" by "+e),null}},l=function(t){var n;if(t&&t.css&&(n=t.cssElem,!n)){n=s("style"),$("head").append(n),t.cssElem=n;try{return n.html(t.css)}catch(o){return n[0].styleSheet.cssText=t.css}}},e=function(){function t(t,n,o){"string"==typeof o&&(o={color:o}),this.options=h(f,$.isPlainObject(o)?o:{}),this.loadCSS(),this.loadHTML(),this.wrapper=$(y.core.html),this.wrapper.data(i,this),this.arrow=this.wrapper.find("."+i+"Arrow"),this.container=this.wrapper.find("."+i+"Container"),this.container.append(this.userContainer),t&&t.length?(this.elementType=t.attr("type"),this.originalElement=t,this.elem=a(t),this.elem.data(i,this),this.elem.before(this.wrapper)):(this.options.arrowShow=!1,r.prepend(this.wrapper)),this.container.hide(),this.run(n)}return t.prototype.loadCSS=function(t){var n;return t||(n=this.options.style,t=this.getStyle(n)),l(t)},t.prototype.loadHTML=function(){var t;if(t=this.getStyle(),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(""+i+"Text")},t.prototype.show=function(t,n){var o,e,i,r;return null==n&&(n=$.noop),r=this.container.parent().parents(":hidden").length>0,e=this.container.add(this.arrow),o=[],r&&t?i="show":r&&!t?i="hide":!r&&t?(i=this.options.showAnimation,o.push(this.options.showDuration)):r||t||(i=this.options.hideAnimation,o.push(this.options.hideDuration)),o.push(n),e[i].apply(e,o)},t.prototype.updatePosition=function(){var t,n,o,e;if(this.elem){switch(t=this.elem.position(),e=this.wrapper.position(),o=this.getPosition(),console.log(this.elem[0]),console.log("update position",o," elem ",t," main ",e),n={},o[0]){case"b":p(n,"top",this.elem.outerHeight());break;case"t":p(n,"bottom",0);break;case"l":p(n,"right",0);break;case"r":p(n,"left",this.elem.outerWidth());break;default:throw"Unknown position: "+o}return navigator.userAgent.match(/MSIE/)||p(n,"top",t.top-e.top),p(n,"left",t.left-e.left),this.container.css(n)}},t.prototype.updateArrow=function(t,n){var e,i,r;if(!this.options.arrowShow||"radio"===this.elementType)return this.arrow.hide(),o;i=arrowDirs[n],r=this.options.arrowSize,this.arrow.css("border-"+n,r+"px solid "+this.getColor()),this.arrow.css(t);for(e in arrowDirs)e!==i&&e!==n&&this.arrow.css("border-"+e,r+"px solid transparent");switch(n){case"bottom":t.top+=r;break;case"right":t.left+=r}return this.arrow.show()},t.prototype.getPosition=function(){var t,n;if(n=this.options.position,t=d(n),0===t.length&&t.push("b"),(1===t.length&&"l"===t[0]||"r"===t[0])&&t.push("m"),1===t.length&&t.push("l"),!this.options.autoReposition)return t;throw"Not implemented"},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),t||(t="default"),n=y.user[t],!n)throw"Missing style: "+t;return n},t.prototype.updateStyle=function(){var t=this;return this.wrapper.find("[data-notify-style]").each(function(n,o){return $(o).attr("style",$(o).attr("data-notify-style").replace(/\{\{\s*color\s*\}\}/gi,t.getColor()))})},t.prototype.run=function(t,n){var e,i=this;return $.isPlainObject(n)?$.extend(this.options,n):"string"===$.type(n)&&(this.options.color=n),this.container&&!t?(this.show(!1),o):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),e=setTimeout(function(){return i.show(!1)},this.options.autoHideDelay)):o):o},t.prototype.destroy=function(){var t=this;return this.show(!1,function(){return t.wrapper.remove()})},t}(),$(function(){return $("body").append(r),$("link").each(function(){var t,n;return n=$(this).attr("href"),n.match(/bootstrap/)?(t=!0,!1):o}),l(y.core),$(n).on("click","."+i+"Wrapper",function(){var t;return(t=$(this).data(i))?t.elem?t.show(!1):t.destroy():o})}),$[c]=function(t,n,o){return t&&t.nodeName||t.jquery?$(t)[c](n,o):(o=n,n=t,new e(null,n,o)),t},$[c].options=function(t){return $.extend(f,t)},$[c].styles=function(t){return $.extend(!0,y.user,t)},$[c].insertCSS=l,$.fn[c]=function(t,n){return $(this).each(function(){var o;return o=a($(this)).data(i),o?o.run(t,n):new e($(this),t,n)}),this}})(window,document); \ No newline at end of file + */(function(t,n,i){"use strict";var e,o,r,s,a,l,h,p,d,u,c,f,w,y,m,g,A,b,x=[].indexOf||function(t){for(var n=0,i=this.length;i>n;n++)if(n in this&&this[n]===t)return n;return-1};w="notify",o="__"+w,m={t:"top",m:"middle",b:"bottom",l:"left",c:"center",r:"right"},l=["l","c","r"],b=["t","m","b"],u=["t","b","l","r"],c={t:"b",m:null,b:"t",l:"r",c:null,r:"l"},f=function(t){var n;return n=[],$.each(t.split(/\W+/),function(t,e){var o;return o=e.toLowerCase().charAt(0),m[o]?n.push(o):i}),n},A={core:{html:'
\n
\n
\n
\n
',css:"."+o+"Corner {\n position: fixed;\n top: 0;\n right: 0;\n margin: 5px;\n z-index: 1050;\n}\n\n."+o+"Corner ."+o+"Wrapper,\n."+o+"Corner ."+o+"Container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n}\n\n."+o+"Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n}\n\n."+o+"Debug {\n position: absolute;\n border: 3px solid red;\n height: 0;\n width: 0;\n}\n\n."+o+"Container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n."+o+"Text {\n position: relative;\n}\n\n."+o+"Arrow {\n position: absolute;\n z-index: 2;\n width: 0;\n height: 0;\n}\n"},user:{"default":{html:'
\n \n
',css:"."+o+"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:"."+o+"Bootstrap {\n white-space: nowrap;\n margin: 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"}}}},y={autoHide:!1,autoHideDelay:2e3,arrowShow:!0,arrowSize:5,position:"bottom",style:"default",color:"red",colors:{red:"#b94a48",green:"#33be40",black:"#393939",blue:"#00f"},showAnimation:"slideDown",showDuration:400,hideAnimation:"slideUp",hideDuration:200,offsetY:0,offsetX:0},s=function(t){return $("<"+t+">")},p=function(t,n){var i;return i=function(){},i.prototype=t,$.extend(!0,new i,n)},r=s("div").addClass(""+o+"Corner"),a=function(t){var n;return t.is("[type=radio]")&&(n=t.parents("form:first").find("[type=radio]").filter(function(n,i){return $(i).attr("name")===t.attr("name")}),t=n.first()),t},h=function(t,n,e){var o,r;if("string"==typeof e)e=parseInt(e,10);else if("number"!=typeof e)return;if(!isNaN(e))return o=m[c[n.charAt(0)]],r=n,t[o]!==i&&(n=m[o.charAt(0)],e*=-1),t[n]===i?t[n]=e:t[n]+=e,null},g=function(t,n,i){if("l"===t||"t"===t)return 0;if("c"===t||"m"===t)return i/2-n/2;if("r"===t||"b"===t)return i-n;throw"Invalid alignment"},d=function(t){var n;if(t&&t.css&&(n=t.cssElem,!n)){n=s("style"),$("head").append(n),t.cssElem=n;try{return n.html(t.css)}catch(i){return n[0].styleSheet.cssText=t.css}}},e=function(){function t(t,n,i){"string"==typeof i&&(i={color:i}),this.options=p(y,$.isPlainObject(i)?i:{}),this.loadCSS(),this.loadHTML(),this.wrapper=$(A.core.html),this.wrapper.data(o,this),this.arrow=this.wrapper.find("."+o+"Arrow"),this.container=this.wrapper.find("."+o+"Container"),this.container.append(this.userContainer),t&&t.length?(this.elementType=t.attr("type"),this.originalElement=t,this.elem=a(t),this.elem.data(o,this),this.elem.before(this.wrapper)):(this.options.arrowShow=!1,r.prepend(this.wrapper)),this.container.hide(),this.run(n)}return t.prototype.loadCSS=function(t){var n;return t||(n=this.options.style,t=this.getStyle(n)),d(t)},t.prototype.loadHTML=function(){var t;if(t=this.getStyle(),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(""+o+"Text")},t.prototype.show=function(t,n){var i,e,o,r;if(null==n&&(n=$.noop),r=this.container.parent().parents(":hidden").length>0,e=this.container.add(this.arrow),i=[],r&&t)o="show";else if(r&&!t)o="hide";else if(!r&&t)o=this.options.showAnimation,i.push(this.options.showDuration);else{if(r||t)return n();o=this.options.hideAnimation,i.push(this.options.hideDuration)}return i.push(n),e[o].apply(e,i)},t.prototype.updatePosition=function(){var t,n,i,e,o,r,s,a,p,d,f,w,y,A,v,C,S,k,R,B,D,H,I;if(this.elem){if(s=this.elem.position(),r=this.elem.outerHeight(),a=this.elem.outerWidth(),D=this.wrapper.position(),i=this.container.height(),e=this.container.width(),R=this.getPosition(),console.log(R),v=R[0],y=R[1],A=R[2]||y,p=m[v],f=c[v],w=m[f],o={},o[w]="b"===v?r:"r"===v?a:0,h(o,"left",s.left-D.left),d=parseInt(this.elem.css("margin-left"),10),d&&h(o,"left",d),/^inline/.test(this.elem.css("display"))&&(C=parseInt(this.elem.css("padding-top"),10),C&&h(o,"top",-C)),h(o,"top",this.options.offsetY),h(o,"left",this.options.offsetX),this.options.arrowShow){for(B=this.options.arrowSize,t=$.extend({},o),H=0,I=u.length;I>H;H++)S=u[H],k=m[S],S!==f&&(n=k===p?this.getColor():"transparent",t["border-"+k]=""+B+"px solid "+n);h(o,m[f],B),this.arrow.css(t).show()}else this.arrow.hide();return x.call(b,v)>=0&&h(o,"left",g(y,e,a)),x.call(l,v)>=0&&h(o,"top",g(y,i,r)),this.container.is(":visible")&&(o.display="block"),this.container.removeAttr("style").css(o)}},t.prototype.getPosition=function(){var t,n,i,e,o,r,s,a;if(n=this.options.position,t=f(n),0===t.length&&(t[0]="b"),i=t[0],0>x.call(u,i))throw"Must be one of ["+u+"]";if((1===t.length||(e=t[0],x.call(b,e)>=0&&(o=t[1],0>x.call(l,o)))||(r=t[0],x.call(l,r)>=0&&(s=t[1],0>x.call(b,s))))&&(t[1]=(a=t[0],x.call(l,a)>=0?"m":"l")),!this.options.autoReposition)return t;throw"Not implemented"},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),t||(t="default"),n=A.user[t],!n)throw"Missing style: "+t;return n},t.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()))})},t.prototype.run=function(t,n){var e=this;return $.isPlainObject(n)?$.extend(this.options,n):"string"===$.type(n)&&(this.options.color=n),this.container&&!t?(this.show(!1),i):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),this.autohideTimer=setTimeout(function(){return e.show(!1)},this.options.autoHideDelay)):i):i},t.prototype.destroy=function(){var t=this;return this.show(!1,function(){return t.wrapper.remove()})},t}(),$(function(){return $("body").append(r),$("link").each(function(){var t,n;return n=$(this).attr("href"),n.match(/bootstrap/)?(t=!0,!1):i}),d(A.core),$(n).on("click","."+o+"Wrapper",function(){var t;return(t=$(this).data(o))?t.elem?t.show(!1):t.destroy():i})}),$[w]=function(t,n,i){return t&&t.nodeName||t.jquery?$(t)[w](n,i):(i=n,n=t,new e(null,n,i)),t},$[w].options=function(t){return $.extend(y,t)},$[w].styles=function(t){return $.extend(!0,A.user,t)},$[w].insertCSS=d,$.fn[w]=function(t,n){return $(this).each(function(){var i;return i=a($(this)).data(o),i?i.run(t,n):new e($(this),t,n)}),this}})(window,document); \ No newline at end of file diff --git a/examples/position.html b/examples/position.html index 78fea77..0f33ed7 100644 --- a/examples/position.html +++ b/examples/position.html @@ -10,9 +10,9 @@ margin: 150px; } .box { - padding: 10px; - margin: 10px; border: thin solid blue; + padding: 10px; + margin: 20px; width: 100px; } .wrapper { @@ -33,7 +33,7 @@ boxes.append($("
").append(box)); setTimeout(function() { - box.notify(p, {position: p}); + box.notify(p, {position: p+" middle"}); }, 500) }); diff --git a/src/notify.coffee b/src/notify.coffee index ff606b0..63b27c2 100644 --- a/src/notify.coffee +++ b/src/notify.coffee @@ -13,6 +13,9 @@ positions = l: 'left' c: 'center' r: 'right' +hPositions = ['l','c','r'] +vPositions = ['t','m','b'] +mainPositions = ['t','b','l','r'] #positions mapped to opposites opposites = t: 'b' @@ -34,6 +37,7 @@ styles = core: html: """
+
@@ -61,7 +65,13 @@ styles = display: inline-block; height: 0; width: 0; - border: thin solid red; + } + + .#{className}Debug { + position: absolute; + border: 3px solid red; + height: 0; + width: 0; } .#{className}Container { @@ -76,10 +86,8 @@ styles = } .#{className}Arrow { - margin-top: 2px; position: absolute; z-index: 2; - margin-left: 10px; width: 0; height: 0; } @@ -136,7 +144,7 @@ styles = pluginOptions = autoHide: false autoHideDelay: 2000 - arrowShow: false + arrowShow: true arrowSize: 5 position: 'bottom' # Default style @@ -154,7 +162,7 @@ pluginOptions = hideAnimation: 'slideUp' hideDuration: 200 # Gap between main and element - offsetY: 2 + offsetY: 0 offsetX: 0 #TODO add z-index watches #parents: { '.ui-dialog': 5001 } @@ -180,10 +188,8 @@ getAnchorElement = (element) -> #custom-styled inputs - find thier real element element -incr = (obj, pos, val, useOpposite = true) -> - +incr = (obj, pos, val) -> # console.log "incr ---- #{pos} #{val} (#{typeof val})" - if typeof val is 'string' val = parseInt val, 10 else if typeof val isnt 'number' @@ -196,7 +202,6 @@ incr = (obj, pos, val, useOpposite = true) -> #use the opposite if exists if obj[opp] isnt `undefined` - return unless useOpposite pos = positions[opp.charAt(0)] val *= -1 @@ -204,10 +209,17 @@ incr = (obj, pos, val, useOpposite = true) -> obj[pos] = val else obj[pos] += val - - console.log "incr (#{opp}>>#{temp}) #{pos} by #{val}" null +realign = (alignment, inner, outer) -> + return if alignment in ['l','t'] + 0 + else if alignment in ['c','m'] + outer/2 - inner/2 + else if alignment in ['r','b'] + outer - inner + throw "Invalid alignment" + insertCSS = (style) -> return unless style and style.css elem = style.cssElem @@ -287,6 +299,8 @@ class Notification else if not hidden and not show fn = @options.hideAnimation args.push @options.hideDuration + else + return callback() args.push callback @@ -294,83 +308,88 @@ class Notification updatePosition: -> return unless @elem - # - elementPosition = @elem.position() - wrapperPosition = @wrapper.position() - # + #grab some dimensions + elemPos = @elem.position() + elemH = @elem.outerHeight() + elemW = @elem.outerWidth() + wrapPos = @wrapper.position() + contH = @container.height() + contW = @container.width() + + #get user defined position position = @getPosition() - - console.log @elem[0] - console.log "update position", position, " elem ", elementPosition, " main ", wrapperPosition + console.log position + pMain = position[0] + pAlign = position[1] + pArrow = position[2] or pAlign #start calculations - p = {} - switch position[0] - when 'b' - incr p, 'top', @elem.outerHeight() - when 't' - incr p, 'bottom', 0 - when 'l' - incr p, 'right', 0 - when 'r' - incr p, 'left', @elem.outerWidth() - else - throw "Unknown position: #{position}" + mainFull = positions[pMain] + opp = opposites[pMain] + oppFull = positions[opp] + #initial positioning + css = {} + css[oppFull] = if pMain is 'b' then elemH else + if pMain is 'r' then elemW else 0 - #elem vs wrapper corrections - unless navigator.userAgent.match /MSIE/ - incr p, 'top', (elementPosition.top - wrapperPosition.top) + #correct for elem-wrapper offset + # unless navigator.userAgent.match /MSIE/ + # incr css, 'top', (elemPos.top - wrapPos.top) + incr css, 'left', elemPos.left - wrapPos.left - incr p, 'left', elementPosition.left - wrapperPosition.left - - # console.log "corrent margin" - # for pos in ['top','right','bottom','left'] - # incr p, pos, @elem.css("margin-#{pos}"), false + #correct for left margin + margin = parseInt @elem.css("margin-left"), 10 + incr css, 'left', margin if margin + #correct for inline top padding + if /^inline/.test @elem.css('display') + padding = parseInt @elem.css("padding-top"), 10 + incr css, 'top', -padding if padding + #user defined offset + incr css, 'top', @options.offsetY + incr css, 'left', @options.offsetX - #set user offset - # p.top += @options.offsetY - # p.left += @options.offsetX - - # @updateArrow p, position - - # if @setCSS - # @container.stop().animate(p) - # else - @container.css p - # @setCSS = true - - updateArrow: (p, position) -> - - unless @options.arrowShow and @elementType isnt 'radio' + #calculate arrow + if not @options.arrowShow @arrow.hide() - return + else + size = @options.arrowSize + arrowCss = $.extend {}, css + #build arrow + for pos in mainPositions + posFull = positions[pos] + continue if pos is opp + color = if posFull is mainFull then @getColor() else 'transparent' + arrowCss["border-#{posFull}"] = "#{size}px solid #{color}" + #add some room for the arrow + incr css, positions[opp], size + #add styles + @arrow.css(arrowCss).show() - dir = arrowDirs[position] - size = @options.arrowSize + #calculate alignment + if pMain in vPositions + incr css, 'left', realign(pAlign, contW, elemW) + if pMain in hPositions + incr css, 'top', realign(pAlign, contH, elemH) - @arrow.css 'border-' + position, size + 'px solid ' + @getColor() - @arrow.css p - for d of arrowDirs - if d isnt dir and d isnt position - @arrow.css 'border-' + d, size + 'px solid transparent' - - switch position - when 'bottom' - p.top += size - when 'right' - p.left += size - - @arrow.show() + #apply css + css.display = 'block' if @container.is(":visible") + @container.removeAttr('style').css css getPosition: -> text = @options.position pos = parsePosition text #if unspecified - choose bottom left - pos.push 'b' if pos.length is 0 - pos.push 'm' if pos.length is 1 and pos[0] is 'l' or pos[0] is 'r' - pos.push 'l' if pos.length is 1 + pos[0] = 'b' if pos.length is 0 + + if pos[0] not in mainPositions + throw "Must be one of [#{mainPositions}]" + + if pos.length is 1 or + (pos[0] in vPositions and pos[1] not in hPositions) or + (pos[0] in hPositions and pos[1] not in vPositions) + pos[1] = if pos[0] in hPositions then 'm' else 'l' unless @options.autoReposition return pos @@ -431,7 +450,7 @@ class Notification #autohide if @options.autoHide clearTimeout @autohideTimer - autohideTimer = setTimeout => + @autohideTimer = setTimeout => @show false , @options.autoHideDelay