1/** 2 * Growler.js - Display 'Growl'-like notifications. 3 * 4 * Notice Options (passed to 'Growler.growl()'): 5 * - className: (string) An optional additional CSS class to apply to notice. 6 * - header: (string) The title that is displayed for the notice. 7 * - life: (float) The number of seconds in which the notice remains visible. 8 * - log: (boolean) If true, will log the entry. 9 * - opacity: (float) The default opacity of the notifications. 10 * - speedin: (float) The speed in seconds in which the notice is shown. 11 * - speedout: (float) The speed in seconds in which the notice is hidden. 12 * - sticky: (boolean) Determines if the notice should always remain visible 13 * until closed by the user. 14 * 15 * Growler Options (passed to 'new Growler()'): 16 * - info: (string) The localized string to display as an information message 17 * at the top of the log. 18 * - location: (string) The location of the growler notices. This can be: 19 * - tr: top-right 20 * - br: bottom-right 21 * - tl: top-left 22 * - bl: bottom-left 23 * - tc: top-center 24 * - bc: bottom-center 25 * - log: (boolean) Enable logging. 26 * - noalerts: (string) The localized string to display when no log entries 27 * are present. 28 * - noclick: (boolean) Don't check for clicks on Growler elements. 29 * 30 * Custom Events: 31 * -------------- 32 * Custom events are triggered on the notice element. The parameters given 33 * below are available through the 'memo' property of the Event object. 34 * 35 * Growler:created 36 * Fired on TODO 37 * params: NONE 38 * 39 * Growler:destroyed 40 * Fired on TODO 41 * params: NONE 42 * 43 * Growler:linkClick 44 * Fired on click of a link in a Growler message. 45 * params: The link 46 * 47 * Growler:toggled 48 * Fired on toggling of the backlog 49 * params: The state after the toggling 50 * 51 * 52 * Growler has been tested with Safari 3(Mac|Win), Firefox 3(Mac|Win), IE7+, 53 * and Opera. 54 * 55 * Requires prototypejs 1.6+ and scriptaculous 1.8+ (effects.js only). 56 * 57 * Code adapted from k.Growler v1.0.0 58 * http://code.google.com/p/kproto/ 59 * Written by Kevin Armstrong <[email protected]> 60 * Released under the MIT license 61 * 62 * @author Michael Slusarz <[email protected]> 63 * @copyright 2010-2015 Horde LLC 64 * @license LGPL-2.1 (http://www.horde.org/licenses/lgpl21) 65 */ 66 67(function() { 68 69 var noticeOptions = { 70 header: '', 71 speedin: 0.3, 72 speedout: 0.5, 73 life: 5, 74 opacity: 0.8, 75 sticky: false, 76 className: '' 77 }, 78 79 growlerOptions = { 80 clear: 'Clear All', 81 location: 'tr', 82 log: false, 83 noalerts: 'No Alerts', 84 info: 'This is the notification log.' 85 }; 86 87 function removeNotice(n) 88 { 89 n.fade({ 90 afterFinish: function() { 91 try { 92 n.fire('Growler:destroyed'); 93 n.remove(); 94 if (!$('Growler').childElements().size()) { 95 $('Growler').hide(); 96 } 97 } catch (e) {} 98 }, 99 duration: n.retrieve('so') 100 }); 101 } 102 103 window.Growler = Class.create({ 104 105 initialize: function(opts) 106 { 107 var style; 108 109 this.opts = Object.extend(Object.clone(growlerOptions), opts || {}); 110 111 this.growler = new Element('DIV', { id: 'Growler' }).setStyle({ 112 position: 'fixed', 113 padding: '10px', 114 zIndex: 50000 115 }).hide(); 116 this.growler.on('click', 'DIV.GrowlerNotice', function(e, elt) { 117 removeNotice(elt); 118 }); 119 120 if (this.opts.log) { 121 this.growlerlog = new Element('DIV', { id: 'GrowlerLog' }) 122 .insert(new Element('DIV').hide() 123 .insert(new Element('UL') 124 .insert(new Element('LI', { className: 'GrowlerInfo' }) 125 .insert(this.opts.info) 126 .insert(new Element('SPAN', { className: 'GrowlerLogClear' }) 127 .insert('[') 128 .insert(new Element('A') 129 .insert(this.opts.clear)) 130 .insert(']'))) 131 .insert(new Element('LI', { className: 'GrowlerNoAlerts' })
132 .insert(this.opts.noalerts)))); 133 $(document.body).insert(this.growlerlog); 134 this.growlerlog.on('click', 'SPAN.GrowlerLogClear A', function() { 135 this.growlerlog.down('LI.GrowlerInfo').siblings().invoke('remove'); 136 this.growlerlog.down('UL').insert( 137 new Element('LI', { className: 'GrowlerNoAlerts' }) 138 .insert(this.opts.noalerts)); 139 }.bind(this)); 140 } 141 142 style = { 143 bc: { bottom: 0, left: '25%', width: '50%' }, 144 bl: { top: 0, right: 0 }, 145 br: { bottom: 0, right: 0 }, 146 tc: { top: 0, left: '25%', width: '50%' }, 147 tl: { top: 0, left: 0 } 148 }; 149 150 this.growler.setStyle( 151 style[this.opts.location] || { top: 0, right: 0 } 152 ); 153 this.growler.wrap(document.body); 154 155 if (!opts.noclick) { 156 this.growler.on('click', 'A', function(e) { 157 e.stop(); 158 this.growler.fire('Growler:linkClick', e.element()); 159 }.bind(this)); 160 } 161 }, 162 163 growl: function(msg, options) 164 { 165 var notice, log, tmp, 166 opts = Object.clone(noticeOptions); 167 Object.extend(opts, options || {}); 168 169 /* Check if sticky notice with same message already exists. */ 170 if (this.growler.select('> .GrowlerSticky').detect(function(n) { 171 return (n.down('.GrowlerNoticeBody').textContent == msg); 172 })) { 173 return; 174 } 175 176 if (opts.log && this.growlerlog) { 177 tmp = this.growlerlog.down('DIV UL'); 178 if (tmp.down('.GrowlerNoAlerts')) { 179 tmp.down('.GrowlerNoAlerts').remove(); 180 } 181 tmp.insert( 182 new Element('LI', { 183 className: opts.className.empty() ? null : opts.className 184 }).insert(msg).insert(new Element('SPAN', { 185 className: 'GrowlerAlertDate'} 186 ).insert('[' + (new Date()).toLocaleString() + ']')) 187 ); 188 } 189 190 notice = new Element('DIV', { className: 'GrowlerNotice' }) 191 .setStyle({ display: 'block', opacity: 0 }) 192 .store('so', opts.speedout); 193 if (!opts.className.empty()) { 194 notice.addClassName(opts.className); 195 } 196 197 notice.insert(new Element('DIV', { 198 className: 'GrowlerNoticeExit' 199 }).update("×")); 200 201 if (!opts.header.empty()) { 202 notice.insert(new Element('DIV', { 203 className: 'GrowlerNoticeHead' 204 }).update(opts.header)); 205 } 206 207 notice.insert(new Element('DIV', { 208 className: 'GrowlerNoticeBody' 209 }).update(msg)); 210 211 this.growler.show().insert(notice); 212 213 new Effect.Opacity(notice, { 214 to: opts.opacity, 215 duration: opts.speedin 216 }); 217 218 if (opts.sticky) { 219 notice.addClassName('GrowlerSticky'); 220 } else { 221 removeNotice.delay(opts.life, notice); 222 } 223 224 notice.fire('Growler:created'); 225 226 return notice; 227 }, 228 229 ungrowl: function(n) 230 { 231 removeNotice(n); 232 }, 233 234 toggleLog: function() 235 { 236 if (!this.growlerlog) { 237 return; 238 }
239 Effect.toggle(this.growlerlog.down('DIV'), 'blind', { 240 duration: 0.5, 241 queue: { 242 position: 'end', 243 scope: 'GrowlerLog', 244 limit: 2 245 } 246 }); 247 this.logvisible = !this.logvisible; 248 this.growlerlog.fire('Growler:toggled', { 249 visible: this.logvisible 250 }); 251 return this.logvisible; 252 }, 253 254 logVisible: function() 255 { 256 return this.growlerlog && this.logvisible; 257 }, 258 259 logSize: function() 260 { 261 return (this.growlerlog && this.growlerlog.down('.GrowlerNoAlerts')) 262 ? 0 263 : this.growlerlog.down('UL').childElements().size(); 264 } 265 266 }); 267 268})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.