diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/Gruntfile.coffee b/Gruntfile.coffee
new file mode 100644
index 0000000..2f656e2
--- /dev/null
+++ b/Gruntfile.coffee
@@ -0,0 +1,49 @@
+fs = require("fs")
+
+#global module:false
+module.exports = (grunt) ->
+
+
+ # Project configuration.
+ grunt.initConfig
+ pkg: grunt.file.readJSON('component.json')
+ banner:
+ "/** <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today(\"yyyy/mm/dd\") %>\n"+
+ " * <%= pkg.homepage %>\n" +
+ " * Copyright (c) <%= grunt.template.today(\"yyyy\") %> <%= pkg.author.name %> - MIT\n"+
+ " */"
+
+ coffee:
+ options:
+ bare: true
+ compile:
+ files:
+ 'dist/<%= pkg.name %>.js': 'src/<%= pkg.name %>.coffee'
+
+ wrap:
+ dist:
+ src: ['dist/<%= pkg.name %>.js']
+ dest: '.'
+ wrapper: ["<%= banner %>\n(function(window,document,undefined) {\n","\n}(window,document));"]
+
+ uglify:
+ options:
+ stripBanners: true
+ banner: '<%= banner %>'
+
+ dist:
+ src: "dist/<%= pkg.name %>.js"
+ dest: "dist/<%= pkg.name %>.min.js"
+
+ watch:
+ scripts:
+ files: 'src/*.coffee'
+ tasks: 'default'
+
+ grunt.loadNpmTasks "grunt-contrib-watch"
+ grunt.loadNpmTasks "grunt-contrib-uglify"
+ grunt.loadNpmTasks "grunt-contrib-coffee"
+ grunt.loadNpmTasks "grunt-wrap"
+
+ # Default task.
+ grunt.registerTask "default", "coffee wrap uglify".split(' ')
diff --git a/README.md b/README.md
index 74f187a..830859a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-notifyjs
-========
-Notify.js - A robust, customizable notification library
\ No newline at end of file
+### Notify.js - A robust, customizable notification library
+
+## http://notifyjs.com
diff --git a/component.json b/component.json
new file mode 100644
index 0000000..d1aa995
--- /dev/null
+++ b/component.json
@@ -0,0 +1,10 @@
+{
+ "title": "Notify.js",
+ "name": "notify",
+ "version": "0.0.1",
+ "author": {
+ "name": "Jaime Pillora"
+ },
+ "homepage": "http://notifyjs.com/",
+ "license": "MIT"
+}
\ No newline at end of file
diff --git a/dist/notify.js b/dist/notify.js
new file mode 100644
index 0000000..28ce459
--- /dev/null
+++ b/dist/notify.js
@@ -0,0 +1,244 @@
+/** Notify.js - v0.0.1 - 2013/04/04
+ * http://notifyjs.com/
+ * Copyright (c) 2013 Jaime Pillora - MIT
+ */
+(function(window,document,undefined) {
+'use strict';
+
+var Options, Prompt, arrowDirs, className, coreStyle, create, getAnchorElement, pluginName, pluginOptions, userStyles;
+
+pluginName = 'notify';
+
+className = '__notify';
+
+arrowDirs = {
+ top: 'bottom',
+ bottom: 'top',
+ left: 'right',
+ right: 'left'
+};
+
+coreStyle = {
+ html: "
",
+ css: "." + className + "Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n}\n\n." + className + "Main {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n." + className + "Content {\n background: #fff;\n position: relative;\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}"
+};
+
+userStyles = {
+ "default": {
+ html: "test",
+ css: "body {\n test: 42\n}"
+ },
+ bootstrap: {
+ html: "test",
+ css: "body {\n test: 42\n}"
+ }
+};
+
+pluginOptions = {
+ autoHidePrompt: false,
+ autoHideDelay: 10000,
+ arrowShow: true,
+ arrowSize: 5,
+ arrowPosition: 'top',
+ color: 'red',
+ colors: {
+ red: '#ee0101',
+ green: '#33be40',
+ black: '#393939',
+ blue: '#00f'
+ },
+ showAnimation: 'fadeIn',
+ showDuration: 200,
+ hideAnimation: 'fadeOut',
+ hideDuration: 600,
+ gap: 2
+};
+
+create = function(tag) {
+ return $(document.createElement(tag));
+};
+
+Options = function(options) {
+ if ($.isPlainObject(options)) {
+ return $.extend(this, options);
+ }
+};
+
+Options.prototype = pluginOptions;
+
+getAnchorElement = function(element) {
+ var fBefore, radios;
+ if (element.is('[type=radio]')) {
+ radios = element.parents('form:first').find('[type=radio]').filter(function(i, e) {
+ return $(e).attr('name') === element.attr('name');
+ });
+ element = radios.first();
+ }
+ fBefore = element.prev();
+ if (fBefore.is('span.styled,span.OBS_checkbox')) {
+ element = fBefore;
+ }
+ return element;
+};
+
+Prompt = (function() {
+
+ function Prompt(elem, node, options) {
+ if ($.type(options) === 'string') {
+ options = {
+ color: options
+ };
+ }
+ this.options = new Options($.isPlainObject(options) ? options : {});
+ this.elementType = elem.attr('type');
+ this.originalElement = elem;
+ this.elem = getAnchorElement(elem);
+ this.elem.data(pluginName, this);
+ this.wrapper = $(coreStyle.html);
+ this.main = this.wrapper.find("." + className + "Main");
+ this.content = this.main.find("." + className + "Content");
+ this.elem.before(this.wrapper);
+ this.main.css(this.calculateCSS());
+ this.run(node);
+ }
+
+ Prompt.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();
+ }
+ };
+
+ Prompt.prototype.showMain = function(show) {
+ var hidden;
+ hidden = this.main.parent().parents(':hidden').length > 0;
+ if (hidden && show) {
+ this.main.show();
+ }
+ if (hidden && !show) {
+ this.main.hide();
+ }
+ if (!hidden && show) {
+ this.main[this.options.showAnimation](this.options.showDuration);
+ }
+ if (!hidden && !show) {
+ return this.main[this.options.hideAnimation](this.options.hideDuration);
+ }
+ };
+
+ Prompt.prototype.calculateCSS = function() {
+ var elementPosition, height, left, mainPosition;
+ elementPosition = this.elem.position();
+ mainPosition = this.main.parent().position();
+ height = this.elem.outerHeight();
+ left = elementPosition.left - mainPosition.left;
+ if (!navigator.userAgent.match(/MSIE/)) {
+ height += elementPosition.top - mainPosition.top;
+ }
+ return {
+ top: height + this.options.gap,
+ left: left
+ };
+ };
+
+ Prompt.prototype.getColor = function() {
+ return this.options.colors[this.options.color] || this.options.color;
+ };
+
+ Prompt.prototype.run = function(node, options) {
+ var t;
+ if ($.isPlainObject(options)) {
+ $.extend(this.options, options);
+ } else if ($.type(options) === 'string') {
+ this.options.color = options;
+ }
+ if (this.main && !node) {
+ this.showMain(false);
+ return;
+ } else if (!this.main && !node) {
+ return;
+ }
+ if ($.type(node) === 'string') {
+ this.content.html(node.replace('\n', '
'));
+ } else {
+ this.content.empty().append(node);
+ }
+ this.content.css({
+ 'color': this.getColor(),
+ 'border-color': this.getColor()
+ });
+ if (this.arrow) {
+ this.arrow.remove();
+ }
+ this.buildArrow();
+ this.content.before(this.arrow);
+ this.showMain(true);
+ if (this.options.autoHidePrompt) {
+ clearTimeout(this.elem.data('mainTimer'));
+ t = setTimeout(function() {
+ return this.showMain(false);
+ }, this.options.autoHideDelay);
+ return this.elem.data('mainTimer', t);
+ }
+ };
+
+ return Prompt;
+
+})();
+
+$(function() {
+ $("head").append(create("style").html(coreStyle.css));
+ return $(document).on('click', "." + className, function() {
+ var inst;
+ inst = getAnchorElement($(this)).data(pluginName);
+ if (inst != null) {
+ return inst.showMain(false);
+ }
+ });
+});
+
+$[pluginName] = function(elem, node, options) {
+ return $(elem)[pluginName](node, options);
+};
+
+$[pluginName].options = function(options) {
+ return $.extend(pluginOptions, options);
+};
+
+$[pluginName].addStyle = function(s) {
+ return $.extend(true, userStyles, s);
+};
+
+$.fn[pluginName] = function(node, options) {
+ return $(this).each(function() {
+ var inst;
+ inst = getAnchorElement($(this)).data(pluginName);
+ if (inst != null) {
+ return inst.run(node, options);
+ } else {
+ return new Prompt($(this), node, options);
+ }
+ });
+};
+
+}(window,document));
\ No newline at end of file
diff --git a/dist/notify.min.js b/dist/notify.min.js
new file mode 100644
index 0000000..d504fac
--- /dev/null
+++ b/dist/notify.min.js
@@ -0,0 +1,4 @@
+/** Notify.js - v0.0.1 - 2013/04/04
+ * http://notifyjs.com/
+ * Copyright (c) 2013 Jaime Pillora - MIT
+ */(function(t,n){"use strict";var i,o,e,r,s,a,h,p,d,l;p="notify",r="__notify",e={top:"bottom",bottom:"top",left:"right",right:"left"},s={html:'',css:"."+r+"Wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n}\n\n."+r+"Main {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n."+r+"Content {\n background: #fff;\n position: relative;\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}"},l={"default":{html:"test",css:"body {\n test: 42\n}"},bootstrap:{html:"test",css:"body {\n test: 42\n}"}},d={autoHidePrompt:!1,autoHideDelay:1e4,arrowShow:!0,arrowSize:5,arrowPosition:"top",color:"red",colors:{red:"#ee0101",green:"#33be40",black:"#393939",blue:"#00f"},showAnimation:"fadeIn",showDuration:200,hideAnimation:"fadeOut",hideDuration:600,gap:2},a=function(t){return $(n.createElement(t))},i=function(t){return $.isPlainObject(t)?$.extend(this,t):undefined},i.prototype=d,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},o=function(){function t(t,n,o){"string"===$.type(o)&&(o={color:o}),this.options=new i($.isPlainObject(o)?o:{}),this.elementType=t.attr("type"),this.originalElement=t,this.elem=h(t),this.elem.data(p,this),this.wrapper=$(s.html),this.main=this.wrapper.find("."+r+"Main"),this.content=this.main.find("."+r+"Content"),this.elem.before(this.wrapper),this.main.css(this.calculateCSS()),this.run(n)}return t.prototype.buildArrow=function(){var t,i,o,s,h;o=this.options.arrowPosition,h=this.options.arrowSize,t=e[o],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 e)i!==o&&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.showMain=function(t){var n;return n=this.main.parent().parents(":hidden").length>0,n&&t&&this.main.show(),n&&!t&&this.main.hide(),!n&&t&&this.main[this.options.showAnimation](this.options.showDuration),n||t?undefined:this.main[this.options.hideAnimation](this.options.hideDuration)},t.prototype.calculateCSS=function(){var t,n,i,o;return t=this.elem.position(),o=this.main.parent().position(),n=this.elem.outerHeight(),i=t.left-o.left,navigator.userAgent.match(/MSIE/)||(n+=t.top-o.top),{top:n+this.options.gap,left:i}},t.prototype.getColor=function(){return this.options.colors[this.options.color]||this.options.color},t.prototype.run=function(t,n){var i;return $.isPlainObject(n)?$.extend(this.options,n):"string"===$.type(n)&&(this.options.color=n),this.main&&!t?(this.showMain(!1),undefined):this.main||t?("string"===$.type(t)?this.content.html(t.replace("\n","
")):this.content.empty().append(t),this.content.css({color:this.getColor(),"border-color":this.getColor()}),this.arrow&&this.arrow.remove(),this.buildArrow(),this.content.before(this.arrow),this.showMain(!0),this.options.autoHidePrompt?(clearTimeout(this.elem.data("mainTimer")),i=setTimeout(function(){return this.showMain(!1)},this.options.autoHideDelay),this.elem.data("mainTimer",i)):undefined):undefined},t}(),$(function(){return $("head").append(a("style").html(s.css)),$(n).on("click","."+r,function(){var t;return t=h($(this)).data(p),null!=t?t.showMain(!1):undefined})}),$[p]=function(t,n,i){return $(t)[p](n,i)},$[p].options=function(t){return $.extend(d,t)},$[p].addStyle=function(t){return $.extend(!0,l,t)},$.fn[p]=function(t,n){return $(this).each(function(){var i;return i=h($(this)).data(p),null!=i?i.run(t,n):new o($(this),t,n)})}})(window,document);
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..5d73cea
--- /dev/null
+++ b/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/notify.jquery.json b/notify.jquery.json
new file mode 100644
index 0000000..ea29b0f
--- /dev/null
+++ b/notify.jquery.json
@@ -0,0 +1,28 @@
+{
+ "name": "notify",
+ "version": "0.0.1",
+ "title": "notify",
+ "description": "A robust, customizable notification library",
+ "bugs": "https://github.com/jpillora/notifyjs/issues",
+ "homepage": "http://notifyjs.com",
+ "docs": "http://notifyjs.com",
+ "download": "http://notifyjs.com#download",
+ "author": {
+ "name": "Jaime Pillora"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://opensource.org/licenses/MIT"
+ }
+ ],
+ "keywords": [
+ "notify",
+ "notification",
+ "prompt",
+ "popup"
+ ],
+ "dependencies": {
+ "jquery": ">=1.8"
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2906229
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "notify",
+ "devDependencies": {
+ "grunt": "~0.4.x",
+ "grunt-contrib-watch": "~0.1.4",
+ "grunt-contrib-uglify": "~0.1.1rc6",
+ "grunt-contrib-jshint": "~0.1.0",
+ "grunt-contrib-concat": "~0.1.1",
+ "grunt-contrib-coffee": "~0.4.0rc7",
+ "grunt-wrap": "~0.2.0"
+ }
+}
diff --git a/src/notify.coffee b/src/notify.coffee
new file mode 100644
index 0000000..4c443bb
--- /dev/null
+++ b/src/notify.coffee
@@ -0,0 +1,260 @@
+
+'use strict'
+
+#plugin constants
+pluginName = 'notify'
+className = '__notify'
+
+arrowDirs =
+ top: 'bottom'
+ bottom: 'top'
+ left: 'right'
+ right: 'left'
+
+coreStyle =
+ html: """
+
+ """
+ css: """
+ .#{className}Wrapper {
+ z-index: 1;
+ position: absolute;
+ display: inline-block;
+ height: 0;
+ width: 0;
+ }
+
+ .#{className}Main {
+ display: none;
+ z-index: 1;
+ position: absolute;
+ cursor: pointer;
+ }
+
+ .#{className}Content {
+ background: #fff;
+ position: relative;
+ font-size: 11px;
+ box-shadow: 0 0 6px #000;
+ -moz-box-shadow: 0 0 6px #000;
+ -webkit-box-shadow: 0 0 6px #000;
+ padding: 4px 10px 4px 8px;
+ border-radius: 6px;
+ border-style: solid;
+ border-width: 2px;
+ -moz-border-radius: 6px;
+ -webkit-border-radius: 6px;
+ white-space: nowrap;
+ }
+ """
+
+userStyles =
+
+ default:
+ html: """
+ test
+ """
+ css: """
+ body {
+ test: 42
+ }
+ """
+
+ bootstrap:
+ html: """
+ test
+ """
+ css: """
+ body {
+ test: 42
+ }
+ """
+
+#overridable options
+pluginOptions =
+ autoHidePrompt: false
+ autoHideDelay: 10000
+ arrowShow: true
+ arrowSize: 5
+ arrowPosition: 'top'
+ # Default color
+ color: 'red'
+ # Color mappings
+ colors:
+ red: '#ee0101'
+ green: '#33be40'
+ black: '#393939'
+ blue: '#00f'
+ showAnimation: 'fadeIn'
+ showDuration: 200
+ hideAnimation: 'fadeOut'
+ hideDuration: 600
+ # Gap between main and element
+ gap: 2
+ #TODO add z-index watches
+ #parents: { '.ui-dialog': 5001 }
+
+# plugin helpers
+create = (tag) ->
+ $ document.createElement(tag)
+
+# inherit plugin options
+Options = (options) ->
+ $.extend @, options if $.isPlainObject(options)
+Options:: = pluginOptions
+
+ #gets first on n radios, and gets the fancy stylised input for hidden inputs
+getAnchorElement = (element) ->
+ #choose the first of n radios
+ if element.is('[type=radio]')
+ radios = element.parents('form:first').find('[type=radio]').filter (i, e) ->
+ $(e).attr('name') is element.attr('name')
+ element = radios.first()
+ #custom-styled inputs - find thier real element
+ fBefore = element.prev()
+ element = fBefore if fBefore.is('span.styled,span.OBS_checkbox')
+ element
+
+#define plugin
+class Prompt
+
+ #setup instance variables
+ constructor: (elem, node, options) ->
+ options = {color: options} if $.type(options) is 'string'
+ @options = new Options if $.isPlainObject(options) then options else {}
+ @elementType = elem.attr('type')
+ @originalElement = elem
+ @elem = getAnchorElement(elem)
+ @elem.data pluginName, @
+
+ @wrapper = $(coreStyle.html)
+ @main = @wrapper.find ".#{className}Main"
+ @content = @main.find ".#{className}Content"
+
+ # add into dom
+ @elem.before @wrapper
+ @main.css @calculateCSS()
+
+ @run(node)
+
+ 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()
+
+ showMain: (show) ->
+ hidden = @main.parent().parents(':hidden').length > 0
+ @main.show() if hidden and show
+ @main.hide() if hidden and not show
+ @main[@options.showAnimation] @options.showDuration if not hidden and show
+ @main[@options.hideAnimation] @options.hideDuration if not hidden and not show
+
+ calculateCSS: () ->
+ elementPosition = @elem.position()
+ mainPosition = @main.parent().position()
+ height = @elem.outerHeight()
+ left = elementPosition.left - mainPosition.left
+ height += (elementPosition.top - mainPosition.top) unless navigator.userAgent.match /MSIE/
+ return {
+ top: height + @options.gap
+ left: left
+ }
+
+ getColor: ->
+ @options.colors[@options.color] or @options.color
+
+ #run plugin
+ run: (node, options) ->
+ #update options
+ if $.isPlainObject(options)
+ $.extend @options, options
+ #shortcut special case
+ else if $.type(options) is 'string'
+ @options.color = options
+
+ if @main and not node
+ @showMain false #hide
+ return
+ else if not @main and not node
+ return
+
+ #update content
+ if $.type(node) is 'string'
+ @content.html node.replace('\n', '
')
+ else
+ @content.empty().append(node)
+
+ @content.css
+ 'color': @getColor()
+ 'border-color': @getColor()
+
+ @arrow.remove() if @arrow
+ @buildArrow()
+ @content.before @arrow
+
+ @showMain true
+
+ #autohide
+ if @options.autoHidePrompt
+ clearTimeout @elem.data 'mainTimer'
+ t = setTimeout ->
+ @showMain false
+ , @options.autoHideDelay
+ @elem.data 'mainTimer', t
+
+#when ready, bind permanent hide listener
+$ ->
+
+ $("head").append(create("style").html(coreStyle.css))
+
+ $(document).on 'click', ".#{className}", ->
+ inst = getAnchorElement($(@)).data pluginName
+ inst.showMain false if inst?
+
+# publicise jquery plugin
+# return alert "$.#{pluginName} already defined" if $[pluginName]?
+# $.pluginName( { ... } ) changes options for all instances
+$[pluginName] = (elem, node, options) ->
+ $(elem)[pluginName](node, options)
+
+# publicise options method
+$[pluginName].options = (options) ->
+ $.extend pluginOptions, options
+
+$[pluginName].addStyle = (s) ->
+ $.extend true, userStyles, s
+
+# $( ... ).pluginName( { .. } ) creates a cached instance on each
+# selected item with custom options for just that instance
+# return alert "$.fn#{pluginName} already defined" if $.fn[pluginName]?
+$.fn[pluginName] = (node, options) ->
+ $(@).each ->
+ inst = getAnchorElement($(@)).data pluginName
+ if inst?
+ inst.run node, options
+ else
+ new Prompt $(@), node, options
+
+#ps. alex is gay.
+