├── .gitignore ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── lib ├── messengerjs-rails.rb └── messengerjs-rails │ └── version.rb ├── messengerjs-rails.gemspec └── vendor └── assets ├── javascripts ├── messenger-theme-flat.js ├── messenger-theme-future.js ├── messenger.js └── messenger.min.js └── stylesheets ├── messenger-spinner.css ├── messenger-theme-air.css ├── messenger-theme-block.css ├── messenger-theme-flat.css ├── messenger-theme-future.css ├── messenger-theme-ice.css └── messenger.css /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.gem 3 | *.rbc 4 | .bundle 5 | .config 6 | .yardoc 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in messengerjs-rails.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining 2 | a copy of this software and associated documentation files (the 3 | "Software"), to deal in the Software without restriction, including 4 | without limitation the rights to use, copy, modify, merge, publish, 5 | distribute, sublicense, and/or sell copies of the Software, and to 6 | permit persons to whom the Software is furnished to do so, subject to 7 | the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be 10 | included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 13 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 14 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 16 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 17 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 18 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # messengerjs-rails 2 | 3 | messengerjs-rails is a Rails (3.1 and above) wrapper for [Messenger](http://github.hubspot.com/messenger/) javascript library. 4 | 5 | # Messenger 6 | 7 | - Show messages in your app. 8 | - Wrap AJAX requests with progress, success and error messages, and add retry to your failed requests. 9 | - Add actions (undo, cancel, etc.) to your messages. 10 | 11 | 12 | ![Messenger](https://raw.github.com/HubSpot/messenger/master/docs/images/messenger.gif) 13 | 14 | 15 | #### [Demo and Usage](http://hubspot.github.com/messenger/docs/welcome) 16 | #### [Docs](http://github.hubspot.com/messenger/) 17 | 18 | 19 | ## Requirement/Dependency: 20 | 21 | 1. jQuery 22 | 23 | 2. Plays well with, but doesn't require, Bootstrap 24 | 25 | ## Installation 26 | 27 | Add the following to your gemfile: 28 | 29 | gem "messengerjs-rails", "~> 1.4.1" 30 | 31 | Add the following directive to your application.coffee / application.js: 32 | 33 | //= require jquery-rails 34 | * 35 | * 36 | //= require messenger 37 | //= require messenger-theme-future 38 | 39 | Add the following directive to your application.scss / application.css. There are four themes/styles provided (future, air, block and ice), change required stylesheet as needed. 40 | 41 | *= require messenger 42 | *= require messenger-spinner 43 | *= require messenger-theme-future 44 | 45 | ## Versioning 46 | 47 | Every attempt is made to mirror the currently shipping Messenger version number wherever possible. 48 | The major, minor, and patch version numbers will always represent the Messenger version. 49 | 50 | ## Contributing 51 | 52 | Feel free to open an issue ticket if you find something that could be improved. 53 | 54 | ## Acknowledgements 55 | 56 | Copyright Ben Song(zbin.song@gmail.com), released under the MIT License. 57 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require "bundler/gem_tasks" -------------------------------------------------------------------------------- /lib/messengerjs-rails.rb: -------------------------------------------------------------------------------- 1 | require "messengerjs-rails/version" 2 | 3 | module MessengerJS 4 | module Rails 5 | class Engine < ::Rails::Engine 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /lib/messengerjs-rails/version.rb: -------------------------------------------------------------------------------- 1 | module MessengerJS 2 | module Rails 3 | VERSION = "1.5.0" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /messengerjs-rails.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/messengerjs-rails/version', __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'messengerjs-rails' 6 | s.version = MessengerJS::Rails::VERSION 7 | s.date = '2014-03-21' 8 | s.summary = 'Messenger js on Rails' 9 | s.description = 'Injects Messenger javascript and stylesheets into your asset pipeline.' 10 | s.authors = ["Ben Song"] 11 | s.email = 'zbin.song@gmail.com' 12 | s.files = Dir["{lib,vendor}/**/*"] + ["MIT-LICENSE", "README.md"] 13 | s.homepage = 'https://github.com/benjis/messengerjs-rails/' 14 | s.license = 'MIT' 15 | end -------------------------------------------------------------------------------- /vendor/assets/javascripts/messenger-theme-flat.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var $, FlatMessage, spinner_template, 3 | __hasProp = {}.hasOwnProperty, 4 | __extends = function (child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 5 | 6 | $ = jQuery; 7 | 8 | spinner_template = '
\n \n \n \n \n \n \n
'; 9 | 10 | FlatMessage = (function (_super) { 11 | 12 | __extends(FlatMessage, _super); 13 | 14 | function FlatMessage() { 15 | return FlatMessage.__super__.constructor.apply(this, arguments); 16 | } 17 | 18 | FlatMessage.prototype.template = function (opts) { 19 | var $message; 20 | $message = FlatMessage.__super__.template.apply(this, arguments); 21 | $message.append($(spinner_template)); 22 | return $message; 23 | }; 24 | 25 | return FlatMessage; 26 | 27 | })(window.Messenger.Message); 28 | 29 | window.Messenger.themes.flat = { 30 | Message: FlatMessage 31 | }; 32 | 33 | }).call(this); -------------------------------------------------------------------------------- /vendor/assets/javascripts/messenger-theme-future.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var $, FutureMessage, spinner_template, 3 | __hasProp = {}.hasOwnProperty, 4 | __extends = function (child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 5 | 6 | $ = jQuery; 7 | 8 | spinner_template = '
\n \n \n \n \n \n \n
'; 9 | 10 | FutureMessage = (function (_super) { 11 | 12 | __extends(FutureMessage, _super); 13 | 14 | function FutureMessage() { 15 | return FutureMessage.__super__.constructor.apply(this, arguments); 16 | } 17 | 18 | FutureMessage.prototype.template = function (opts) { 19 | var $message; 20 | $message = FutureMessage.__super__.template.apply(this, arguments); 21 | $message.append($(spinner_template)); 22 | return $message; 23 | }; 24 | 25 | return FutureMessage; 26 | 27 | })(window.Messenger.Message); 28 | 29 | window.Messenger.themes.future = { 30 | Message: FutureMessage 31 | }; 32 | 33 | }).call(this); -------------------------------------------------------------------------------- /vendor/assets/javascripts/messenger.js: -------------------------------------------------------------------------------- 1 | /*! messenger 1.5.0 */ 2 | /* 3 | * This file begins the output concatenated into messenger.js 4 | * 5 | * It establishes the Messenger object while preserving whatever it was before 6 | * (for noConflict), and making it a callable function. 7 | */ 8 | 9 | (function () { 10 | var _prevMessenger = window.Messenger; 11 | var localMessenger; 12 | 13 | localMessenger = window.Messenger = function () { 14 | return localMessenger._call.apply(this, arguments); 15 | } 16 | 17 | window.Messenger.noConflict = function () { 18 | window.Messenger = _prevMessenger; 19 | 20 | return localMessenger; 21 | } 22 | })(); 23 | 24 | /* 25 | * This file contains shims for when Underscore and Backbone 26 | * are not included. 27 | * 28 | * Portions taken from Underscore.js and Backbone.js 29 | * Both of which are Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud 30 | */ 31 | window.Messenger._ = (function () { 32 | if (window._) 33 | return window._ 34 | 35 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 36 | 37 | // Create quick reference variables for speed access to core prototypes. 38 | var push = ArrayProto.push, 39 | slice = ArrayProto.slice, 40 | concat = ArrayProto.concat, 41 | toString = ObjProto.toString, 42 | hasOwnProperty = ObjProto.hasOwnProperty; 43 | 44 | // All **ECMAScript 5** native function implementations that we hope to use 45 | // are declared here. 46 | var 47 | nativeForEach = ArrayProto.forEach, 48 | nativeMap = ArrayProto.map, 49 | nativeReduce = ArrayProto.reduce, 50 | nativeReduceRight = ArrayProto.reduceRight, 51 | nativeFilter = ArrayProto.filter, 52 | nativeEvery = ArrayProto.every, 53 | nativeSome = ArrayProto.some, 54 | nativeIndexOf = ArrayProto.indexOf, 55 | nativeLastIndexOf = ArrayProto.lastIndexOf, 56 | nativeIsArray = Array.isArray, 57 | nativeKeys = Object.keys, 58 | nativeBind = FuncProto.bind; 59 | 60 | // Create a safe reference to the Underscore object for use below. 61 | var _ = {}; 62 | 63 | // Establish the object that gets returned to break out of a loop iteration. 64 | var breaker = {}; 65 | 66 | var each = _.each = _.forEach = function (obj, iterator, context) { 67 | if (obj == null) return; 68 | if (nativeForEach && obj.forEach === nativeForEach) { 69 | obj.forEach(iterator, context); 70 | } else if (obj.length === +obj.length) { 71 | for (var i = 0, l = obj.length; i < l; i++) { 72 | if (iterator.call(context, obj[i], i, obj) === breaker) return; 73 | } 74 | } else { 75 | for (var key in obj) { 76 | if (_.has(obj, key)) { 77 | if (iterator.call(context, obj[key], key, obj) === breaker) return; 78 | } 79 | } 80 | } 81 | }; 82 | 83 | _.result = function (object, property) { 84 | if (object == null) return null; 85 | var value = object[property]; 86 | return _.isFunction(value) ? value.call(object) : value; 87 | }; 88 | 89 | _.once = function (func) { 90 | var ran = false, memo; 91 | return function () { 92 | if (ran) return memo; 93 | ran = true; 94 | memo = func.apply(this, arguments); 95 | func = null; 96 | return memo; 97 | }; 98 | }; 99 | 100 | var idCounter = 0; 101 | _.uniqueId = function (prefix) { 102 | var id = ++idCounter + ''; 103 | return prefix ? prefix + id : id; 104 | }; 105 | 106 | _.filter = _.select = function (obj, iterator, context) { 107 | var results = []; 108 | if (obj == null) return results; 109 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 110 | each(obj, function (value, index, list) { 111 | if (iterator.call(context, value, index, list)) results[results.length] = value; 112 | }); 113 | return results; 114 | }; 115 | 116 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. 117 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function (name) { 118 | _['is' + name] = function (obj) { 119 | return toString.call(obj) == '[object ' + name + ']'; 120 | }; 121 | }); 122 | 123 | _.defaults = function (obj) { 124 | each(slice.call(arguments, 1), function (source) { 125 | if (source) { 126 | for (var prop in source) { 127 | if (obj[prop] == null) obj[prop] = source[prop]; 128 | } 129 | } 130 | }); 131 | return obj; 132 | }; 133 | 134 | _.extend = function (obj) { 135 | each(slice.call(arguments, 1), function (source) { 136 | if (source) { 137 | for (var prop in source) { 138 | obj[prop] = source[prop]; 139 | } 140 | } 141 | }); 142 | return obj; 143 | }; 144 | 145 | _.keys = nativeKeys || function (obj) { 146 | if (obj !== Object(obj)) throw new TypeError('Invalid object'); 147 | var keys = []; 148 | for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; 149 | return keys; 150 | }; 151 | 152 | _.bind = function (func, context) { 153 | if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 154 | var args = slice.call(arguments, 2); 155 | return function () { 156 | return func.apply(context, args.concat(slice.call(arguments))); 157 | }; 158 | }; 159 | 160 | _.isObject = function (obj) { 161 | return obj === Object(obj); 162 | }; 163 | 164 | return _; 165 | })(); 166 | 167 | window.Messenger.Events = (function () { 168 | if (window.Backbone && Backbone.Events) { 169 | return Backbone.Events; 170 | } 171 | 172 | var eventsShim = function () { 173 | var eventSplitter = /\s+/; 174 | 175 | var eventsApi = function (obj, action, name, rest) { 176 | if (!name) return true; 177 | if (typeof name === 'object') { 178 | for (var key in name) { 179 | obj[action].apply(obj, [key, name[key]].concat(rest)); 180 | } 181 | } else if (eventSplitter.test(name)) { 182 | var names = name.split(eventSplitter); 183 | for (var i = 0, l = names.length; i < l; i++) { 184 | obj[action].apply(obj, [names[i]].concat(rest)); 185 | } 186 | } else { 187 | return true; 188 | } 189 | }; 190 | 191 | var triggerEvents = function (events, args) { 192 | var ev, i = -1, l = events.length; 193 | switch (args.length) { 194 | case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); 195 | return; 196 | case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]); 197 | return; 198 | case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]); 199 | return; 200 | case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]); 201 | return; 202 | default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); 203 | } 204 | }; 205 | 206 | var Events = { 207 | 208 | on: function (name, callback, context) { 209 | if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this; 210 | this._events || (this._events = {}); 211 | var list = this._events[name] || (this._events[name] = []); 212 | list.push({ callback: callback, context: context, ctx: context || this }); 213 | return this; 214 | }, 215 | 216 | once: function (name, callback, context) { 217 | if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this; 218 | var self = this; 219 | var once = _.once(function () { 220 | self.off(name, once); 221 | callback.apply(this, arguments); 222 | }); 223 | once._callback = callback; 224 | this.on(name, once, context); 225 | return this; 226 | }, 227 | 228 | off: function (name, callback, context) { 229 | var list, ev, events, names, i, l, j, k; 230 | if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; 231 | if (!name && !callback && !context) { 232 | this._events = {}; 233 | return this; 234 | } 235 | 236 | names = name ? [name] : _.keys(this._events); 237 | for (i = 0, l = names.length; i < l; i++) { 238 | name = names[i]; 239 | if (list = this._events[name]) { 240 | events = []; 241 | if (callback || context) { 242 | for (j = 0, k = list.length; j < k; j++) { 243 | ev = list[j]; 244 | if ((callback && callback !== ev.callback && 245 | callback !== ev.callback._callback) || 246 | (context && context !== ev.context)) { 247 | events.push(ev); 248 | } 249 | } 250 | } 251 | this._events[name] = events; 252 | } 253 | } 254 | 255 | return this; 256 | }, 257 | 258 | trigger: function (name) { 259 | if (!this._events) return this; 260 | var args = Array.prototype.slice.call(arguments, 1); 261 | if (!eventsApi(this, 'trigger', name, args)) return this; 262 | var events = this._events[name]; 263 | var allEvents = this._events.all; 264 | if (events) triggerEvents(events, args); 265 | if (allEvents) triggerEvents(allEvents, arguments); 266 | return this; 267 | }, 268 | 269 | listenTo: function (obj, name, callback) { 270 | var listeners = this._listeners || (this._listeners = {}); 271 | var id = obj._listenerId || (obj._listenerId = _.uniqueId('l')); 272 | listeners[id] = obj; 273 | obj.on(name, typeof name === 'object' ? this : callback, this); 274 | return this; 275 | }, 276 | 277 | stopListening: function (obj, name, callback) { 278 | var listeners = this._listeners; 279 | if (!listeners) return; 280 | if (obj) { 281 | obj.off(name, typeof name === 'object' ? this : callback, this); 282 | if (!name && !callback) delete listeners[obj._listenerId]; 283 | } else { 284 | if (typeof name === 'object') callback = this; 285 | for (var id in listeners) { 286 | listeners[id].off(name, callback, this); 287 | } 288 | this._listeners = {}; 289 | } 290 | return this; 291 | } 292 | }; 293 | 294 | Events.bind = Events.on; 295 | Events.unbind = Events.off; 296 | return Events; 297 | }; 298 | return eventsShim(); 299 | })(); 300 | 301 | (function () { 302 | var $, ActionMessenger, BaseView, Events, RetryingMessage, _, _Message, _Messenger, _ref, _ref1, _ref2, 303 | __hasProp = {}.hasOwnProperty, 304 | __extends = function (child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 305 | __slice = [].slice, 306 | __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; }; 307 | 308 | $ = jQuery; 309 | 310 | _ = (_ref = window._) != null ? _ref : window.Messenger._; 311 | 312 | Events = (_ref1 = typeof Backbone !== "undefined" && Backbone !== null ? Backbone.Events : void 0) != null ? _ref1 : window.Messenger.Events; 313 | 314 | BaseView = (function () { 315 | 316 | function BaseView(options) { 317 | $.extend(this, Events); 318 | if (_.isObject(options)) { 319 | if (options.el) { 320 | this.setElement(options.el); 321 | } 322 | this.model = options.model; 323 | } 324 | this.initialize.apply(this, arguments); 325 | } 326 | 327 | BaseView.prototype.setElement = function (el) { 328 | this.$el = $(el); 329 | return this.el = this.$el[0]; 330 | }; 331 | 332 | BaseView.prototype.delegateEvents = function (events) { 333 | var delegateEventSplitter, eventName, key, match, method, selector, _results; 334 | if (!(events || (events = _.result(this, "events")))) { 335 | return; 336 | } 337 | this.undelegateEvents(); 338 | delegateEventSplitter = /^(\S+)\s*(.*)$/; 339 | _results = []; 340 | for (key in events) { 341 | method = events[key]; 342 | if (!_.isFunction(method)) { 343 | method = this[events[key]]; 344 | } 345 | if (!method) { 346 | throw new Error("Method \"" + events[key] + "\" does not exist"); 347 | } 348 | match = key.match(delegateEventSplitter); 349 | eventName = match[1]; 350 | selector = match[2]; 351 | method = _.bind(method, this); 352 | eventName += ".delegateEvents" + this.cid; 353 | if (selector === '') { 354 | _results.push(this.jqon(eventName, method)); 355 | } else { 356 | _results.push(this.jqon(eventName, selector, method)); 357 | } 358 | } 359 | return _results; 360 | }; 361 | 362 | BaseView.prototype.jqon = function (eventName, selector, method) { 363 | var _ref2; 364 | if (this.$el.on != null) { 365 | return (_ref2 = this.$el).on.apply(_ref2, arguments); 366 | } else { 367 | if (!(method != null)) { 368 | method = selector; 369 | selector = void 0; 370 | } 371 | if (selector != null) { 372 | return this.$el.delegate(selector, eventName, method); 373 | } else { 374 | return this.$el.bind(eventName, method); 375 | } 376 | } 377 | }; 378 | 379 | BaseView.prototype.jqoff = function (eventName) { 380 | var _ref2; 381 | if (this.$el.off != null) { 382 | return (_ref2 = this.$el).off.apply(_ref2, arguments); 383 | } else { 384 | this.$el.undelegate(); 385 | return this.$el.unbind(eventName); 386 | } 387 | }; 388 | 389 | BaseView.prototype.undelegateEvents = function () { 390 | return this.jqoff(".delegateEvents" + this.cid); 391 | }; 392 | 393 | BaseView.prototype.remove = function () { 394 | this.undelegateEvents(); 395 | return this.$el.remove(); 396 | }; 397 | 398 | return BaseView; 399 | 400 | })(); 401 | 402 | _Message = (function (_super) { 403 | 404 | __extends(_Message, _super); 405 | 406 | function _Message() { 407 | return _Message.__super__.constructor.apply(this, arguments); 408 | } 409 | 410 | _Message.prototype.defaults = { 411 | hideAfter: 10, 412 | scroll: true, 413 | closeButtonText: "×", 414 | escapeText: false 415 | }; 416 | 417 | _Message.prototype.initialize = function (opts) { 418 | if (opts == null) { 419 | opts = {}; 420 | } 421 | this.shown = false; 422 | this.rendered = false; 423 | this.messenger = opts.messenger; 424 | return this.options = $.extend({}, this.options, opts, this.defaults); 425 | }; 426 | 427 | _Message.prototype.show = function () { 428 | var wasShown; 429 | if (!this.rendered) { 430 | this.render(); 431 | } 432 | this.$message.removeClass('messenger-hidden'); 433 | wasShown = this.shown; 434 | this.shown = true; 435 | if (!wasShown) { 436 | return this.trigger('show'); 437 | } 438 | }; 439 | 440 | _Message.prototype.hide = function () { 441 | var wasShown; 442 | if (!this.rendered) { 443 | return; 444 | } 445 | this.$message.addClass('messenger-hidden'); 446 | wasShown = this.shown; 447 | this.shown = false; 448 | if (wasShown) { 449 | return this.trigger('hide'); 450 | } 451 | }; 452 | 453 | _Message.prototype.cancel = function () { 454 | return this.hide(); 455 | }; 456 | 457 | _Message.prototype.update = function (opts) { 458 | var _ref2, 459 | _this = this; 460 | if (_.isString(opts)) { 461 | opts = { 462 | message: opts 463 | }; 464 | } 465 | $.extend(this.options, opts); 466 | this.lastUpdate = new Date(); 467 | this.rendered = false; 468 | this.events = (_ref2 = this.options.events) != null ? _ref2 : {}; 469 | this.render(); 470 | this.actionsToEvents(); 471 | this.delegateEvents(); 472 | this.checkClickable(); 473 | if (this.options.hideAfter) { 474 | this.$message.addClass('messenger-will-hide-after'); 475 | if (this._hideTimeout != null) { 476 | clearTimeout(this._hideTimeout); 477 | } 478 | this._hideTimeout = setTimeout(function () { 479 | return _this.hide(); 480 | }, this.options.hideAfter * 1000); 481 | } else { 482 | this.$message.removeClass('messenger-will-hide-after'); 483 | } 484 | if (this.options.hideOnNavigate) { 485 | this.$message.addClass('messenger-will-hide-on-navigate'); 486 | if ((typeof Backbone !== "undefined" && Backbone !== null ? Backbone.history : void 0) != null) { 487 | Backbone.history.on('route', function () { 488 | return _this.hide(); 489 | }); 490 | } 491 | } else { 492 | this.$message.removeClass('messenger-will-hide-on-navigate'); 493 | } 494 | return this.trigger('update', this); 495 | }; 496 | 497 | _Message.prototype.scrollTo = function () { 498 | if (!this.options.scroll) { 499 | return; 500 | } 501 | return $.scrollTo(this.$el, { 502 | duration: 400, 503 | offset: { 504 | left: 0, 505 | top: -20 506 | } 507 | }); 508 | }; 509 | 510 | _Message.prototype.timeSinceUpdate = function () { 511 | if (this.lastUpdate) { 512 | return (new Date) - this.lastUpdate; 513 | } else { 514 | return null; 515 | } 516 | }; 517 | 518 | _Message.prototype.actionsToEvents = function () { 519 | var act, name, _ref2, _results, 520 | _this = this; 521 | _ref2 = this.options.actions; 522 | _results = []; 523 | for (name in _ref2) { 524 | act = _ref2[name]; 525 | _results.push(this.events["click [data-action=\"" + name + "\"] a"] = (function (act) { 526 | return function (e) { 527 | e.preventDefault(); 528 | e.stopPropagation(); 529 | _this.trigger("action:" + name, act, e); 530 | return act.action.call(_this, e, _this); 531 | }; 532 | })(act)); 533 | } 534 | return _results; 535 | }; 536 | 537 | _Message.prototype.checkClickable = function () { 538 | var evt, name, _ref2, _results; 539 | _ref2 = this.events; 540 | _results = []; 541 | for (name in _ref2) { 542 | evt = _ref2[name]; 543 | if (name === 'click') { 544 | _results.push(this.$message.addClass('messenger-clickable')); 545 | } else { 546 | _results.push(void 0); 547 | } 548 | } 549 | return _results; 550 | }; 551 | 552 | _Message.prototype.undelegateEvents = function () { 553 | var _ref2; 554 | _Message.__super__.undelegateEvents.apply(this, arguments); 555 | return (_ref2 = this.$message) != null ? _ref2.removeClass('messenger-clickable') : void 0; 556 | }; 557 | 558 | _Message.prototype.parseActions = function () { 559 | var act, actions, n_act, name, _ref2, _ref3; 560 | actions = []; 561 | _ref2 = this.options.actions; 562 | for (name in _ref2) { 563 | act = _ref2[name]; 564 | n_act = $.extend({}, act); 565 | n_act.name = name; 566 | if ((_ref3 = n_act.label) == null) { 567 | n_act.label = name; 568 | } 569 | actions.push(n_act); 570 | } 571 | return actions; 572 | }; 573 | 574 | _Message.prototype.template = function (opts) { 575 | var $action, $actions, $cancel, $link, $message, $text, action, _i, _len, _ref2, 576 | _this = this; 577 | $message = $("
"); 578 | if (opts.showCloseButton) { 579 | $cancel = $('