Skip to content
Browse files

Add submodules for alertify and bootstrap, checkout tags, use grunt

  • Loading branch information...
1 parent 1b91f70 commit a256619fc4634a3981fe84fd47daa12e5aaeb58d bitpshr committed
View
6 .gitmodules
@@ -0,0 +1,6 @@
+[submodule "vendor/bootstrap"]
+ path = vendor/bootstrap
+ url = https://github.com/twitter/bootstrap.git
+[submodule "vendor/alertify"]
+ path = vendor/alertify
+ url = https://github.com/fabien-d/alertify.js.git
View
32 Gruntfile.js
@@ -0,0 +1,32 @@
+/*global module:false*/
+module.exports = function(grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ jshint: {
+ files: ['src/*.js', 'bin/*.js']
+ },
+ concat: {
+ dist: {
+ src: ['vendor/alertify/lib/alertify.js', 'src/holler-client.js'],
+ dest: 'dist/<%= pkg.name %>-client.concat.js'
+ }
+ },
+ uglify: {
+ build: {
+ src: '<%= concat.dist.dest %>',
+ dest: 'dist/<%= pkg.name %>-client.min.js'
+ }
+ }
+ });
+
+ // Load the plugin that provides the "uglify" task.
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+
+ // Default task(s).
+ grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
+
+};
View
20 README.md
@@ -67,12 +67,20 @@ You can also redirect the current page to a new url. Again, all users using the
holler http://yourServerUrl:port redirect http://someOtherUrl
```
-##Going forward
-I definitely need to address the following:
-
-* Security: need a way to lock down notifications so that only auth'd users can send them
-* Simplicity: need a way to simplify the holler.js command (it's ugly to pass in 3 options)
-
+##Contributing
+Holler.js uses [Grunt](http://gruntjs.com) for file linting and uglification. To start contributing, first make sure [node](http://nodejs.org) is installed. Then:
+
+```bash
+git clone https://github.com/bitpshr/holler.git && cd holler
+git submodules update --recursive --init
+cd vendor/bootstrap && npm install && make bootstrap && cd ..
+npm install
+# start a server at localhost (e.g. http://127.0.0.1)
+holler-server
+# view demo.html in a browser
+# send a log message
+holler http://127.0.0.1:1337 log "foobar"
+```
##License
[WTFPL](http://sam.zoy.org/wtfpl/)
View
12 demo/alertify.min.js
@@ -1,12 +0,0 @@
-/**
- * alertify
- * An unobtrusive customizable JavaScript notification system
- *
- * @author Fabien Doiron <fabien.doiron@gmail.com>
- * @copyright Fabien Doiron 2012
- * @license MIT <http://opensource.org/licenses/mit-license.php>
- * @link http://fabien-d.github.com/alertify.js/
- * @module alertify
- * @version 0.3.2
- */
-(function(e,t){"use strict";var n=e.document,r;r=function(){var r={},i={},s=!1,o={ENTER:13,ESC:27,SPACE:32},u=[],a,f,l,c,h,p;return i={buttons:{holder:'<nav class="alertify-buttons">{{buttons}}</nav>',submit:'<button type="submit" class="alertify-button alertify-button-ok" id="alertify-ok" />{{ok}}</button>',ok:'<a href="#" class="alertify-button alertify-button-ok" id="alertify-ok">{{ok}}</a>',cancel:'<a href="#" class="alertify-button alertify-button-cancel" id="alertify-cancel">{{cancel}}</a>'},input:'<div class="alertify-text-wrapper"><input type="text" class="alertify-text" id="alertify-text"></div>',message:'<p class="alertify-message">{{message}}</p>',log:'<article class="alertify-log{{class}}">{{message}}</article>'},p=function(){var e,r=n.createElement("fakeelement"),i={transition:"transitionend",OTransition:"otransitionend",MSTransition:"msTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(e in i)if(r.style[e]!==t)return i[e]},a=function(e){return n.getElementById(e)},r={labels:{ok:"OK",cancel:"Cancel"},delay:5e3,buttonReverse:!1,transition:t,addListeners:function(r){var i=a("alertify-resetFocus"),s=a("alertify-ok")||t,u=a("alertify-cancel")||t,f=a("alertify-text")||t,l=a("alertify-form")||t,c=typeof s!="undefined",h=typeof u!="undefined",p=typeof f!="undefined",d="",v=this,m,g,y,b,w;m=function(e){typeof e.preventDefault!="undefined"&&e.preventDefault(),y(e),typeof f!="undefined"&&(d=f.value),typeof r=="function"&&r(!0,d)},g=function(e){typeof e.preventDefault!="undefined"&&e.preventDefault(),y(e),typeof r=="function"&&r(!1)},y=function(e){v.hide(),v.unbind(n.body,"keyup",b),v.unbind(i,"focus",w),p&&v.unbind(l,"submit",m),c&&v.unbind(s,"click",m),h&&v.unbind(u,"click",g)},b=function(e){var t=e.keyCode;t===o.SPACE&&!p&&m(e),t===o.ESC&&h&&g(e)},w=function(e){p?f.focus():h?u.focus():s.focus()},this.bind(i,"focus",w),c&&this.bind(s,"click",m),h&&this.bind(u,"click",g),this.bind(n.body,"keyup",b),p&&this.bind(l,"submit",m),e.setTimeout(function(){f?(f.focus(),f.select()):s.focus()},50)},bind:function(e,t,n){typeof e.addEventListener=="function"?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)},appendButtons:function(e,t){return this.buttonReverse?t+e:e+t},build:function(e){var t="",n=e.type,r=e.message,s=e.cssClass||"";t+='<div class="alertify-dialog">',n==="prompt"&&(t+='<form id="alertify-form">'),t+='<article class="alertify-inner">',t+=i.message.replace("{{message}}",r),n==="prompt"&&(t+=i.input),t+=i.buttons.holder,t+="</article>",n==="prompt"&&(t+="</form>"),t+='<a id="alertify-resetFocus" class="alertify-resetFocus" href="#">Reset Focus</a>',t+="</div>";switch(n){case"confirm":t=t.replace("{{buttons}}",this.appendButtons(i.buttons.cancel,i.buttons.ok)),t=t.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"prompt":t=t.replace("{{buttons}}",this.appendButtons(i.buttons.cancel,i.buttons.submit)),t=t.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"alert":t=t.replace("{{buttons}}",i.buttons.ok),t=t.replace("{{ok}}",this.labels.ok);break;default:}return c.className="alertify alertify-show alertify-"+n+" "+s,l.className="alertify-cover",t},close:function(e,t){var n=t&&!isNaN(t)?+t:this.delay,r=this,i;this.bind(e,"click",function(){h.removeChild(e)}),i=function(e){e.stopPropagation(),e.propertyName==="opacity"&&h.removeChild(this)};if(t===0)return;setTimeout(function(){typeof e!="undefined"&&e.parentNode===h&&(typeof r.transition!="undefined"?(r.bind(e,r.transition,i),e.className+=" alertify-log-hide"):h.removeChild(e))},n)},dialog:function(e,t,r,i,o){f=n.activeElement;var a=function(){if(c&&c.scrollTop!==null)return;a()};if(typeof e!="string")throw new Error("message must be a string");if(typeof t!="string")throw new Error("type must be a string");if(typeof r!="undefined"&&typeof r!="function")throw new Error("fn must be a function");return typeof this.init=="function"&&(this.init(),a()),u.push({type:t,message:e,callback:r,placeholder:i,cssClass:o}),s||this.setup(),this},extend:function(e){if(typeof e!="string")throw new Error("extend method must have exactly one paramter");return function(t,n){return this.log(t,e,n),this}},hide:function(){u.splice(0,1),u.length>0?this.setup():(s=!1,c.className="alertify alertify-hide alertify-hidden",l.className="alertify-cover alertify-hidden",f.focus())},init:function(){n.createElement("nav"),n.createElement("article"),n.createElement("section"),l=n.createElement("div"),l.setAttribute("id","alertify-cover"),l.className="alertify-cover alertify-hidden",n.body.appendChild(l),c=n.createElement("section"),c.setAttribute("id","alertify"),c.className="alertify alertify-hidden",n.body.appendChild(c),h=n.createElement("section"),h.setAttribute("id","alertify-logs"),h.className="alertify-logs",n.body.appendChild(h),n.body.setAttribute("tabindex","0"),this.transition=p(),delete this.init},log:function(e,t,n){var r=function(){if(h&&h.scrollTop!==null)return;r()};return typeof this.init=="function"&&(this.init(),r()),this.notify(e,t,n),this},notify:function(e,t,r){var i=n.createElement("article");i.className="alertify-log"+(typeof t=="string"&&t!==""?" alertify-log-"+t:""),i.innerHTML=e,h.insertBefore(i,h.firstChild),setTimeout(function(){i.className=i.className+" alertify-log-show"},50),this.close(i,r)},set:function(e){var t;if(typeof e!="object"&&e instanceof Array)throw new Error("args must be an object");for(t in e)e.hasOwnProperty(t)&&(this[t]=e[t])},setup:function(){var e=u[0];s=!0,c.innerHTML=this.build(e),typeof e.placeholder=="string"&&e.placeholder!==""&&(a("alertify-text").value=e.placeholder),this.addListeners(e.callback)},unbind:function(e,t,n){typeof e.removeEventListener=="function"?e.removeEventListener(t,n,!1):e.detachEvent&&e.detachEvent("on"+t,n)}},{alert:function(e,t,n){return r.dialog(e,"alert",t,"",n),this},confirm:function(e,t,n){return r.dialog(e,"confirm",t,"",n),this},extend:r.extend,init:r.init,log:function(e,t,n){return r.log(e,t,n),this},prompt:function(e,t,n,i){return r.dialog(e,"prompt",t,n,i),this},success:function(e,t){return r.log(e,"success",t),this},error:function(e,t){return r.log(e,"error",t),this},set:function(e){r.set(e)},labels:r.labels}},typeof define=="function"?define([],function(){return new r}):typeof e.alertify=="undefined"&&(e.alertify=new r)})(this);
View
1,092 demo/bootstrap/css/bootstrap-responsive.css
@@ -1,1092 +0,0 @@
-/*!
- * Bootstrap Responsive v2.2.2
- *
- * Copyright 2012 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world @twitter by @mdo and @fat.
- */
-
-@-ms-viewport {
- width: device-width;
-}
-
-.clearfix {
- *zoom: 1;
-}
-
-.clearfix:before,
-.clearfix:after {
- display: table;
- line-height: 0;
- content: "";
-}
-
-.clearfix:after {
- clear: both;
-}
-
-.hide-text {
- font: 0/0 a;
- color: transparent;
- text-shadow: none;
- background-color: transparent;
- border: 0;
-}
-
-.input-block-level {
- display: block;
- width: 100%;
- min-height: 30px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.hidden {
- display: none;
- visibility: hidden;
-}
-
-.visible-phone {
- display: none !important;
-}
-
-.visible-tablet {
- display: none !important;
-}
-
-.hidden-desktop {
- display: none !important;
-}
-
-.visible-desktop {
- display: inherit !important;
-}
-
-@media (min-width: 768px) and (max-width: 979px) {
- .hidden-desktop {
- display: inherit !important;
- }
- .visible-desktop {
- display: none !important ;
- }
- .visible-tablet {
- display: inherit !important;
- }
- .hidden-tablet {
- display: none !important;
- }
-}
-
-@media (max-width: 767px) {
- .hidden-desktop {
- display: inherit !important;
- }
- .visible-desktop {
- display: none !important;
- }
- .visible-phone {
- display: inherit !important;
- }
- .hidden-phone {
- display: none !important;
- }
-}
-
-@media (min-width: 1200px) {
- .row {
- margin-left: -30px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 30px;
- }
- .container,
- .navbar-static-top .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 1170px;
- }
- .span12 {
- width: 1170px;
- }
- .span11 {
- width: 1070px;
- }
- .span10 {
- width: 970px;
- }
- .span9 {
- width: 870px;
- }
- .span8 {
- width: 770px;
- }
- .span7 {
- width: 670px;
- }
- .span6 {
- width: 570px;
- }
- .span5 {
- width: 470px;
- }
- .span4 {
- width: 370px;
- }
- .span3 {
- width: 270px;
- }
- .span2 {
- width: 170px;
- }
- .span1 {
- width: 70px;
- }
- .offset12 {
- margin-left: 1230px;
- }
- .offset11 {
- margin-left: 1130px;
- }
- .offset10 {
- margin-left: 1030px;
- }
- .offset9 {
- margin-left: 930px;
- }
- .offset8 {
- margin-left: 830px;
- }
- .offset7 {
- margin-left: 730px;
- }
- .offset6 {
- margin-left: 630px;
- }
- .offset5 {
- margin-left: 530px;
- }
- .offset4 {
- margin-left: 430px;
- }
- .offset3 {
- margin-left: 330px;
- }
- .offset2 {
- margin-left: 230px;
- }
- .offset1 {
- margin-left: 130px;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid [class*="span"] {
- display: block;
- float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.564102564102564%;
- *margin-left: 2.5109110747408616%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.564102564102564%;
- }
- .row-fluid .span12 {
- width: 100%;
- *width: 99.94680851063829%;
- }
- .row-fluid .span11 {
- width: 91.45299145299145%;
- *width: 91.39979996362975%;
- }
- .row-fluid .span10 {
- width: 82.90598290598291%;
- *width: 82.8527914166212%;
- }
- .row-fluid .span9 {
- width: 74.35897435897436%;
- *width: 74.30578286961266%;
- }
- .row-fluid .span8 {
- width: 65.81196581196582%;
- *width: 65.75877432260411%;
- }
- .row-fluid .span7 {
- width: 57.26495726495726%;
- *width: 57.21176577559556%;
- }
- .row-fluid .span6 {
- width: 48.717948717948715%;
- *width: 48.664757228587014%;
- }
- .row-fluid .span5 {
- width: 40.17094017094017%;
- *width: 40.11774868157847%;
- }
- .row-fluid .span4 {
- width: 31.623931623931625%;
- *width: 31.570740134569924%;
- }
- .row-fluid .span3 {
- width: 23.076923076923077%;
- *width: 23.023731587561375%;
- }
- .row-fluid .span2 {
- width: 14.52991452991453%;
- *width: 14.476723040552828%;
- }
- .row-fluid .span1 {
- width: 5.982905982905983%;
- *width: 5.929714493544281%;
- }
- .row-fluid .offset12 {
- margin-left: 105.12820512820512%;
- *margin-left: 105.02182214948171%;
- }
- .row-fluid .offset12:first-child {
- margin-left: 102.56410256410257%;
- *margin-left: 102.45771958537915%;
- }
- .row-fluid .offset11 {
- margin-left: 96.58119658119658%;
- *margin-left: 96.47481360247316%;
- }
- .row-fluid .offset11:first-child {
- margin-left: 94.01709401709402%;
- *margin-left: 93.91071103837061%;
- }
- .row-fluid .offset10 {
- margin-left: 88.03418803418803%;
- *margin-left: 87.92780505546462%;
- }
- .row-fluid .offset10:first-child {
- margin-left: 85.47008547008548%;
- *margin-left: 85.36370249136206%;
- }
- .row-fluid .offset9 {
- margin-left: 79.48717948717949%;
- *margin-left: 79.38079650845607%;
- }
- .row-fluid .offset9:first-child {
- margin-left: 76.92307692307693%;
- *margin-left: 76.81669394435352%;
- }
- .row-fluid .offset8 {
- margin-left: 70.94017094017094%;
- *margin-left: 70.83378796144753%;
- }
- .row-fluid .offset8:first-child {
- margin-left: 68.37606837606839%;
- *margin-left: 68.26968539734497%;
- }
- .row-fluid .offset7 {
- margin-left: 62.393162393162385%;
- *margin-left: 62.28677941443899%;
- }
- .row-fluid .offset7:first-child {
- margin-left: 59.82905982905982%;
- *margin-left: 59.72267685033642%;
- }
- .row-fluid .offset6 {
- margin-left: 53.84615384615384%;
- *margin-left: 53.739770867430444%;
- }
- .row-fluid .offset6:first-child {
- margin-left: 51.28205128205128%;
- *margin-left: 51.175668303327875%;
- }
- .row-fluid .offset5 {
- margin-left: 45.299145299145295%;
- *margin-left: 45.1927623204219%;
- }
- .row-fluid .offset5:first-child {
- margin-left: 42.73504273504273%;
- *margin-left: 42.62865975631933%;
- }
- .row-fluid .offset4 {
- margin-left: 36.75213675213675%;
- *margin-left: 36.645753773413354%;
- }
- .row-fluid .offset4:first-child {
- margin-left: 34.18803418803419%;
- *margin-left: 34.081651209310785%;
- }
- .row-fluid .offset3 {
- margin-left: 28.205128205128204%;
- *margin-left: 28.0987452264048%;
- }
- .row-fluid .offset3:first-child {
- margin-left: 25.641025641025642%;
- *margin-left: 25.53464266230224%;
- }
- .row-fluid .offset2 {
- margin-left: 19.65811965811966%;
- *margin-left: 19.551736679396257%;
- }
- .row-fluid .offset2:first-child {
- margin-left: 17.094017094017094%;
- *margin-left: 16.98763411529369%;
- }
- .row-fluid .offset1 {
- margin-left: 11.11111111111111%;
- *margin-left: 11.004728132387708%;
- }
- .row-fluid .offset1:first-child {
- margin-left: 8.547008547008547%;
- *margin-left: 8.440625568285142%;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- .controls-row [class*="span"] + [class*="span"] {
- margin-left: 30px;
- }
- input.span12,
- textarea.span12,
- .uneditable-input.span12 {
- width: 1156px;
- }
- input.span11,
- textarea.span11,
- .uneditable-input.span11 {
- width: 1056px;
- }
- input.span10,
- textarea.span10,
- .uneditable-input.span10 {
- width: 956px;
- }
- input.span9,
- textarea.span9,
- .uneditable-input.span9 {
- width: 856px;
- }
- input.span8,
- textarea.span8,
- .uneditable-input.span8 {
- width: 756px;
- }
- input.span7,
- textarea.span7,
- .uneditable-input.span7 {
- width: 656px;
- }
- input.span6,
- textarea.span6,
- .uneditable-input.span6 {
- width: 556px;
- }
- input.span5,
- textarea.span5,
- .uneditable-input.span5 {
- width: 456px;
- }
- input.span4,
- textarea.span4,
- .uneditable-input.span4 {
- width: 356px;
- }
- input.span3,
- textarea.span3,
- .uneditable-input.span3 {
- width: 256px;
- }
- input.span2,
- textarea.span2,
- .uneditable-input.span2 {
- width: 156px;
- }
- input.span1,
- textarea.span1,
- .uneditable-input.span1 {
- width: 56px;
- }
- .thumbnails {
- margin-left: -30px;
- }
- .thumbnails > li {
- margin-left: 30px;
- }
- .row-fluid .thumbnails {
- margin-left: 0;
- }
-}
-
-@media (min-width: 768px) and (max-width: 979px) {
- .row {
- margin-left: -20px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 20px;
- }
- .container,
- .navbar-static-top .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 724px;
- }
- .span12 {
- width: 724px;
- }
- .span11 {
- width: 662px;
- }
- .span10 {
- width: 600px;
- }
- .span9 {
- width: 538px;
- }
- .span8 {
- width: 476px;
- }
- .span7 {
- width: 414px;
- }
- .span6 {
- width: 352px;
- }
- .span5 {
- width: 290px;
- }
- .span4 {
- width: 228px;
- }
- .span3 {
- width: 166px;
- }
- .span2 {
- width: 104px;
- }
- .span1 {
- width: 42px;
- }
- .offset12 {
- margin-left: 764px;
- }
- .offset11 {
- margin-left: 702px;
- }
- .offset10 {
- margin-left: 640px;
- }
- .offset9 {
- margin-left: 578px;
- }
- .offset8 {
- margin-left: 516px;
- }
- .offset7 {
- margin-left: 454px;
- }
- .offset6 {
- margin-left: 392px;
- }
- .offset5 {
- margin-left: 330px;
- }
- .offset4 {
- margin-left: 268px;
- }
- .offset3 {
- margin-left: 206px;
- }
- .offset2 {
- margin-left: 144px;
- }
- .offset1 {
- margin-left: 82px;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- line-height: 0;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid [class*="span"] {
- display: block;
- float: left;
- width: 100%;
- min-height: 30px;
- margin-left: 2.7624309392265194%;
- *margin-left: 2.709239449864817%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid .controls-row [class*="span"] + [class*="span"] {
- margin-left: 2.7624309392265194%;
- }
- .row-fluid .span12 {
- width: 100%;
- *width: 99.94680851063829%;
- }
- .row-fluid .span11 {
- width: 91.43646408839778%;
- *width: 91.38327259903608%;
- }
- .row-fluid .span10 {
- width: 82.87292817679558%;
- *width: 82.81973668743387%;
- }
- .row-fluid .span9 {
- width: 74.30939226519337%;
- *width: 74.25620077583166%;
- }
- .row-fluid .span8 {
- width: 65.74585635359117%;
- *width: 65.69266486422946%;
- }
- .row-fluid .span7 {
- width: 57.18232044198895%;
- *width: 57.12912895262725%;
- }
- .row-fluid .span6 {
- width: 48.61878453038674%;
- *width: 48.56559304102504%;
- }
- .row-fluid .span5 {
- width: 40.05524861878453%;
- *width: 40.00205712942283%;
- }
- .row-fluid .span4 {
- width: 31.491712707182323%;
- *width: 31.43852121782062%;
- }
- .row-fluid .span3 {
- width: 22.92817679558011%;
- *width: 22.87498530621841%;
- }
- .row-fluid .span2 {
- width: 14.3646408839779%;
- *width: 14.311449394616199%;
- }
- .row-fluid .span1 {
- width: 5.801104972375691%;
- *width: 5.747913483013988%;
- }
- .row-fluid .offset12 {
- margin-left: 105.52486187845304%;
- *margin-left: 105.41847889972962%;
- }
- .row-fluid .offset12:first-child {
- margin-left: 102.76243093922652%;
- *margin-left: 102.6560479605031%;
- }
- .row-fluid .offset11 {
- margin-left: 96.96132596685082%;
- *margin-left: 96.8549429881274%;
- }
- .row-fluid .offset11:first-child {
- margin-left: 94.1988950276243%;
- *margin-left: 94.09251204890089%;
- }
- .row-fluid .offset10 {
- margin-left: 88.39779005524862%;
- *margin-left: 88.2914070765252%;
- }
- .row-fluid .offset10:first-child {
- margin-left: 85.6353591160221%;
- *margin-left: 85.52897613729868%;
- }
- .row-fluid .offset9 {
- margin-left: 79.8342541436464%;
- *margin-left: 79.72787116492299%;
- }
- .row-fluid .offset9:first-child {
- margin-left: 77.07182320441989%;
- *margin-left: 76.96544022569647%;
- }
- .row-fluid .offset8 {
- margin-left: 71.2707182320442%;
- *margin-left: 71.16433525332079%;
- }
- .row-fluid .offset8:first-child {
- margin-left: 68.50828729281768%;
- *margin-left: 68.40190431409427%;
- }
- .row-fluid .offset7 {
- margin-left: 62.70718232044199%;
- *margin-left: 62.600799341718584%;
- }
- .row-fluid .offset7:first-child {
- margin-left: 59.94475138121547%;
- *margin-left: 59.838368402492065%;
- }
- .row-fluid .offset6 {
- margin-left: 54.14364640883978%;
- *margin-left: 54.037263430116376%;
- }
- .row-fluid .offset6:first-child {
- margin-left: 51.38121546961326%;
- *margin-left: 51.27483249088986%;
- }
- .row-fluid .offset5 {
- margin-left: 45.58011049723757%;
- *margin-left: 45.47372751851417%;
- }
- .row-fluid .offset5:first-child {
- margin-left: 42.81767955801105%;
- *margin-left: 42.71129657928765%;
- }
- .row-fluid .offset4 {
- margin-left: 37.01657458563536%;
- *margin-left: 36.91019160691196%;
- }
- .row-fluid .offset4:first-child {
- margin-left: 34.25414364640884%;
- *margin-left: 34.14776066768544%;
- }
- .row-fluid .offset3 {
- margin-left: 28.45303867403315%;
- *margin-left: 28.346655695309746%;
- }
- .row-fluid .offset3:first-child {
- margin-left: 25.69060773480663%;
- *margin-left: 25.584224756083227%;
- }
- .row-fluid .offset2 {
- margin-left: 19.88950276243094%;
- *margin-left: 19.783119783707537%;
- }
- .row-fluid .offset2:first-child {
- margin-left: 17.12707182320442%;
- *margin-left: 17.02068884448102%;
- }
- .row-fluid .offset1 {
- margin-left: 11.32596685082873%;
- *margin-left: 11.219583872105325%;
- }
- .row-fluid .offset1:first-child {
- margin-left: 8.56353591160221%;
- *margin-left: 8.457152932878806%;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- .controls-row [class*="span"] + [class*="span"] {
- margin-left: 20px;
- }
- input.span12,
- textarea.span12,
- .uneditable-input.span12 {
- width: 710px;
- }
- input.span11,
- textarea.span11,
- .uneditable-input.span11 {
- width: 648px;
- }
- input.span10,
- textarea.span10,
- .uneditable-input.span10 {
- width: 586px;
- }
- input.span9,
- textarea.span9,
- .uneditable-input.span9 {
- width: 524px;
- }
- input.span8,
- textarea.span8,
- .uneditable-input.span8 {
- width: 462px;
- }
- input.span7,
- textarea.span7,
- .uneditable-input.span7 {
- width: 400px;
- }
- input.span6,
- textarea.span6,
- .uneditable-input.span6 {
- width: 338px;
- }
- input.span5,
- textarea.span5,
- .uneditable-input.span5 {
- width: 276px;
- }
- input.span4,
- textarea.span4,
- .uneditable-input.span4 {
- width: 214px;
- }
- input.span3,
- textarea.span3,
- .uneditable-input.span3 {
- width: 152px;
- }
- input.span2,
- textarea.span2,
- .uneditable-input.span2 {
- width: 90px;
- }
- input.span1,
- textarea.span1,
- .uneditable-input.span1 {
- width: 28px;
- }
-}
-
-@media (max-width: 767px) {
- body {
- padding-right: 20px;
- padding-left: 20px;
- }
- .navbar-fixed-top,
- .navbar-fixed-bottom,
- .navbar-static-top {
- margin-right: -20px;
- margin-left: -20px;
- }
- .container-fluid {
- padding: 0;
- }
- .dl-horizontal dt {
- float: none;
- width: auto;
- clear: none;
- text-align: left;
- }
- .dl-horizontal dd {
- margin-left: 0;
- }
- .container {
- width: auto;
- }
- .row-fluid {
- width: 100%;
- }
- .row,
- .thumbnails {
- margin-left: 0;
- }
- .thumbnails > li {
- float: none;
- margin-left: 0;
- }
- [class*="span"],
- .uneditable-input[class*="span"],
- .row-fluid [class*="span"] {
- display: block;
- float: none;
- width: 100%;
- margin-left: 0;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .span12,
- .row-fluid .span12 {
- width: 100%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .row-fluid [class*="offset"]:first-child {
- margin-left: 0;
- }
- .input-large,
- .input-xlarge,
- .input-xxlarge,
- input[class*="span"],
- select[class*="span"],
- textarea[class*="span"],
- .uneditable-input {
- display: block;
- width: 100%;
- min-height: 30px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .input-prepend input,
- .input-append input,
- .input-prepend input[class*="span"],
- .input-append input[class*="span"] {
- display: inline-block;
- width: auto;
- }
- .controls-row [class*="span"] + [class*="span"] {
- margin-left: 0;
- }
- .modal {
- position: fixed;
- top: 20px;
- right: 20px;
- left: 20px;
- width: auto;
- margin: 0;
- }
- .modal.fade {
- top: -100px;
- }
- .modal.fade.in {
- top: 20px;
- }
-}
-
-@media (max-width: 480px) {
- .nav-collapse {
- -webkit-transform: translate3d(0, 0, 0);
- }
- .page-header h1 small {
- display: block;
- line-height: 20px;
- }
- input[type="checkbox"],
- input[type="radio"] {
- border: 1px solid #ccc;
- }
- .form-horizontal .control-label {
- float: none;
- width: auto;
- padding-top: 0;
- text-align: left;
- }
- .form-horizontal .controls {
- margin-left: 0;
- }
- .form-horizontal .control-list {
- padding-top: 0;
- }
- .form-horizontal .form-actions {
- padding-right: 10px;
- padding-left: 10px;
- }
- .media .pull-left,
- .media .pull-right {
- display: block;
- float: none;
- margin-bottom: 10px;
- }
- .media-object {
- margin-right: 0;
- margin-left: 0;
- }
- .modal {
- top: 10px;
- right: 10px;
- left: 10px;
- }
- .modal-header .close {
- padding: 10px;
- margin: -10px;
- }
- .carousel-caption {
- position: static;
- }
-}
-
-@media (max-width: 979px) {
- body {
- padding-top: 0;
- }
- .navbar-fixed-top,
- .navbar-fixed-bottom {
- position: static;
- }
- .navbar-fixed-top {
- margin-bottom: 20px;
- }
- .navbar-fixed-bottom {
- margin-top: 20px;
- }
- .navbar-fixed-top .navbar-inner,
- .navbar-fixed-bottom .navbar-inner {
- padding: 5px;
- }
- .navbar .container {
- width: auto;
- padding: 0;
- }
- .navbar .brand {
- padding-right: 10px;
- padding-left: 10px;
- margin: 0 0 0 -5px;
- }
- .nav-collapse {
- clear: both;
- }
- .nav-collapse .nav {
- float: none;
- margin: 0 0 10px;
- }
- .nav-collapse .nav > li {
- float: none;
- }
- .nav-collapse .nav > li > a {
- margin-bottom: 2px;
- }
- .nav-collapse .nav > .divider-vertical {
- display: none;
- }
- .nav-collapse .nav .nav-header {
- color: #777777;
- text-shadow: none;
- }
- .nav-collapse .nav > li > a,
- .nav-collapse .dropdown-menu a {
- padding: 9px 15px;
- font-weight: bold;
- color: #777777;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- }
- .nav-collapse .btn {
- padding: 4px 10px 4px;
- font-weight: normal;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- }
- .nav-collapse .dropdown-menu li + li a {
- margin-bottom: 2px;
- }
- .nav-collapse .nav > li > a:hover,
- .nav-collapse .dropdown-menu a:hover {
- background-color: #f2f2f2;
- }
- .navbar-inverse .nav-collapse .nav > li > a,
- .navbar-inverse .nav-collapse .dropdown-menu a {
- color: #999999;
- }
- .navbar-inverse .nav-collapse .nav > li > a:hover,
- .navbar-inverse .nav-collapse .dropdown-menu a:hover {
- background-color: #111111;
- }
- .nav-collapse.in .btn-group {
- padding: 0;
- margin-top: 5px;
- }
- .nav-collapse .dropdown-menu {
- position: static;
- top: auto;
- left: auto;
- display: none;
- float: none;
- max-width: none;
- padding: 0;
- margin: 0 15px;
- background-color: transparent;
- border: none;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- }
- .nav-collapse .open > .dropdown-menu {
- display: block;
- }
- .nav-collapse .dropdown-menu:before,
- .nav-collapse .dropdown-menu:after {
- display: none;
- }
- .nav-collapse .dropdown-menu .divider {
- display: none;
- }
- .nav-collapse .nav > li > .dropdown-menu:before,
- .nav-collapse .nav > li > .dropdown-menu:after {
- display: none;
- }
- .nav-collapse .navbar-form,
- .nav-collapse .navbar-search {
- float: none;
- padding: 10px 15px;
- margin: 10px 0;
- border-top: 1px solid #f2f2f2;
- border-bottom: 1px solid #f2f2f2;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- }
- .navbar-inverse .nav-collapse .navbar-form,
- .navbar-inverse .nav-collapse .navbar-search {
- border-top-color: #111111;
- border-bottom-color: #111111;
- }
- .navbar .nav-collapse .nav.pull-right {
- float: none;
- margin-left: 0;
- }
- .nav-collapse,
- .nav-collapse.collapse {
- height: 0;
- overflow: hidden;
- }
- .navbar .btn-navbar {
- display: block;
- }
- .navbar-static .navbar-inner {
- padding-right: 10px;
- padding-left: 10px;
- }
-}
-
-@media (min-width: 980px) {
- .nav-collapse.collapse {
- height: auto !important;
- overflow: visible !important;
- }
-}
View
6,039 demo/bootstrap/css/bootstrap.css
0 additions, 6,039 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
6 demo/bootstrap/css/error.txt
@@ -1,6 +0,0 @@
-A less error occured trying to build your bundle. You've likely entered an invalid input into the less variable field. Check your syntax and try again!
-
- thanks!
-
-
-{"type":"Parse","message":"Syntax Error on line 792","index":25106,"filename":"bootstrap.css","line":792,"column":11,"extract":[" *margin: -5px 0 5px;"," ove rflow: hidden;"," background-color: @top;"]}
View
BIN demo/bootstrap/img/glyphicons-halflings-white.png
Deleted file not rendered
View
BIN demo/bootstrap/img/glyphicons-halflings.png
Deleted file not rendered
View
0 demo/css/app.css 100755 → 100644
File mode changed.
View
13 demo/index.html
@@ -7,9 +7,9 @@
<meta name="description" content="real-time, in-app notifications and admin for web and mobile via the command line">
<meta name="author" content="Paul Bouchon">
<title>holler.js</title>
- <link href="bootstrap/css/bootstrap.css" rel="stylesheet">
+ <link href="../vendor/bootstrap/bootstrap/css/bootstrap.css" rel="stylesheet">
<link href="css/app.css" rel="stylesheet">
- <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
+ <link href="../vendor/bootstrap/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
@@ -133,10 +133,17 @@ <h1 class="sectionTitle"><span class="accent">4.</span> Holler stuff</h1>
<a href="http://twitter.com/bitpshr"><span>Contact</span></a>
</p>
</div>
- <script src="alertify.min.js"></script>
+ <script src="../vendor/alertify/lib/alertify.min.js"></script>
<script>
setTimeout('alertify.log("New Features! Refresh current page or redirect to new url for all users in real-time via command line.");',1500);
</script>
+ <script>
+ var hollerConfig = {
+ host: "http://127.0.0.1",
+ port: "1337"
+ }
+ </script>
+ <script type="text/javascript" src="../dist/holler-client.min.js"></script>
<script type="text/javascript">
var _gauges = _gauges || [];
(function() {
View
1,071 dist/holler-client.concat.js 100755 → 100644
@@ -3,474 +3,625 @@
* An unobtrusive customizable JavaScript notification system
*
* @author Fabien Doiron <fabien.doiron@gmail.com>
- * @copyright Fabien Doiron 2012
+ * @copyright Fabien Doiron 2013
* @license MIT <http://opensource.org/licenses/mit-license.php>
* @link http://fabien-d.github.com/alertify.js/
* @module alertify
- * @version 0.2.12
+ * @version 0.3.8
*/
-/*global define setTimeout*/
+/*global define*/
(function (global, undefined) {
- "use strict";
-
- var document = global.document,
- Alertify;
-
- Alertify = function () {
-
- var _alertify = {},
- dialogs = {},
- isopen = false,
- keys = { ENTER: 13, ESC: 27, SPACE: 32 },
- queue = [],
- $, elCallee, elCover, elDialog, elLog;
-
- /**
- * Markup pieces
- * @type {Object}
- */
- dialogs = {
- buttons : {
- holder : "<nav class=\"alertify-buttons\">{{buttons}}</nav>",
- submit : "<button type=\"submit\" class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\" />{{ok}}</button>",
- ok : "<a href=\"#\" class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\">{{ok}}</a>",
- cancel : "<a href=\"#\" class=\"alertify-button alertify-button-cancel\" id=\"alertify-cancel\">{{cancel}}</a>"
- },
- input : "<input type=\"text\" class=\"alertify-text\" id=\"alertify-text\">",
- message : "<p class=\"alertify-message\">{{message}}</p>",
- log : "<article class=\"alertify-log{{class}}\">{{message}}</article>"
- };
-
- /**
- * Shorthand for document.getElementById()
- *
- * @param {String} id A specific element ID
- * @return {Object} HTML element
- */
- $ = function (id) {
- return document.getElementById(id);
- };
-
- /**
- * Alertify private object
- * @type {Object}
- */
- _alertify = {
-
- /**
- * Labels object
- * @type {Object}
- */
- labels : {
- ok : "OK",
- cancel : "Cancel"
- },
-
- /**
- * Delay number
- * @type {Number}
- */
- delay : 5000,
-
- /**
- * Set the proper button click events
- *
- * @param {Function} fn [Optional] Callback function
- *
- * @return {undefined}
- */
- addListeners : function (fn) {
- var btnReset = $("alertify-resetFocus"),
- btnOK = $("alertify-ok") || undefined,
- btnCancel = $("alertify-cancel") || undefined,
- input = $("alertify-text") || undefined,
- form = $("alertify-form") || undefined,
- hasOK = (typeof btnOK !== "undefined"),
- hasCancel = (typeof btnCancel !== "undefined"),
- hasInput = (typeof input !== "undefined"),
- val = "",
- self = this,
- ok, cancel, common, key, reset;
-
- // ok event handler
- ok = function (event) {
- if (typeof event.preventDefault !== "undefined") event.preventDefault();
- common(event);
- if (typeof input !== "undefined") val = input.value;
- if (typeof fn === "function") fn(true, val);
- };
-
- // cancel event handler
- cancel = function (event) {
- if (typeof event.preventDefault !== "undefined") event.preventDefault();
- common(event);
- if (typeof fn === "function") fn(false);
- };
-
- // common event handler (keyup, ok and cancel)
- common = function (event) {
- self.hide();
- self.unbind(document.body, "keyup", key);
- self.unbind(btnReset, "focus", reset);
- if (hasInput) self.unbind(form, "submit", ok);
- if (hasOK) self.unbind(btnOK, "click", ok);
- if (hasCancel) self.unbind(btnCancel, "click", cancel);
- };
-
- // keyup handler
- key = function (event) {
- var keyCode = event.keyCode;
- if (keyCode === keys.SPACE && !hasInput) ok(event);
- if (keyCode === keys.ESC && hasCancel) cancel(event);
- };
-
- // reset focus to first item in the dialog
- reset = function (event) {
- if (hasInput) input.focus();
- else if (hasCancel) btnCancel.focus();
- else btnOK.focus();
- };
-
- // handle reset focus link
- // this ensures that the keyboard focus does not
- // ever leave the dialog box until an action has
- // been taken
- this.bind(btnReset, "focus", reset);
- // handle OK click
- if (hasOK) this.bind(btnOK, "click", ok);
- // handle Cancel click
- if (hasCancel) this.bind(btnCancel, "click", cancel);
- // listen for keys, Cancel => ESC
- this.bind(document.body, "keyup", key);
- // bind form submit
- if (hasInput) this.bind(form, "submit", ok);
- // set focus on OK button or the input text
- global.setTimeout(function () {
- if (input) {
- input.focus();
- input.select();
- }
- else btnOK.focus();
- }, 50);
- },
-
- /**
- * Bind events to elements
- *
- * @param {Object} el HTML Object
- * @param {Event} event Event to attach to element
- * @param {Function} fn Callback function
- *
- * @return {undefined}
- */
- bind : function (el, event, fn) {
- if (typeof el.addEventListener === "function") {
- el.addEventListener(event, fn, false);
- } else if (el.attachEvent) {
- el.attachEvent("on" + event, fn);
- }
- },
-
- /**
- * Build the proper message box
- *
- * @param {Object} item Current object in the queue
- *
- * @return {String} An HTML string of the message box
- */
- build : function (item) {
- var html = "",
- type = item.type,
- message = item.message,
- css = item.cssClass || "";
-
- html += "<div class=\"alertify-dialog\">";
-
- if (type === "prompt") html += "<form id=\"alertify-form\">";
-
- html += "<article class=\"alertify-inner\">";
- html += dialogs.message.replace("{{message}}", message);
-
- if (type === "prompt") html += dialogs.input;
-
- html += dialogs.buttons.holder;
- html += "</article>";
-
- if (type === "prompt") html += "</form>";
-
- html += "<a id=\"alertify-resetFocus\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>";
- html += "</div>";
-
- switch (type) {
- case "confirm":
- html = html.replace("{{buttons}}", dialogs.buttons.cancel + dialogs.buttons.ok);
- html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
- break;
- case "prompt":
- html = html.replace("{{buttons}}", dialogs.buttons.cancel + dialogs.buttons.submit);
- html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
- break;
- case "alert":
- html = html.replace("{{buttons}}", dialogs.buttons.ok);
- html = html.replace("{{ok}}", this.labels.ok);
- break;
- default:
- break;
- }
-
- elDialog.className = "alertify alertify-show alertify-" + type + " " + css;
- elCover.className = "alertify-cover";
- return html;
- },
-
- /**
- * Close the log messages
- *
- * @param {Object} elem HTML Element of log message to close
- * @param {Number} wait [optional] Time (in ms) to wait before automatically hiding the message
- *
- * @return {undefined}
- */
- close : function (elem, wait) {
- var timer = (wait && !isNaN(wait)) ? +wait : this.delay; // Unary Plus: +"2" === 2
- this.bind(elem, "click", function () {
- elLog.removeChild(elem);
- });
- setTimeout(function () {
- if (typeof elem !== "undefined" && elem.parentNode === elLog) elLog.removeChild(elem);
- }, timer);
- },
-
- /**
- * Create a dialog box
- *
- * @param {String} message The message passed from the callee
- * @param {String} type Type of dialog to create
- * @param {Function} fn [Optional] Callback function
- * @param {String} placeholder [Optional] Default value for prompt input field
- * @param {String} cssClass [Optional] Class(es) to append to dialog box
- *
- * @return {Object}
- */
- dialog : function (message, type, fn, placeholder, cssClass) {
- // set the current active element
- // this allows the keyboard focus to be resetted
- // after the dialog box is closed
- elCallee = document.activeElement;
- // check to ensure the alertify dialog element
- // has been successfully created
- var check = function () {
- if (elDialog && elDialog.scrollTop !== null) return;
- else check();
- };
- // error catching
- if (typeof message !== "string") throw new Error("message must be a string");
- if (typeof type !== "string") throw new Error("type must be a string");
- if (typeof fn !== "undefined" && typeof fn !== "function") throw new Error("fn must be a function");
- // initialize alertify if it hasn't already been done
- if (typeof this.init === "function") {
- this.init();
- check();
- }
-
- queue.push({ type: type, message: message, callback: fn, placeholder: placeholder, cssClass: cssClass });
- if (!isopen) this.setup();
-
- return this;
- },
-
- /**
- * Extend the log method to create custom methods
- *
- * @param {String} type Custom method name
- *
- * @return {Function}
- */
- extend : function (type) {
- if (typeof type !== "string") throw new Error("extend method must have exactly one paramter");
- return function (message, wait) {
- this.log(message, type, wait);
- return this;
- };
- },
-
- /**
- * Hide the dialog and rest to defaults
- *
- * @return {undefined}
- */
- hide : function () {
- // remove reference from queue
- queue.splice(0,1);
- // if items remaining in the queue
- if (queue.length > 0) this.setup();
- else {
- isopen = false;
- elDialog.className = "alertify alertify-hide alertify-hidden";
- elCover.className = "alertify-cover alertify-hidden";
- // set focus to the last element or body
- // after the dialog is closed
- elCallee.focus();
- }
- },
-
- /**
- * Initialize Alertify
- * Create the 2 main elements
- *
- * @return {undefined}
- */
- init : function () {
- // ensure legacy browsers support html5 tags
- document.createElement("nav");
- document.createElement("article");
- document.createElement("section");
- // cover
- elCover = document.createElement("div");
- elCover.setAttribute("id", "alertify-cover");
- elCover.className = "alertify-cover alertify-hidden";
- document.body.appendChild(elCover);
- // main element
- elDialog = document.createElement("section");
- elDialog.setAttribute("id", "alertify");
- elDialog.className = "alertify alertify-hidden";
- document.body.appendChild(elDialog);
- // log element
- elLog = document.createElement("section");
- elLog.setAttribute("id", "alertify-logs");
- elLog.className = "alertify-logs";
- document.body.appendChild(elLog);
- // set tabindex attribute on body element
- // this allows script to give it focus
- // after the dialog is closed
- document.body.setAttribute("tabindex", "0");
- // clean up init method
- delete this.init;
- },
-
- /**
- * Show a new log message box
- *
- * @param {String} message The message passed from the callee
- * @param {String} type [Optional] Optional type of log message
- * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding the log
- *
- * @return {Object}
- */
- log : function (message, type, wait) {
- // check to ensure the alertify dialog element
- // has been successfully created
- var check = function () {
- if (elLog && elLog.scrollTop !== null) return;
- else check();
- };
- // initialize alertify if it hasn't already been done
- if (typeof this.init === "function") {
- this.init();
- check();
- }
- this.notify(message, type, wait);
- return this;
- },
-
- /**
- * Add new log message
- * If a type is passed, a class name "alertify-log-{type}" will get added.
- * This allows for custom look and feel for various types of notifications.
- *
- * @param {String} message The message passed from the callee
- * @param {String} type [Optional] Type of log message
- * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding
- *
- * @return {undefined}
- */
- notify : function (message, type, wait) {
- var log = document.createElement("article");
- log.className = "alertify-log" + ((typeof type === "string" && type !== "") ? " alertify-log-" + type : "");
- log.innerHTML = message;
- // prepend child
- elLog.insertBefore(log, elLog.firstChild);
- // triggers the CSS animation
- setTimeout(function() { log.className = log.className + " alertify-log-show"; }, 50);
- this.close(log, wait);
- },
-
- /**
- * Set properties
- *
- * @param {Object} args Passing parameters
- *
- * @return {undefined}
- */
- set : function (args) {
- var k;
- // error catching
- if (typeof args !== "object" && args instanceof Array) throw new Error("args must be an object");
- // set parameters
- for (k in args) {
- if (args.hasOwnProperty(k)) {
- this[k] = args[k];
- }
- }
- },
-
- /**
- * Initiate all the required pieces for the dialog box
- *
- * @return {undefined}
- */
- setup : function () {
- var item = queue[0];
-
- isopen = true;
- elDialog.innerHTML = this.build(item);
- if (typeof item.placeholder === "string" && item.placeholder !== "") $("alertify-text").value = item.placeholder;
- this.addListeners(item.callback);
- },
-
- /**
- * Unbind events to elements
- *
- * @param {Object} el HTML Object
- * @param {Event} event Event to detach to element
- * @param {Function} fn Callback function
- *
- * @return {undefined}
- */
- unbind : function (el, event, fn) {
- if (typeof el.removeEventListener === "function") {
- el.removeEventListener(event, fn, false);
- } else if (el.detachEvent) {
- el.detachEvent("on" + event, fn);
- }
- }
- };
-
- return {
- alert : function (message, fn, cssClass) { _alertify.dialog(message, "alert", fn, "", cssClass); return this; },
- confirm : function (message, fn, cssClass) { _alertify.dialog(message, "confirm", fn, "", cssClass); return this; },
- extend : _alertify.extend,
- init : _alertify.init,
- log : function (message, type, wait) { _alertify.log(message, type, wait); return this; },
- prompt : function (message, fn, placeholder, cssClass) { _alertify.dialog(message, "prompt", fn, placeholder, cssClass); return this; },
- success : function (message, wait) { _alertify.log(message, "success", wait); return this; },
- error : function (message, wait) { _alertify.log(message, "error", wait); return this; },
- set : function (args) { _alertify.set(args); },
- labels : _alertify.labels
- };
- };
-
- // AMD and window support
- if (typeof define === "function") {
- define([], function () { return new Alertify(); });
- } else {
- if (typeof global.alertify === "undefined") {
- global.alertify = new Alertify();
- }
- }
+ "use strict";
+
+ var document = global.document,
+ Alertify;
+
+ Alertify = function () {
+
+ var _alertify = {},
+ dialogs = {},
+ isopen = false,
+ keys = { ENTER: 13, ESC: 27, SPACE: 32 },
+ queue = [],
+ $, btnCancel, btnOK, btnReset, btnFocus, elCallee, elCover, elDialog, elLog, form, input, getTransitionEvent;
+
+ /**
+ * Markup pieces
+ * @type {Object}
+ */
+ dialogs = {
+ buttons : {
+ holder : "<nav class=\"alertify-buttons\">{{buttons}}</nav>",
+ submit : "<button type=\"submit\" class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\">{{ok}}</button>",
+ ok : "<a href=\"#\" class=\"alertify-button alertify-button-ok\" id=\"alertify-ok\">{{ok}}</a>",
+ cancel : "<a href=\"#\" class=\"alertify-button alertify-button-cancel\" id=\"alertify-cancel\">{{cancel}}</a>"
+ },
+ input : "<div class=\"alertify-text-wrapper\"><input type=\"text\" class=\"alertify-text\" id=\"alertify-text\"></div>",
+ message : "<p class=\"alertify-message\">{{message}}</p>",
+ log : "<article class=\"alertify-log{{class}}\">{{message}}</article>"
+ };
+
+ /**
+ * Return the proper transitionend event
+ * @return {String} Transition type string
+ */
+ getTransitionEvent = function () {
+ var t,
+ el = document.createElement("fakeelement"),
+ transitions = {
+ "WebkitTransition" : "webkitTransitionEnd",
+ "MozTransition" : "transitionend",
+ "OTransition" : "otransitionend",
+ "transition" : "transitionend"
+ };
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined) return transitions[t];
+ }
+ };
+
+ /**
+ * Shorthand for document.getElementById()
+ *
+ * @param {String} id A specific element ID
+ * @return {Object} HTML element
+ */
+ $ = function (id) {
+ return document.getElementById(id);
+ };
+
+ /**
+ * Alertify private object
+ * @type {Object}
+ */
+ _alertify = {
+
+ /**
+ * Labels object
+ * @type {Object}
+ */
+ labels : {
+ ok : "OK",
+ cancel : "Cancel"
+ },
+
+ /**
+ * Delay number
+ * @type {Number}
+ */
+ delay : 5000,
+
+ /**
+ * Whether buttons are reversed (default is secondary/primary)
+ * @type {Boolean}
+ */
+ buttonReverse : false,
+
+ /**
+ * Which button should be focused by default
+ * @type {String} "ok" (default), "cancel", or "none"
+ */
+ buttonFocus : "ok",
+
+ /**
+ * Set the transition event on load
+ * @type {[type]}
+ */
+ transition : undefined,
+
+ /**
+ * Set the proper button click events
+ *
+ * @param {Function} fn [Optional] Callback function
+ *
+ * @return {undefined}
+ */
+ addListeners : function (fn) {
+ var hasOK = (typeof btnOK !== "undefined"),
+ hasCancel = (typeof btnCancel !== "undefined"),
+ hasInput = (typeof input !== "undefined"),
+ val = "",
+ self = this,
+ ok, cancel, common, key, reset;
+
+ // ok event handler
+ ok = function (event) {
+ if (typeof event.preventDefault !== "undefined") event.preventDefault();
+ common(event);
+ if (typeof input !== "undefined") val = input.value;
+ if (typeof fn === "function") {
+ if (typeof input !== "undefined") {
+ fn(true, val);
+ }
+ else fn(true);
+ }
+ return false;
+ };
+
+ // cancel event handler
+ cancel = function (event) {
+ if (typeof event.preventDefault !== "undefined") event.preventDefault();
+ common(event);
+ if (typeof fn === "function") fn(false);
+ return false;
+ };
+
+ // common event handler (keyup, ok and cancel)
+ common = function (event) {
+ self.hide();
+ self.unbind(document.body, "keyup", key);
+ self.unbind(btnReset, "focus", reset);
+ if (hasInput) self.unbind(form, "submit", ok);
+ if (hasOK) self.unbind(btnOK, "click", ok);
+ if (hasCancel) self.unbind(btnCancel, "click", cancel);
+ };
+
+ // keyup handler
+ key = function (event) {
+ var keyCode = event.keyCode;
+ if (keyCode === keys.SPACE && !hasInput) ok(event);
+ if (keyCode === keys.ESC && hasCancel) cancel(event);
+ };
+
+ // reset focus to first item in the dialog
+ reset = function (event) {
+ if (hasInput) input.focus();
+ else if (hasCancel) btnCancel.focus();
+ else btnOK.focus();
+ };
+
+ // handle reset focus link
+ // this ensures that the keyboard focus does not
+ // ever leave the dialog box until an action has
+ // been taken
+ this.bind(btnReset, "focus", reset);
+ // handle OK click
+ if (hasOK) this.bind(btnOK, "click", ok);
+ // handle Cancel click
+ if (hasCancel) this.bind(btnCancel, "click", cancel);
+ // listen for keys, Cancel => ESC
+ this.bind(document.body, "keyup", key);
+ // bind form submit
+ if (hasInput) this.bind(form, "submit", ok);
+ if (typeof this.transition === "undefined") {
+ this.setFocus();
+ }
+ },
+
+ /**
+ * Bind events to elements
+ *
+ * @param {Object} el HTML Object
+ * @param {Event} event Event to attach to element
+ * @param {Function} fn Callback function
+ *
+ * @return {undefined}
+ */
+ bind : function (el, event, fn) {
+ if (typeof el.addEventListener === "function") {
+ el.addEventListener(event, fn, false);
+ } else if (el.attachEvent) {
+ el.attachEvent("on" + event, fn);
+ }
+ },
+
+ /**
+ * Use alertify as the global error handler (using window.onerror)
+ *
+ * @return {boolean} success
+ */
+ handleErrors : function () {
+ if (typeof global.onerror !== "undefined") {
+ var self = this;
+ global.onerror = function (msg, url, line) {
+ self.error("[" + msg + " on line " + line + " of " + url + "]", 0);
+ };
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Append button HTML strings
+ *
+ * @param {String} secondary The secondary button HTML string
+ * @param {String} primary The primary button HTML string
+ *
+ * @return {String} The appended button HTML strings
+ */
+ appendButtons : function (secondary, primary) {
+ return this.buttonReverse ? primary + secondary : secondary + primary;
+ },
+
+ /**
+ * Build the proper message box
+ *
+ * @param {Object} item Current object in the queue
+ *
+ * @return {String} An HTML string of the message box
+ */
+ build : function (item) {
+ var html = "",
+ type = item.type,
+ message = item.message,
+ css = item.cssClass || "";
+
+ html += "<div class=\"alertify-dialog\">";
+
+ if (_alertify.buttonFocus === "none") html += "<a href=\"#\" id=\"alertify-noneFocus\" class=\"alertify-hidden\"></a>";
+
+ if (type === "prompt") html += "<form id=\"alertify-form\">";
+
+ html += "<article class=\"alertify-inner\">";
+ html += dialogs.message.replace("{{message}}", message);
+
+ if (type === "prompt") html += dialogs.input;
+
+ html += dialogs.buttons.holder;
+ html += "</article>";
+
+ if (type === "prompt") html += "</form>";
+
+ html += "<a id=\"alertify-resetFocus\" class=\"alertify-resetFocus\" href=\"#\">Reset Focus</a>";
+ html += "</div>";
+
+ switch (type) {
+ case "confirm":
+ html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.ok));
+ html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
+ break;
+ case "prompt":
+ html = html.replace("{{buttons}}", this.appendButtons(dialogs.buttons.cancel, dialogs.buttons.submit));
+ html = html.replace("{{ok}}", this.labels.ok).replace("{{cancel}}", this.labels.cancel);
+ break;
+ case "alert":
+ html = html.replace("{{buttons}}", dialogs.buttons.ok);
+ html = html.replace("{{ok}}", this.labels.ok);
+ break;
+ default:
+ break;
+ }
+
+ elDialog.className = "alertify alertify-show alertify-" + type + " " + css;
+ elCover.className = "alertify-cover";
+ return html;
+ },
+
+ /**
+ * Close the log messages
+ *
+ * @param {Object} elem HTML Element of log message to close
+ * @param {Number} wait [optional] Time (in ms) to wait before automatically hiding the message, if 0 never hide
+ *
+ * @return {undefined}
+ */
+ close : function (elem, wait) {
+ // Unary Plus: +"2" === 2
+ var timer = (wait && !isNaN(wait)) ? +wait : this.delay,
+ self = this,
+ hideElement, transitionDone;
+
+ // set click event on log messages
+ this.bind(elem, "click", function () {
+ hideElement(elem);
+ });
+ // Hide the dialog box after transition
+ // This ensure it doens't block any element from being clicked
+ transitionDone = function (event) {
+ event.stopPropagation();
+ // unbind event so function only gets called once
+ self.unbind(this, self.transition, transitionDone);
+ // remove log message
+ elLog.removeChild(this);
+ if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
+ };
+ // this sets the hide class to transition out
+ // or removes the child if css transitions aren't supported
+ hideElement = function (el) {
+ // ensure element exists
+ if (typeof el !== "undefined" && el.parentNode === elLog) {
+ // whether CSS transition exists
+ if (typeof self.transition !== "undefined") {
+ self.bind(el, self.transition, transitionDone);
+ el.className += " alertify-log-hide";
+ } else {
+ elLog.removeChild(el);
+ if (!elLog.hasChildNodes()) elLog.className += " alertify-logs-hidden";
+ }
+ }
+ };
+ // never close (until click) if wait is set to 0
+ if (wait === 0) return;
+ // set timeout to auto close the log message
+ setTimeout(function () { hideElement(elem); }, timer);
+ },
+
+ /**
+ * Create a dialog box
+ *
+ * @param {String} message The message passed from the callee
+ * @param {String} type Type of dialog to create
+ * @param {Function} fn [Optional] Callback function
+ * @param {String} placeholder [Optional] Default value for prompt input field
+ * @param {String} cssClass [Optional] Class(es) to append to dialog box
+ *
+ * @return {Object}
+ */
+ dialog : function (message, type, fn, placeholder, cssClass) {
+ // set the current active element
+ // this allows the keyboard focus to be resetted
+ // after the dialog box is closed
+ elCallee = document.activeElement;
+ // check to ensure the alertify dialog element
+ // has been successfully created
+ var check = function () {
+ if (elDialog && elDialog.scrollTop !== null) return;
+ else check();
+ };
+ // error catching
+ if (typeof message !== "string") throw new Error("message must be a string");
+ if (typeof type !== "string") throw new Error("type must be a string");
+ if (typeof fn !== "undefined" && typeof fn !== "function") throw new Error("fn must be a function");
+ // initialize alertify if it hasn't already been done
+ if (typeof this.init === "function") {
+ this.init();
+ check();
+ }
+
+ queue.push({ type: type, message: message, callback: fn, placeholder: placeholder, cssClass: cssClass });
+ if (!isopen) this.setup();
+
+ return this;
+ },
+
+ /**
+ * Extend the log method to create custom methods
+ *
+ * @param {String} type Custom method name
+ *
+ * @return {Function}
+ */
+ extend : function (type) {
+ if (typeof type !== "string") throw new Error("extend method must have exactly one paramter");
+ return function (message, wait) {
+ this.log(message, type, wait);
+ return this;
+ };
+ },
+
+ /**
+ * Hide the dialog and rest to defaults
+ *
+ * @return {undefined}
+ */
+ hide : function () {
+ var transitionDone,
+ self = this;
+ // remove reference from queue
+ queue.splice(0,1);
+ // if items remaining in the queue
+ if (queue.length > 0) this.setup();
+ else {
+ isopen = false;
+ // Hide the dialog box after transition
+ // This ensure it doens't block any element from being clicked
+ transitionDone = function (event) {
+ event.stopPropagation();
+ elDialog.className += " alertify-isHidden";
+ // unbind event so function only gets called once
+ self.unbind(elDialog, self.transition, transitionDone);
+ };
+ // whether CSS transition exists
+ if (typeof this.transition !== "undefined") {
+ this.bind(elDialog, this.transition, transitionDone);
+ elDialog.className = "alertify alertify-hide alertify-hidden";
+ } else {
+ elDialog.className = "alertify alertify-hide alertify-hidden alertify-isHidden";
+ }
+ elCover.className = "alertify-cover alertify-cover-hidden";
+ // set focus to the last element or body
+ // after the dialog is closed
+ elCallee.focus();
+ }
+ },
+
+ /**
+ * Initialize Alertify
+ * Create the 2 main elements
+ *
+ * @return {undefined}
+ */
+ init : function () {
+ // ensure legacy browsers support html5 tags
+ document.createElement("nav");
+ document.createElement("article");
+ document.createElement("section");
+ // cover
+ elCover = document.createElement("div");
+ elCover.setAttribute("id", "alertify-cover");
+ elCover.className = "alertify-cover alertify-cover-hidden";
+ document.body.appendChild(elCover);
+ // main element
+ elDialog = document.createElement("section");
+ elDialog.setAttribute("id", "alertify");
+ elDialog.className = "alertify alertify-hidden";
+ document.body.appendChild(elDialog);
+ // log element
+ elLog = document.createElement("section");
+ elLog.setAttribute("id", "alertify-logs");
+ elLog.className = "alertify-logs alertify-logs-hidden";
+ document.body.appendChild(elLog);
+ // set tabindex attribute on body element
+ // this allows script to give it focus
+ // after the dialog is closed
+ document.body.setAttribute("tabindex", "0");
+ // set transition type
+ this.transition = getTransitionEvent();
+ // clean up init method
+ delete this.init;
+ },
+
+ /**
+ * Show a new log message box
+ *
+ * @param {String} message The message passed from the callee
+ * @param {String} type [Optional] Optional type of log message
+ * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding the log
+ *
+ * @return {Object}
+ */
+ log : function (message, type, wait) {
+ // check to ensure the alertify dialog element
+ // has been successfully created
+ var check = function () {
+ if (elLog && elLog.scrollTop !== null) return;
+ else check();
+ };
+ // initialize alertify if it hasn't already been done
+ if (typeof this.init === "function") {
+ this.init();
+ check();
+ }
+ elLog.className = "alertify-logs";
+ this.notify(message, type, wait);
+ return this;
+ },
+
+ /**
+ * Add new log message
+ * If a type is passed, a class name "alertify-log-{type}" will get added.
+ * This allows for custom look and feel for various types of notifications.
+ *
+ * @param {String} message The message passed from the callee
+ * @param {String} type [Optional] Type of log message
+ * @param {Number} wait [Optional] Time (in ms) to wait before auto-hiding
+ *
+ * @return {undefined}
+ */
+ notify : function (message, type, wait) {
+ var log = document.createElement("article");
+ log.className = "alertify-log" + ((typeof type === "string" && type !== "") ? " alertify-log-" + type : "");
+ log.innerHTML = message;
+ // prepend child
+ elLog.insertBefore(log, elLog.firstChild);
+ // triggers the CSS animation
+ setTimeout(function() { log.className = log.className + " alertify-log-show"; }, 50);
+ this.close(log, wait);
+ },
+
+ /**
+ * Set properties
+ *
+ * @param {Object} args Passing parameters
+ *
+ * @return {undefined}
+ */
+ set : function (args) {
+ var k;
+ // error catching
+ if (typeof args !== "object" && args instanceof Array) throw new Error("args must be an object");
+ // set parameters
+ for (k in args) {
+ if (args.hasOwnProperty(k)) {
+ this[k] = args[k];
+ }
+ }
+ },
+
+ /**
+ * Common place to set focus to proper element
+ *
+ * @return {undefined}
+ */
+ setFocus : function () {
+ if (input) {
+ input.focus();
+ input.select();
+ }
+ else btnFocus.focus();
+ },
+
+ /**
+ * Initiate all the required pieces for the dialog box
+ *
+ * @return {undefined}
+ */
+ setup : function () {
+ var item = queue[0],
+ self = this,
+ transitionDone;
+
+ // dialog is open
+ isopen = true;
+ // Set button focus after transition
+ transitionDone = function (event) {
+ event.stopPropagation();
+ self.setFocus();
+ // unbind event so function only gets called once
+ self.unbind(elDialog, self.transition, transitionDone);
+ };
+ // whether CSS transition exists
+ if (typeof this.transition !== "undefined") {
+ this.bind(elDialog, this.transition, transitionDone);
+ }
+ // build the proper dialog HTML
+ elDialog.innerHTML = this.build(item);
+ // assign all the common elements
+ btnReset = $("alertify-resetFocus");
+ btnOK = $("alertify-ok") || undefined;
+ btnCancel = $("alertify-cancel") || undefined;
+ btnFocus = (_alertify.buttonFocus === "cancel") ? btnCancel : ((_alertify.buttonFocus === "none") ? $("alertify-noneFocus") : btnOK),
+ input = $("alertify-text") || undefined;
+ form = $("alertify-form") || undefined;
+ // add placeholder value to the input field
+ if (typeof item.placeholder === "string" && item.placeholder !== "") input.value = item.placeholder;
+ this.addListeners(item.callback);
+ },
+
+ /**
+ * Unbind events to elements
+ *
+ * @param {Object} el HTML Object
+ * @param {Event} event Event to detach to element
+ * @param {Function} fn Callback function
+ *
+ * @return {undefined}
+ */
+ unbind : function (el, event, fn) {
+ if (typeof el.removeEventListener === "function") {
+ el.removeEventListener(event, fn, false);
+ } else if (el.detachEvent) {
+ el.detachEvent("on" + event, fn);
+ }
+ }
+ };
+
+ return {
+ alert : function (message, fn, cssClass) { _alertify.dialog(message, "alert", fn, "", cssClass); return this; },
+ confirm : function (message, fn, cssClass) { _alertify.dialog(message, "confirm", fn, "", cssClass); return this; },
+ extend : _alertify.extend,
+ init : _alertify.init,
+ log : function (message, type, wait) { _alertify.log(message, type, wait); return this; },
+ prompt : function (message, fn, placeholder, cssClass) { _alertify.dialog(message, "prompt", fn, placeholder, cssClass); return this; },
+ success : function (message, wait) { _alertify.log(message, "success", wait); return this; },
+ error : function (message, wait) { _alertify.log(message, "error", wait); return this; },
+ set : function (args) { _alertify.set(args); },
+ labels : _alertify.labels,
+ debug : _alertify.handleErrors
+ };
+ };
+
+ // AMD and window support
+ if (typeof define === "function") {
+ define([], function () { return new Alertify(); });
+ } else if (typeof global.alertify === "undefined") {
+ global.alertify = new Alertify();
+ }
}(this));
+
//
// name : holler-client.js