├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── dist ├── django-ajax-chat-0.1.tar.gz └── django-ajax-chat-0.2.tar.gz ├── djangoChat ├── __init__.py ├── admin.py ├── issues.txt ├── models.py ├── static │ └── djangoChat │ │ ├── app │ │ ├── build │ │ │ └── app.build.js │ │ └── scripts │ │ │ ├── channel.js │ │ │ ├── collections │ │ │ ├── messages.js │ │ │ └── users.js │ │ │ ├── main.js │ │ │ ├── models │ │ │ ├── message.js │ │ │ └── user.js │ │ │ ├── templates │ │ │ ├── message.tmpl │ │ │ └── user.tmpl │ │ │ ├── vendor │ │ │ ├── backbone-amd │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ └── backbone.js │ │ │ ├── jquery-legacy │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── jquery.js │ │ │ ├── jquery │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── jquery.js │ │ │ ├── requirejs-text │ │ │ │ ├── .bower.json │ │ │ │ └── text.js │ │ │ ├── requirejs │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── require.js │ │ │ └── underscore-amd │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ └── underscore.js │ │ │ └── views │ │ │ ├── addMessage.js │ │ │ ├── message.js │ │ │ ├── messages.js │ │ │ ├── user.js │ │ │ └── users.js │ │ ├── bower.json │ │ ├── css │ │ ├── main.css │ │ └── normalize.css │ │ ├── dist │ │ ├── build.txt │ │ ├── build │ │ │ └── app.build.js │ │ └── scripts │ │ │ ├── channel.js │ │ │ ├── collections │ │ │ ├── messages.js │ │ │ └── users.js │ │ │ ├── main.js │ │ │ ├── models │ │ │ ├── message.js │ │ │ └── user.js │ │ │ ├── templates │ │ │ ├── message.tmpl │ │ │ └── user.tmpl │ │ │ ├── vendor │ │ │ ├── backbone-amd │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ └── backbone.js │ │ │ ├── jquery-legacy │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── jquery.js │ │ │ ├── jquery │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── jquery.js │ │ │ ├── requirejs-text │ │ │ │ ├── .bower.json │ │ │ │ └── text.js │ │ │ ├── requirejs │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ └── require.js │ │ │ └── underscore-amd │ │ │ │ ├── .bower.json │ │ │ │ ├── .gitignore │ │ │ │ ├── .npmignore │ │ │ │ ├── .travis.yml │ │ │ │ └── underscore.js │ │ │ └── views │ │ │ ├── addMessage.js │ │ │ ├── message.js │ │ │ ├── messages.js │ │ │ ├── user.js │ │ │ └── users.js │ │ ├── less │ │ └── main.less │ │ ├── otherjs │ │ └── less.js │ │ └── todo.txt ├── templates │ └── djangoChat │ │ ├── base.html │ │ ├── index.html │ │ └── login.html ├── tests.py ├── urls.py └── views.py ├── django_ajax_chat.egg-info ├── PKG-INFO ├── SOURCES.txt ├── dependency_links.txt └── top_level.txt └── setup.py /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharan01/django-ajax-chat/1ad9575fb90bf100c35a205b21fe60922c026372/LICENSE.txt -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | recursive-include djangoChat/static * 4 | recursive-include djangoChat/templates * 5 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Django Chat 3 | ===== 4 | 5 | DjangoChat is a simple Django Chat app 6 | 7 | 8 | demo 9 | ---- 10 | http://www.sharan.co/chat/ 11 | 12 | Quick start 13 | ----------- 14 | 15 | 1. Add "djangoChat" to your INSTALLED_APPS setting like this:: 16 | 17 | INSTALLED_APPS = ( 18 | ... 19 | 'djangoChat', 20 | ) 21 | 22 | 2. Include the polls URLconf in your project urls.py :: 23 | 24 | url(r'^chat/', include('djangoChat.urls')), 25 | 26 | 3. Run `python manage.py syncdb` to create the djangoChat models. 27 | 28 | 4. Start the development server and visit http://127.0.0.1:8000/chat/ 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /dist/django-ajax-chat-0.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharan01/django-ajax-chat/1ad9575fb90bf100c35a205b21fe60922c026372/dist/django-ajax-chat-0.1.tar.gz -------------------------------------------------------------------------------- /dist/django-ajax-chat-0.2.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharan01/django-ajax-chat/1ad9575fb90bf100c35a205b21fe60922c026372/dist/django-ajax-chat-0.2.tar.gz -------------------------------------------------------------------------------- /djangoChat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sharan01/django-ajax-chat/1ad9575fb90bf100c35a205b21fe60922c026372/djangoChat/__init__.py -------------------------------------------------------------------------------- /djangoChat/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from djangoChat.models import Message 3 | 4 | 5 | admin.site.register(Message) 6 | # optional ordering -------------------------------------------------------------------------------- /djangoChat/issues.txt: -------------------------------------------------------------------------------- 1 | issues 2 | --------- 3 | avatars 4 | encode html for dangerous tags -------------------------------------------------------------------------------- /djangoChat/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from datetime import datetime 3 | from django.contrib.auth.signals import user_logged_in, user_logged_out 4 | from django.contrib.auth.models import User 5 | import urllib, hashlib, binascii 6 | 7 | class Message(models.Model): 8 | user = models.CharField(max_length=200) 9 | message = models.TextField(max_length=200) 10 | time = models.DateTimeField(auto_now_add=True) 11 | gravatar = models.CharField(max_length=300) 12 | def __unicode__(self): 13 | return self.user 14 | # def save(self): 15 | # if self.time == None: 16 | # self.time = datetime.now() 17 | # super(Message, self).save() 18 | 19 | 20 | 21 | 22 | def generate_avatar(email): 23 | a = "http://www.gravatar.com/avatar/" 24 | a+=hashlib.md5(email.lower()).hexdigest() 25 | a+='?d=identicon' 26 | return a 27 | def hash_username(username): 28 | a = binascii.crc32(username) 29 | return a 30 | class ChatUser(models.Model): 31 | user = models.OneToOneField(User) 32 | userID = models.IntegerField() 33 | username = models.CharField(max_length=300) 34 | is_chat_user = models.BooleanField(default=False) 35 | gravatar_url = models.CharField(max_length=300) 36 | last_accessed = models.DateTimeField(auto_now_add=True) 37 | 38 | User.profile = property(lambda u: ChatUser.objects.get_or_create(user=u,defaults={'gravatar_url':generate_avatar(u.email),'username':u.username,'userID':hash_username(u.username)})[0]) 39 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/build/app.build.js: -------------------------------------------------------------------------------- 1 | ({ 2 | appDir:"../", 3 | baseUrl:"scripts", 4 | dir:"../../dist", 5 | mainConfigFile:"../scripts/main.js", 6 | name:"main", 7 | optimizeCss:"standard" 8 | }) -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/channel.js: -------------------------------------------------------------------------------- 1 | define(['backbone'], function (Backbone) { 2 | var channel = _.extend({}, Backbone.Events); 3 | return channel; 4 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/collections/messages.js: -------------------------------------------------------------------------------- 1 | define(['backbone','models/message'],function(Backbone,MsgModel){ 2 | 3 | Messages = Backbone.Collection.extend({ 4 | model : MsgModel, 5 | url : '/chat/api/' 6 | }); 7 | 8 | return Messages; 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/collections/users.js: -------------------------------------------------------------------------------- 1 | define(['backbone','models/user'],function(Backbone,usrModel){ 2 | return Backbone.Collection.extend({ 3 | url:'/chat/api/users/', 4 | model:usrModel 5 | }); 6 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/main.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths:{ 3 | "jquery":"vendor/jquery/jquery", 4 | "underscore":"vendor/underscore-amd/underscore", 5 | "backbone":"vendor/backbone-amd/backbone", 6 | "text":"vendor/requirejs-text/text" 7 | }, 8 | urlArgs: "v=" + (new Date()).getTime() 9 | }); 10 | 11 | require(['views/messages','views/addMessage','collections/messages', ],function(MsgsView,AddMsg,MsgCollection){ 12 | 13 | msgCollec = new MsgCollection(jsonData); 14 | v = new MsgsView({collection:msgCollec}); 15 | 16 | a = new AddMsg(); 17 | }); 18 | 19 | require(['views/users','collections/users'],function(UsersView,UsrCollec){ 20 | usrCollec = new UsrCollec(); 21 | usersView = new UsersView({collection:usrCollec}); 22 | 23 | }); 24 | 25 | 26 | setInterval(function(){ 27 | msgCollec.fetch({update: true, remove: false}); 28 | },2000); 29 | setInterval(function(){ 30 | usrCollec.fetch({refresh:true}); 31 | console.log('users fetched'); 32 | },30000); 33 | 34 | 35 | 36 | require(['jquery'],function($){ 37 | 38 | setInterval(function(){ 39 | $.get( "/chat/api/users/update/", function( data ) { 40 | console.log("updated"); 41 | }); 42 | },30000); 43 | 44 | 45 | 46 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/models/message.js: -------------------------------------------------------------------------------- 1 | define(['backbone','jquery'],function(Backbone,$){ 2 | Message = Backbone.Model.extend({ 3 | 4 | validate: function(attr){ 5 | // temporary m so as to not modify attr.msg when jquery trim is called 6 | m = attr.msg; 7 | if($.trim(m) === ''){ 8 | return "empty messege"; 9 | } 10 | }, 11 | initialize: function(){ 12 | this.on('invalid',function(model,error){ 13 | console.log(error); 14 | }); 15 | } 16 | }); 17 | 18 | return Message; 19 | }); 20 | 21 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/models/user.js: -------------------------------------------------------------------------------- 1 | define(['backbone'],function(){ 2 | return Backbone.Model.extend({ 3 | 4 | }); 5 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/templates/message.tmpl: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%=user%> 4 |
5 |
<%=user%>
6 |

7 |
8 |
9 |
10 | <%=msg%> 11 | <%=time%> 12 |
13 |
14 |

-------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/templates/user.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | <%= username %> 6 |
7 |

-------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/backbone-amd/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backbone-amd", 3 | "homepage": "https://github.com/amdjs/backbone", 4 | "version": "1.0.0", 5 | "_release": "1.0.0", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "1.0.0", 9 | "commit": "df9a95275594eee98cd3d372464ee1467fdb7b1f" 10 | }, 11 | "_source": "git://github.com/amdjs/backbone.git", 12 | "_target": "*", 13 | "_originalSource": "backbone-amd" 14 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/backbone-amd/.gitignore: -------------------------------------------------------------------------------- 1 | raw 2 | *.sw? 3 | .DS_Store 4 | node_modules 5 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/backbone-amd/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | Rakefile 3 | docs/ 4 | raw/ 5 | examples/ 6 | index.html 7 | .jshintrc 8 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/backbone-amd/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/jquery-legacy/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "1.10.2", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "main": "jquery.js", 10 | "license": "MIT", 11 | "homepage": "https://github.com/components/jquery", 12 | "_release": "1.10.2", 13 | "_resolution": { 14 | "type": "version", 15 | "tag": "1.10.2", 16 | "commit": "6b2390db24ba3490ca75251eec4888f7342bf4da" 17 | }, 18 | "_source": "git://github.com/components/jquery.git", 19 | "_target": "1.10", 20 | "_originalSource": "jquery" 21 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/jquery-legacy/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.0.3", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "main": "jquery.js", 10 | "license": "MIT", 11 | "homepage": "https://github.com/components/jquery", 12 | "_release": "2.0.3", 13 | "_resolution": { 14 | "type": "version", 15 | "tag": "2.0.3", 16 | "commit": "452a56b52b8f4a032256cdb8b6838f25f0bdb3d2" 17 | }, 18 | "_source": "git://github.com/components/jquery.git", 19 | "_target": "*", 20 | "_originalSource": "jquery" 21 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/jquery/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/requirejs-text/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "requirejs-text", 3 | "homepage": "https://github.com/requirejs/text", 4 | "version": "2.0.10", 5 | "_release": "2.0.10", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "2.0.10", 9 | "commit": "1592cbf9c7ffd703b36a3af4002e86457b8ab5dd" 10 | }, 11 | "_source": "git://github.com/requirejs/text.git", 12 | "_target": "*", 13 | "_originalSource": "requirejs-text" 14 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/requirejs-text/text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/requirejs/text for details 5 | */ 6 | /*jslint regexp: true */ 7 | /*global require, XMLHttpRequest, ActiveXObject, 8 | define, window, process, Packages, 9 | java, location, Components, FileUtils */ 10 | 11 | define(['module'], function (module) { 12 | 'use strict'; 13 | 14 | var text, fs, Cc, Ci, xpcIsWindows, 15 | progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], 16 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, 17 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, 18 | hasLocation = typeof location !== 'undefined' && location.href, 19 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), 20 | defaultHostName = hasLocation && location.hostname, 21 | defaultPort = hasLocation && (location.port || undefined), 22 | buildMap = {}, 23 | masterConfig = (module.config && module.config()) || {}; 24 | 25 | text = { 26 | version: '2.0.10', 27 | 28 | strip: function (content) { 29 | //Strips declarations so that external SVG and XML 30 | //documents can be added to a document without worry. Also, if the string 31 | //is an HTML document, only the part inside the body tag is returned. 32 | if (content) { 33 | content = content.replace(xmlRegExp, ""); 34 | var matches = content.match(bodyRegExp); 35 | if (matches) { 36 | content = matches[1]; 37 | } 38 | } else { 39 | content = ""; 40 | } 41 | return content; 42 | }, 43 | 44 | jsEscape: function (content) { 45 | return content.replace(/(['\\])/g, '\\$1') 46 | .replace(/[\f]/g, "\\f") 47 | .replace(/[\b]/g, "\\b") 48 | .replace(/[\n]/g, "\\n") 49 | .replace(/[\t]/g, "\\t") 50 | .replace(/[\r]/g, "\\r") 51 | .replace(/[\u2028]/g, "\\u2028") 52 | .replace(/[\u2029]/g, "\\u2029"); 53 | }, 54 | 55 | createXhr: masterConfig.createXhr || function () { 56 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first. 57 | var xhr, i, progId; 58 | if (typeof XMLHttpRequest !== "undefined") { 59 | return new XMLHttpRequest(); 60 | } else if (typeof ActiveXObject !== "undefined") { 61 | for (i = 0; i < 3; i += 1) { 62 | progId = progIds[i]; 63 | try { 64 | xhr = new ActiveXObject(progId); 65 | } catch (e) {} 66 | 67 | if (xhr) { 68 | progIds = [progId]; // so faster next time 69 | break; 70 | } 71 | } 72 | } 73 | 74 | return xhr; 75 | }, 76 | 77 | /** 78 | * Parses a resource name into its component parts. Resource names 79 | * look like: module/name.ext!strip, where the !strip part is 80 | * optional. 81 | * @param {String} name the resource name 82 | * @returns {Object} with properties "moduleName", "ext" and "strip" 83 | * where strip is a boolean. 84 | */ 85 | parseName: function (name) { 86 | var modName, ext, temp, 87 | strip = false, 88 | index = name.indexOf("."), 89 | isRelative = name.indexOf('./') === 0 || 90 | name.indexOf('../') === 0; 91 | 92 | if (index !== -1 && (!isRelative || index > 1)) { 93 | modName = name.substring(0, index); 94 | ext = name.substring(index + 1, name.length); 95 | } else { 96 | modName = name; 97 | } 98 | 99 | temp = ext || modName; 100 | index = temp.indexOf("!"); 101 | if (index !== -1) { 102 | //Pull off the strip arg. 103 | strip = temp.substring(index + 1) === "strip"; 104 | temp = temp.substring(0, index); 105 | if (ext) { 106 | ext = temp; 107 | } else { 108 | modName = temp; 109 | } 110 | } 111 | 112 | return { 113 | moduleName: modName, 114 | ext: ext, 115 | strip: strip 116 | }; 117 | }, 118 | 119 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, 120 | 121 | /** 122 | * Is an URL on another domain. Only works for browser use, returns 123 | * false in non-browser environments. Only used to know if an 124 | * optimized .js version of a text resource should be loaded 125 | * instead. 126 | * @param {String} url 127 | * @returns Boolean 128 | */ 129 | useXhr: function (url, protocol, hostname, port) { 130 | var uProtocol, uHostName, uPort, 131 | match = text.xdRegExp.exec(url); 132 | if (!match) { 133 | return true; 134 | } 135 | uProtocol = match[2]; 136 | uHostName = match[3]; 137 | 138 | uHostName = uHostName.split(':'); 139 | uPort = uHostName[1]; 140 | uHostName = uHostName[0]; 141 | 142 | return (!uProtocol || uProtocol === protocol) && 143 | (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && 144 | ((!uPort && !uHostName) || uPort === port); 145 | }, 146 | 147 | finishLoad: function (name, strip, content, onLoad) { 148 | content = strip ? text.strip(content) : content; 149 | if (masterConfig.isBuild) { 150 | buildMap[name] = content; 151 | } 152 | onLoad(content); 153 | }, 154 | 155 | load: function (name, req, onLoad, config) { 156 | //Name has format: some.module.filext!strip 157 | //The strip part is optional. 158 | //if strip is present, then that means only get the string contents 159 | //inside a body tag in an HTML string. For XML/SVG content it means 160 | //removing the declarations so the content can be inserted 161 | //into the current doc without problems. 162 | 163 | // Do not bother with the work if a build and text will 164 | // not be inlined. 165 | if (config.isBuild && !config.inlineText) { 166 | onLoad(); 167 | return; 168 | } 169 | 170 | masterConfig.isBuild = config.isBuild; 171 | 172 | var parsed = text.parseName(name), 173 | nonStripName = parsed.moduleName + 174 | (parsed.ext ? '.' + parsed.ext : ''), 175 | url = req.toUrl(nonStripName), 176 | useXhr = (masterConfig.useXhr) || 177 | text.useXhr; 178 | 179 | // Do not load if it is an empty: url 180 | if (url.indexOf('empty:') === 0) { 181 | onLoad(); 182 | return; 183 | } 184 | 185 | //Load the text. Use XHR if possible and in a browser. 186 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { 187 | text.get(url, function (content) { 188 | text.finishLoad(name, parsed.strip, content, onLoad); 189 | }, function (err) { 190 | if (onLoad.error) { 191 | onLoad.error(err); 192 | } 193 | }); 194 | } else { 195 | //Need to fetch the resource across domains. Assume 196 | //the resource has been optimized into a JS module. Fetch 197 | //by the module name + extension, but do not include the 198 | //!strip part to avoid file system issues. 199 | req([nonStripName], function (content) { 200 | text.finishLoad(parsed.moduleName + '.' + parsed.ext, 201 | parsed.strip, content, onLoad); 202 | }); 203 | } 204 | }, 205 | 206 | write: function (pluginName, moduleName, write, config) { 207 | if (buildMap.hasOwnProperty(moduleName)) { 208 | var content = text.jsEscape(buildMap[moduleName]); 209 | write.asModule(pluginName + "!" + moduleName, 210 | "define(function () { return '" + 211 | content + 212 | "';});\n"); 213 | } 214 | }, 215 | 216 | writeFile: function (pluginName, moduleName, req, write, config) { 217 | var parsed = text.parseName(moduleName), 218 | extPart = parsed.ext ? '.' + parsed.ext : '', 219 | nonStripName = parsed.moduleName + extPart, 220 | //Use a '.js' file name so that it indicates it is a 221 | //script that can be loaded across domains. 222 | fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; 223 | 224 | //Leverage own load() method to load plugin value, but only 225 | //write out values that do not have the strip argument, 226 | //to avoid any potential issues with ! in file names. 227 | text.load(nonStripName, req, function (value) { 228 | //Use own write() method to construct full module value. 229 | //But need to create shell that translates writeFile's 230 | //write() to the right interface. 231 | var textWrite = function (contents) { 232 | return write(fileName, contents); 233 | }; 234 | textWrite.asModule = function (moduleName, contents) { 235 | return write.asModule(moduleName, fileName, contents); 236 | }; 237 | 238 | text.write(pluginName, nonStripName, textWrite, config); 239 | }, config); 240 | } 241 | }; 242 | 243 | if (masterConfig.env === 'node' || (!masterConfig.env && 244 | typeof process !== "undefined" && 245 | process.versions && 246 | !!process.versions.node && 247 | !process.versions['node-webkit'])) { 248 | //Using special require.nodeRequire, something added by r.js. 249 | fs = require.nodeRequire('fs'); 250 | 251 | text.get = function (url, callback, errback) { 252 | try { 253 | var file = fs.readFileSync(url, 'utf8'); 254 | //Remove BOM (Byte Mark Order) from utf8 files if it is there. 255 | if (file.indexOf('\uFEFF') === 0) { 256 | file = file.substring(1); 257 | } 258 | callback(file); 259 | } catch (e) { 260 | errback(e); 261 | } 262 | }; 263 | } else if (masterConfig.env === 'xhr' || (!masterConfig.env && 264 | text.createXhr())) { 265 | text.get = function (url, callback, errback, headers) { 266 | var xhr = text.createXhr(), header; 267 | xhr.open('GET', url, true); 268 | 269 | //Allow plugins direct access to xhr headers 270 | if (headers) { 271 | for (header in headers) { 272 | if (headers.hasOwnProperty(header)) { 273 | xhr.setRequestHeader(header.toLowerCase(), headers[header]); 274 | } 275 | } 276 | } 277 | 278 | //Allow overrides specified in config 279 | if (masterConfig.onXhr) { 280 | masterConfig.onXhr(xhr, url); 281 | } 282 | 283 | xhr.onreadystatechange = function (evt) { 284 | var status, err; 285 | //Do not explicitly handle errors, those should be 286 | //visible via console output in the browser. 287 | if (xhr.readyState === 4) { 288 | status = xhr.status; 289 | if (status > 399 && status < 600) { 290 | //An http 4xx or 5xx error. Signal an error. 291 | err = new Error(url + ' HTTP status: ' + status); 292 | err.xhr = xhr; 293 | errback(err); 294 | } else { 295 | callback(xhr.responseText); 296 | } 297 | 298 | if (masterConfig.onXhrComplete) { 299 | masterConfig.onXhrComplete(xhr, url); 300 | } 301 | } 302 | }; 303 | xhr.send(null); 304 | }; 305 | } else if (masterConfig.env === 'rhino' || (!masterConfig.env && 306 | typeof Packages !== 'undefined' && typeof java !== 'undefined')) { 307 | //Why Java, why is this so awkward? 308 | text.get = function (url, callback) { 309 | var stringBuffer, line, 310 | encoding = "utf-8", 311 | file = new java.io.File(url), 312 | lineSeparator = java.lang.System.getProperty("line.separator"), 313 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), 314 | content = ''; 315 | try { 316 | stringBuffer = new java.lang.StringBuffer(); 317 | line = input.readLine(); 318 | 319 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 320 | // http://www.unicode.org/faq/utf_bom.html 321 | 322 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: 323 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 324 | if (line && line.length() && line.charAt(0) === 0xfeff) { 325 | // Eat the BOM, since we've already found the encoding on this file, 326 | // and we plan to concatenating this buffer with others; the BOM should 327 | // only appear at the top of a file. 328 | line = line.substring(1); 329 | } 330 | 331 | if (line !== null) { 332 | stringBuffer.append(line); 333 | } 334 | 335 | while ((line = input.readLine()) !== null) { 336 | stringBuffer.append(lineSeparator); 337 | stringBuffer.append(line); 338 | } 339 | //Make sure we return a JavaScript string and not a Java string. 340 | content = String(stringBuffer.toString()); //String 341 | } finally { 342 | input.close(); 343 | } 344 | callback(content); 345 | }; 346 | } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && 347 | typeof Components !== 'undefined' && Components.classes && 348 | Components.interfaces)) { 349 | //Avert your gaze! 350 | Cc = Components.classes, 351 | Ci = Components.interfaces; 352 | Components.utils['import']('resource://gre/modules/FileUtils.jsm'); 353 | xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); 354 | 355 | text.get = function (url, callback) { 356 | var inStream, convertStream, fileObj, 357 | readData = {}; 358 | 359 | if (xpcIsWindows) { 360 | url = url.replace(/\//g, '\\'); 361 | } 362 | 363 | fileObj = new FileUtils.File(url); 364 | 365 | //XPCOM, you so crazy 366 | try { 367 | inStream = Cc['@mozilla.org/network/file-input-stream;1'] 368 | .createInstance(Ci.nsIFileInputStream); 369 | inStream.init(fileObj, 1, 0, false); 370 | 371 | convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] 372 | .createInstance(Ci.nsIConverterInputStream); 373 | convertStream.init(inStream, "utf-8", inStream.available(), 374 | Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 375 | 376 | convertStream.readString(inStream.available(), readData); 377 | convertStream.close(); 378 | inStream.close(); 379 | callback(readData.value); 380 | } catch (e) { 381 | throw new Error((fileObj && fileObj.path || '') + ': ' + e); 382 | } 383 | }; 384 | } 385 | return text; 386 | }); 387 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/requirejs/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "requirejs", 3 | "homepage": "https://github.com/jrburke/requirejs", 4 | "version": "2.1.8", 5 | "_release": "2.1.8", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "2.1.8", 9 | "commit": "2b083dbb358e8c1876b059434d4b571d8f87534a" 10 | }, 11 | "_source": "git://github.com/jrburke/requirejs.git", 12 | "_target": "*", 13 | "_originalSource": "requirejs" 14 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/requirejs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | docs/jquery-require-sample/webapp-build/ 3 | docs/jquery-require-sample/dist 4 | dist/dist-site/ 5 | dist/dist-build/ 6 | shrinktest.sh 7 | tests/layers/allplugins-require.js 8 | tests/packages/optimizing/built/ 9 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/underscore-amd/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "underscore-amd", 3 | "homepage": "https://github.com/amdjs/underscore", 4 | "version": "1.5.1", 5 | "_release": "1.5.1", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "1.5.1", 9 | "commit": "569cb933afaf17d1a0874a62fb4b47fc793e824a" 10 | }, 11 | "_source": "git://github.com/amdjs/underscore.git", 12 | "_target": "*", 13 | "_originalSource": "underscore-amd" 14 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/underscore-amd/.gitignore: -------------------------------------------------------------------------------- 1 | raw 2 | node_modules 3 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/underscore-amd/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | Rakefile 3 | docs/ 4 | raw/ 5 | index.html 6 | underscore-min.js 7 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/underscore-amd/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/vendor/underscore-amd/underscore.js: -------------------------------------------------------------------------------- 1 | // Underscore.js 1.5.1 2 | // http://underscorejs.org 3 | // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors 4 | // Underscore may be freely distributed under the MIT license. 5 | 6 | (function() { 7 | 8 | // Baseline setup 9 | // -------------- 10 | 11 | // Establish the root object, `window` in the browser, or `global` on the server. 12 | var root = this; 13 | 14 | // Save the previous value of the `_` variable. 15 | var previousUnderscore = root._; 16 | 17 | // Establish the object that gets returned to break out of a loop iteration. 18 | var breaker = {}; 19 | 20 | // Save bytes in the minified (but not gzipped) version: 21 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; 22 | 23 | // Create quick reference variables for speed access to core prototypes. 24 | var 25 | push = ArrayProto.push, 26 | slice = ArrayProto.slice, 27 | concat = ArrayProto.concat, 28 | toString = ObjProto.toString, 29 | hasOwnProperty = ObjProto.hasOwnProperty; 30 | 31 | // All **ECMAScript 5** native function implementations that we hope to use 32 | // are declared here. 33 | var 34 | nativeForEach = ArrayProto.forEach, 35 | nativeMap = ArrayProto.map, 36 | nativeReduce = ArrayProto.reduce, 37 | nativeReduceRight = ArrayProto.reduceRight, 38 | nativeFilter = ArrayProto.filter, 39 | nativeEvery = ArrayProto.every, 40 | nativeSome = ArrayProto.some, 41 | nativeIndexOf = ArrayProto.indexOf, 42 | nativeLastIndexOf = ArrayProto.lastIndexOf, 43 | nativeIsArray = Array.isArray, 44 | nativeKeys = Object.keys, 45 | nativeBind = FuncProto.bind; 46 | 47 | // Create a safe reference to the Underscore object for use below. 48 | var _ = function(obj) { 49 | if (obj instanceof _) return obj; 50 | if (!(this instanceof _)) return new _(obj); 51 | this._wrapped = obj; 52 | }; 53 | 54 | // Export the Underscore object for **Node.js**, with 55 | // backwards-compatibility for the old `require()` API. If we're in 56 | // the browser, add `_` as a global object via a string identifier, 57 | // for Closure Compiler "advanced" mode. 58 | if (typeof exports !== 'undefined') { 59 | if (typeof module !== 'undefined' && module.exports) { 60 | exports = module.exports = _; 61 | } 62 | exports._ = _; 63 | } else { 64 | root._ = _; 65 | } 66 | 67 | // Current version. 68 | _.VERSION = '1.5.1'; 69 | 70 | // Collection Functions 71 | // -------------------- 72 | 73 | // The cornerstone, an `each` implementation, aka `forEach`. 74 | // Handles objects with the built-in `forEach`, arrays, and raw objects. 75 | // Delegates to **ECMAScript 5**'s native `forEach` if available. 76 | var each = _.each = _.forEach = function(obj, iterator, context) { 77 | if (obj == null) return; 78 | if (nativeForEach && obj.forEach === nativeForEach) { 79 | obj.forEach(iterator, context); 80 | } else if (obj.length === +obj.length) { 81 | for (var i = 0, l = obj.length; i < l; i++) { 82 | if (iterator.call(context, obj[i], i, obj) === breaker) return; 83 | } 84 | } else { 85 | for (var key in obj) { 86 | if (_.has(obj, key)) { 87 | if (iterator.call(context, obj[key], key, obj) === breaker) return; 88 | } 89 | } 90 | } 91 | }; 92 | 93 | // Return the results of applying the iterator to each element. 94 | // Delegates to **ECMAScript 5**'s native `map` if available. 95 | _.map = _.collect = function(obj, iterator, context) { 96 | var results = []; 97 | if (obj == null) return results; 98 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); 99 | each(obj, function(value, index, list) { 100 | results.push(iterator.call(context, value, index, list)); 101 | }); 102 | return results; 103 | }; 104 | 105 | var reduceError = 'Reduce of empty array with no initial value'; 106 | 107 | // **Reduce** builds up a single result from a list of values, aka `inject`, 108 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. 109 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { 110 | var initial = arguments.length > 2; 111 | if (obj == null) obj = []; 112 | if (nativeReduce && obj.reduce === nativeReduce) { 113 | if (context) iterator = _.bind(iterator, context); 114 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); 115 | } 116 | each(obj, function(value, index, list) { 117 | if (!initial) { 118 | memo = value; 119 | initial = true; 120 | } else { 121 | memo = iterator.call(context, memo, value, index, list); 122 | } 123 | }); 124 | if (!initial) throw new TypeError(reduceError); 125 | return memo; 126 | }; 127 | 128 | // The right-associative version of reduce, also known as `foldr`. 129 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available. 130 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) { 131 | var initial = arguments.length > 2; 132 | if (obj == null) obj = []; 133 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { 134 | if (context) iterator = _.bind(iterator, context); 135 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); 136 | } 137 | var length = obj.length; 138 | if (length !== +length) { 139 | var keys = _.keys(obj); 140 | length = keys.length; 141 | } 142 | each(obj, function(value, index, list) { 143 | index = keys ? keys[--length] : --length; 144 | if (!initial) { 145 | memo = obj[index]; 146 | initial = true; 147 | } else { 148 | memo = iterator.call(context, memo, obj[index], index, list); 149 | } 150 | }); 151 | if (!initial) throw new TypeError(reduceError); 152 | return memo; 153 | }; 154 | 155 | // Return the first value which passes a truth test. Aliased as `detect`. 156 | _.find = _.detect = function(obj, iterator, context) { 157 | var result; 158 | any(obj, function(value, index, list) { 159 | if (iterator.call(context, value, index, list)) { 160 | result = value; 161 | return true; 162 | } 163 | }); 164 | return result; 165 | }; 166 | 167 | // Return all the elements that pass a truth test. 168 | // Delegates to **ECMAScript 5**'s native `filter` if available. 169 | // Aliased as `select`. 170 | _.filter = _.select = function(obj, iterator, context) { 171 | var results = []; 172 | if (obj == null) return results; 173 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); 174 | each(obj, function(value, index, list) { 175 | if (iterator.call(context, value, index, list)) results.push(value); 176 | }); 177 | return results; 178 | }; 179 | 180 | // Return all the elements for which a truth test fails. 181 | _.reject = function(obj, iterator, context) { 182 | return _.filter(obj, function(value, index, list) { 183 | return !iterator.call(context, value, index, list); 184 | }, context); 185 | }; 186 | 187 | // Determine whether all of the elements match a truth test. 188 | // Delegates to **ECMAScript 5**'s native `every` if available. 189 | // Aliased as `all`. 190 | _.every = _.all = function(obj, iterator, context) { 191 | iterator || (iterator = _.identity); 192 | var result = true; 193 | if (obj == null) return result; 194 | if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 195 | each(obj, function(value, index, list) { 196 | if (!(result = result && iterator.call(context, value, index, list))) return breaker; 197 | }); 198 | return !!result; 199 | }; 200 | 201 | // Determine if at least one element in the object matches a truth test. 202 | // Delegates to **ECMAScript 5**'s native `some` if available. 203 | // Aliased as `any`. 204 | var any = _.some = _.any = function(obj, iterator, context) { 205 | iterator || (iterator = _.identity); 206 | var result = false; 207 | if (obj == null) return result; 208 | if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); 209 | each(obj, function(value, index, list) { 210 | if (result || (result = iterator.call(context, value, index, list))) return breaker; 211 | }); 212 | return !!result; 213 | }; 214 | 215 | // Determine if the array or object contains a given value (using `===`). 216 | // Aliased as `include`. 217 | _.contains = _.include = function(obj, target) { 218 | if (obj == null) return false; 219 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; 220 | return any(obj, function(value) { 221 | return value === target; 222 | }); 223 | }; 224 | 225 | // Invoke a method (with arguments) on every item in a collection. 226 | _.invoke = function(obj, method) { 227 | var args = slice.call(arguments, 2); 228 | var isFunc = _.isFunction(method); 229 | return _.map(obj, function(value) { 230 | return (isFunc ? method : value[method]).apply(value, args); 231 | }); 232 | }; 233 | 234 | // Convenience version of a common use case of `map`: fetching a property. 235 | _.pluck = function(obj, key) { 236 | return _.map(obj, function(value){ return value[key]; }); 237 | }; 238 | 239 | // Convenience version of a common use case of `filter`: selecting only objects 240 | // containing specific `key:value` pairs. 241 | _.where = function(obj, attrs, first) { 242 | if (_.isEmpty(attrs)) return first ? void 0 : []; 243 | return _[first ? 'find' : 'filter'](obj, function(value) { 244 | for (var key in attrs) { 245 | if (attrs[key] !== value[key]) return false; 246 | } 247 | return true; 248 | }); 249 | }; 250 | 251 | // Convenience version of a common use case of `find`: getting the first object 252 | // containing specific `key:value` pairs. 253 | _.findWhere = function(obj, attrs) { 254 | return _.where(obj, attrs, true); 255 | }; 256 | 257 | // Return the maximum element or (element-based computation). 258 | // Can't optimize arrays of integers longer than 65,535 elements. 259 | // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) 260 | _.max = function(obj, iterator, context) { 261 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 262 | return Math.max.apply(Math, obj); 263 | } 264 | if (!iterator && _.isEmpty(obj)) return -Infinity; 265 | var result = {computed : -Infinity, value: -Infinity}; 266 | each(obj, function(value, index, list) { 267 | var computed = iterator ? iterator.call(context, value, index, list) : value; 268 | computed > result.computed && (result = {value : value, computed : computed}); 269 | }); 270 | return result.value; 271 | }; 272 | 273 | // Return the minimum element (or element-based computation). 274 | _.min = function(obj, iterator, context) { 275 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { 276 | return Math.min.apply(Math, obj); 277 | } 278 | if (!iterator && _.isEmpty(obj)) return Infinity; 279 | var result = {computed : Infinity, value: Infinity}; 280 | each(obj, function(value, index, list) { 281 | var computed = iterator ? iterator.call(context, value, index, list) : value; 282 | computed < result.computed && (result = {value : value, computed : computed}); 283 | }); 284 | return result.value; 285 | }; 286 | 287 | // Shuffle an array. 288 | _.shuffle = function(obj) { 289 | var rand; 290 | var index = 0; 291 | var shuffled = []; 292 | each(obj, function(value) { 293 | rand = _.random(index++); 294 | shuffled[index - 1] = shuffled[rand]; 295 | shuffled[rand] = value; 296 | }); 297 | return shuffled; 298 | }; 299 | 300 | // An internal function to generate lookup iterators. 301 | var lookupIterator = function(value) { 302 | return _.isFunction(value) ? value : function(obj){ return obj[value]; }; 303 | }; 304 | 305 | // Sort the object's values by a criterion produced by an iterator. 306 | _.sortBy = function(obj, value, context) { 307 | var iterator = lookupIterator(value); 308 | return _.pluck(_.map(obj, function(value, index, list) { 309 | return { 310 | value : value, 311 | index : index, 312 | criteria : iterator.call(context, value, index, list) 313 | }; 314 | }).sort(function(left, right) { 315 | var a = left.criteria; 316 | var b = right.criteria; 317 | if (a !== b) { 318 | if (a > b || a === void 0) return 1; 319 | if (a < b || b === void 0) return -1; 320 | } 321 | return left.index < right.index ? -1 : 1; 322 | }), 'value'); 323 | }; 324 | 325 | // An internal function used for aggregate "group by" operations. 326 | var group = function(obj, value, context, behavior) { 327 | var result = {}; 328 | var iterator = lookupIterator(value == null ? _.identity : value); 329 | each(obj, function(value, index) { 330 | var key = iterator.call(context, value, index, obj); 331 | behavior(result, key, value); 332 | }); 333 | return result; 334 | }; 335 | 336 | // Groups the object's values by a criterion. Pass either a string attribute 337 | // to group by, or a function that returns the criterion. 338 | _.groupBy = function(obj, value, context) { 339 | return group(obj, value, context, function(result, key, value) { 340 | (_.has(result, key) ? result[key] : (result[key] = [])).push(value); 341 | }); 342 | }; 343 | 344 | // Counts instances of an object that group by a certain criterion. Pass 345 | // either a string attribute to count by, or a function that returns the 346 | // criterion. 347 | _.countBy = function(obj, value, context) { 348 | return group(obj, value, context, function(result, key) { 349 | if (!_.has(result, key)) result[key] = 0; 350 | result[key]++; 351 | }); 352 | }; 353 | 354 | // Use a comparator function to figure out the smallest index at which 355 | // an object should be inserted so as to maintain order. Uses binary search. 356 | _.sortedIndex = function(array, obj, iterator, context) { 357 | iterator = iterator == null ? _.identity : lookupIterator(iterator); 358 | var value = iterator.call(context, obj); 359 | var low = 0, high = array.length; 360 | while (low < high) { 361 | var mid = (low + high) >>> 1; 362 | iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; 363 | } 364 | return low; 365 | }; 366 | 367 | // Safely create a real, live array from anything iterable. 368 | _.toArray = function(obj) { 369 | if (!obj) return []; 370 | if (_.isArray(obj)) return slice.call(obj); 371 | if (obj.length === +obj.length) return _.map(obj, _.identity); 372 | return _.values(obj); 373 | }; 374 | 375 | // Return the number of elements in an object. 376 | _.size = function(obj) { 377 | if (obj == null) return 0; 378 | return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; 379 | }; 380 | 381 | // Array Functions 382 | // --------------- 383 | 384 | // Get the first element of an array. Passing **n** will return the first N 385 | // values in the array. Aliased as `head` and `take`. The **guard** check 386 | // allows it to work with `_.map`. 387 | _.first = _.head = _.take = function(array, n, guard) { 388 | if (array == null) return void 0; 389 | return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; 390 | }; 391 | 392 | // Returns everything but the last entry of the array. Especially useful on 393 | // the arguments object. Passing **n** will return all the values in 394 | // the array, excluding the last N. The **guard** check allows it to work with 395 | // `_.map`. 396 | _.initial = function(array, n, guard) { 397 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); 398 | }; 399 | 400 | // Get the last element of an array. Passing **n** will return the last N 401 | // values in the array. The **guard** check allows it to work with `_.map`. 402 | _.last = function(array, n, guard) { 403 | if (array == null) return void 0; 404 | if ((n != null) && !guard) { 405 | return slice.call(array, Math.max(array.length - n, 0)); 406 | } else { 407 | return array[array.length - 1]; 408 | } 409 | }; 410 | 411 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. 412 | // Especially useful on the arguments object. Passing an **n** will return 413 | // the rest N values in the array. The **guard** 414 | // check allows it to work with `_.map`. 415 | _.rest = _.tail = _.drop = function(array, n, guard) { 416 | return slice.call(array, (n == null) || guard ? 1 : n); 417 | }; 418 | 419 | // Trim out all falsy values from an array. 420 | _.compact = function(array) { 421 | return _.filter(array, _.identity); 422 | }; 423 | 424 | // Internal implementation of a recursive `flatten` function. 425 | var flatten = function(input, shallow, output) { 426 | if (shallow && _.every(input, _.isArray)) { 427 | return concat.apply(output, input); 428 | } 429 | each(input, function(value) { 430 | if (_.isArray(value) || _.isArguments(value)) { 431 | shallow ? push.apply(output, value) : flatten(value, shallow, output); 432 | } else { 433 | output.push(value); 434 | } 435 | }); 436 | return output; 437 | }; 438 | 439 | // Return a completely flattened version of an array. 440 | _.flatten = function(array, shallow) { 441 | return flatten(array, shallow, []); 442 | }; 443 | 444 | // Return a version of the array that does not contain the specified value(s). 445 | _.without = function(array) { 446 | return _.difference(array, slice.call(arguments, 1)); 447 | }; 448 | 449 | // Produce a duplicate-free version of the array. If the array has already 450 | // been sorted, you have the option of using a faster algorithm. 451 | // Aliased as `unique`. 452 | _.uniq = _.unique = function(array, isSorted, iterator, context) { 453 | if (_.isFunction(isSorted)) { 454 | context = iterator; 455 | iterator = isSorted; 456 | isSorted = false; 457 | } 458 | var initial = iterator ? _.map(array, iterator, context) : array; 459 | var results = []; 460 | var seen = []; 461 | each(initial, function(value, index) { 462 | if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { 463 | seen.push(value); 464 | results.push(array[index]); 465 | } 466 | }); 467 | return results; 468 | }; 469 | 470 | // Produce an array that contains the union: each distinct element from all of 471 | // the passed-in arrays. 472 | _.union = function() { 473 | return _.uniq(_.flatten(arguments, true)); 474 | }; 475 | 476 | // Produce an array that contains every item shared between all the 477 | // passed-in arrays. 478 | _.intersection = function(array) { 479 | var rest = slice.call(arguments, 1); 480 | return _.filter(_.uniq(array), function(item) { 481 | return _.every(rest, function(other) { 482 | return _.indexOf(other, item) >= 0; 483 | }); 484 | }); 485 | }; 486 | 487 | // Take the difference between one array and a number of other arrays. 488 | // Only the elements present in just the first array will remain. 489 | _.difference = function(array) { 490 | var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); 491 | return _.filter(array, function(value){ return !_.contains(rest, value); }); 492 | }; 493 | 494 | // Zip together multiple lists into a single array -- elements that share 495 | // an index go together. 496 | _.zip = function() { 497 | var length = _.max(_.pluck(arguments, "length").concat(0)); 498 | var results = new Array(length); 499 | for (var i = 0; i < length; i++) { 500 | results[i] = _.pluck(arguments, '' + i); 501 | } 502 | return results; 503 | }; 504 | 505 | // Converts lists into objects. Pass either a single array of `[key, value]` 506 | // pairs, or two parallel arrays of the same length -- one of keys, and one of 507 | // the corresponding values. 508 | _.object = function(list, values) { 509 | if (list == null) return {}; 510 | var result = {}; 511 | for (var i = 0, l = list.length; i < l; i++) { 512 | if (values) { 513 | result[list[i]] = values[i]; 514 | } else { 515 | result[list[i][0]] = list[i][1]; 516 | } 517 | } 518 | return result; 519 | }; 520 | 521 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), 522 | // we need this function. Return the position of the first occurrence of an 523 | // item in an array, or -1 if the item is not included in the array. 524 | // Delegates to **ECMAScript 5**'s native `indexOf` if available. 525 | // If the array is large and already in sort order, pass `true` 526 | // for **isSorted** to use binary search. 527 | _.indexOf = function(array, item, isSorted) { 528 | if (array == null) return -1; 529 | var i = 0, l = array.length; 530 | if (isSorted) { 531 | if (typeof isSorted == 'number') { 532 | i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); 533 | } else { 534 | i = _.sortedIndex(array, item); 535 | return array[i] === item ? i : -1; 536 | } 537 | } 538 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); 539 | for (; i < l; i++) if (array[i] === item) return i; 540 | return -1; 541 | }; 542 | 543 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. 544 | _.lastIndexOf = function(array, item, from) { 545 | if (array == null) return -1; 546 | var hasIndex = from != null; 547 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { 548 | return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); 549 | } 550 | var i = (hasIndex ? from : array.length); 551 | while (i--) if (array[i] === item) return i; 552 | return -1; 553 | }; 554 | 555 | // Generate an integer Array containing an arithmetic progression. A port of 556 | // the native Python `range()` function. See 557 | // [the Python documentation](http://docs.python.org/library/functions.html#range). 558 | _.range = function(start, stop, step) { 559 | if (arguments.length <= 1) { 560 | stop = start || 0; 561 | start = 0; 562 | } 563 | step = arguments[2] || 1; 564 | 565 | var len = Math.max(Math.ceil((stop - start) / step), 0); 566 | var idx = 0; 567 | var range = new Array(len); 568 | 569 | while(idx < len) { 570 | range[idx++] = start; 571 | start += step; 572 | } 573 | 574 | return range; 575 | }; 576 | 577 | // Function (ahem) Functions 578 | // ------------------ 579 | 580 | // Reusable constructor function for prototype setting. 581 | var ctor = function(){}; 582 | 583 | // Create a function bound to a given object (assigning `this`, and arguments, 584 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if 585 | // available. 586 | _.bind = function(func, context) { 587 | var args, bound; 588 | if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); 589 | if (!_.isFunction(func)) throw new TypeError; 590 | args = slice.call(arguments, 2); 591 | return bound = function() { 592 | if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); 593 | ctor.prototype = func.prototype; 594 | var self = new ctor; 595 | ctor.prototype = null; 596 | var result = func.apply(self, args.concat(slice.call(arguments))); 597 | if (Object(result) === result) return result; 598 | return self; 599 | }; 600 | }; 601 | 602 | // Partially apply a function by creating a version that has had some of its 603 | // arguments pre-filled, without changing its dynamic `this` context. 604 | _.partial = function(func) { 605 | var args = slice.call(arguments, 1); 606 | return function() { 607 | return func.apply(this, args.concat(slice.call(arguments))); 608 | }; 609 | }; 610 | 611 | // Bind all of an object's methods to that object. Useful for ensuring that 612 | // all callbacks defined on an object belong to it. 613 | _.bindAll = function(obj) { 614 | var funcs = slice.call(arguments, 1); 615 | if (funcs.length === 0) throw new Error("bindAll must be passed function names"); 616 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); 617 | return obj; 618 | }; 619 | 620 | // Memoize an expensive function by storing its results. 621 | _.memoize = function(func, hasher) { 622 | var memo = {}; 623 | hasher || (hasher = _.identity); 624 | return function() { 625 | var key = hasher.apply(this, arguments); 626 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); 627 | }; 628 | }; 629 | 630 | // Delays a function for the given number of milliseconds, and then calls 631 | // it with the arguments supplied. 632 | _.delay = function(func, wait) { 633 | var args = slice.call(arguments, 2); 634 | return setTimeout(function(){ return func.apply(null, args); }, wait); 635 | }; 636 | 637 | // Defers a function, scheduling it to run after the current call stack has 638 | // cleared. 639 | _.defer = function(func) { 640 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); 641 | }; 642 | 643 | // Returns a function, that, when invoked, will only be triggered at most once 644 | // during a given window of time. Normally, the throttled function will run 645 | // as much as it can, without ever going more than once per `wait` duration; 646 | // but if you'd like to disable the execution on the leading edge, pass 647 | // `{leading: false}`. To disable execution on the trailing edge, ditto. 648 | _.throttle = function(func, wait, options) { 649 | var context, args, result; 650 | var timeout = null; 651 | var previous = 0; 652 | options || (options = {}); 653 | var later = function() { 654 | previous = options.leading === false ? 0 : new Date; 655 | timeout = null; 656 | result = func.apply(context, args); 657 | }; 658 | return function() { 659 | var now = new Date; 660 | if (!previous && options.leading === false) previous = now; 661 | var remaining = wait - (now - previous); 662 | context = this; 663 | args = arguments; 664 | if (remaining <= 0) { 665 | clearTimeout(timeout); 666 | timeout = null; 667 | previous = now; 668 | result = func.apply(context, args); 669 | } else if (!timeout && options.trailing !== false) { 670 | timeout = setTimeout(later, remaining); 671 | } 672 | return result; 673 | }; 674 | }; 675 | 676 | // Returns a function, that, as long as it continues to be invoked, will not 677 | // be triggered. The function will be called after it stops being called for 678 | // N milliseconds. If `immediate` is passed, trigger the function on the 679 | // leading edge, instead of the trailing. 680 | _.debounce = function(func, wait, immediate) { 681 | var result; 682 | var timeout = null; 683 | return function() { 684 | var context = this, args = arguments; 685 | var later = function() { 686 | timeout = null; 687 | if (!immediate) result = func.apply(context, args); 688 | }; 689 | var callNow = immediate && !timeout; 690 | clearTimeout(timeout); 691 | timeout = setTimeout(later, wait); 692 | if (callNow) result = func.apply(context, args); 693 | return result; 694 | }; 695 | }; 696 | 697 | // Returns a function that will be executed at most one time, no matter how 698 | // often you call it. Useful for lazy initialization. 699 | _.once = function(func) { 700 | var ran = false, memo; 701 | return function() { 702 | if (ran) return memo; 703 | ran = true; 704 | memo = func.apply(this, arguments); 705 | func = null; 706 | return memo; 707 | }; 708 | }; 709 | 710 | // Returns the first function passed as an argument to the second, 711 | // allowing you to adjust arguments, run code before and after, and 712 | // conditionally execute the original function. 713 | _.wrap = function(func, wrapper) { 714 | return function() { 715 | var args = [func]; 716 | push.apply(args, arguments); 717 | return wrapper.apply(this, args); 718 | }; 719 | }; 720 | 721 | // Returns a function that is the composition of a list of functions, each 722 | // consuming the return value of the function that follows. 723 | _.compose = function() { 724 | var funcs = arguments; 725 | return function() { 726 | var args = arguments; 727 | for (var i = funcs.length - 1; i >= 0; i--) { 728 | args = [funcs[i].apply(this, args)]; 729 | } 730 | return args[0]; 731 | }; 732 | }; 733 | 734 | // Returns a function that will only be executed after being called N times. 735 | _.after = function(times, func) { 736 | return function() { 737 | if (--times < 1) { 738 | return func.apply(this, arguments); 739 | } 740 | }; 741 | }; 742 | 743 | // Object Functions 744 | // ---------------- 745 | 746 | // Retrieve the names of an object's properties. 747 | // Delegates to **ECMAScript 5**'s native `Object.keys` 748 | _.keys = nativeKeys || function(obj) { 749 | if (obj !== Object(obj)) throw new TypeError('Invalid object'); 750 | var keys = []; 751 | for (var key in obj) if (_.has(obj, key)) keys.push(key); 752 | return keys; 753 | }; 754 | 755 | // Retrieve the values of an object's properties. 756 | _.values = function(obj) { 757 | var values = []; 758 | for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); 759 | return values; 760 | }; 761 | 762 | // Convert an object into a list of `[key, value]` pairs. 763 | _.pairs = function(obj) { 764 | var pairs = []; 765 | for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); 766 | return pairs; 767 | }; 768 | 769 | // Invert the keys and values of an object. The values must be serializable. 770 | _.invert = function(obj) { 771 | var result = {}; 772 | for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; 773 | return result; 774 | }; 775 | 776 | // Return a sorted list of the function names available on the object. 777 | // Aliased as `methods` 778 | _.functions = _.methods = function(obj) { 779 | var names = []; 780 | for (var key in obj) { 781 | if (_.isFunction(obj[key])) names.push(key); 782 | } 783 | return names.sort(); 784 | }; 785 | 786 | // Extend a given object with all the properties in passed-in object(s). 787 | _.extend = function(obj) { 788 | each(slice.call(arguments, 1), function(source) { 789 | if (source) { 790 | for (var prop in source) { 791 | obj[prop] = source[prop]; 792 | } 793 | } 794 | }); 795 | return obj; 796 | }; 797 | 798 | // Return a copy of the object only containing the whitelisted properties. 799 | _.pick = function(obj) { 800 | var copy = {}; 801 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 802 | each(keys, function(key) { 803 | if (key in obj) copy[key] = obj[key]; 804 | }); 805 | return copy; 806 | }; 807 | 808 | // Return a copy of the object without the blacklisted properties. 809 | _.omit = function(obj) { 810 | var copy = {}; 811 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); 812 | for (var key in obj) { 813 | if (!_.contains(keys, key)) copy[key] = obj[key]; 814 | } 815 | return copy; 816 | }; 817 | 818 | // Fill in a given object with default properties. 819 | _.defaults = function(obj) { 820 | each(slice.call(arguments, 1), function(source) { 821 | if (source) { 822 | for (var prop in source) { 823 | if (obj[prop] === void 0) obj[prop] = source[prop]; 824 | } 825 | } 826 | }); 827 | return obj; 828 | }; 829 | 830 | // Create a (shallow-cloned) duplicate of an object. 831 | _.clone = function(obj) { 832 | if (!_.isObject(obj)) return obj; 833 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj); 834 | }; 835 | 836 | // Invokes interceptor with the obj, and then returns obj. 837 | // The primary purpose of this method is to "tap into" a method chain, in 838 | // order to perform operations on intermediate results within the chain. 839 | _.tap = function(obj, interceptor) { 840 | interceptor(obj); 841 | return obj; 842 | }; 843 | 844 | // Internal recursive comparison function for `isEqual`. 845 | var eq = function(a, b, aStack, bStack) { 846 | // Identical objects are equal. `0 === -0`, but they aren't identical. 847 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). 848 | if (a === b) return a !== 0 || 1 / a == 1 / b; 849 | // A strict comparison is necessary because `null == undefined`. 850 | if (a == null || b == null) return a === b; 851 | // Unwrap any wrapped objects. 852 | if (a instanceof _) a = a._wrapped; 853 | if (b instanceof _) b = b._wrapped; 854 | // Compare `[[Class]]` names. 855 | var className = toString.call(a); 856 | if (className != toString.call(b)) return false; 857 | switch (className) { 858 | // Strings, numbers, dates, and booleans are compared by value. 859 | case '[object String]': 860 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is 861 | // equivalent to `new String("5")`. 862 | return a == String(b); 863 | case '[object Number]': 864 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for 865 | // other numeric values. 866 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); 867 | case '[object Date]': 868 | case '[object Boolean]': 869 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their 870 | // millisecond representations. Note that invalid dates with millisecond representations 871 | // of `NaN` are not equivalent. 872 | return +a == +b; 873 | // RegExps are compared by their source patterns and flags. 874 | case '[object RegExp]': 875 | return a.source == b.source && 876 | a.global == b.global && 877 | a.multiline == b.multiline && 878 | a.ignoreCase == b.ignoreCase; 879 | } 880 | if (typeof a != 'object' || typeof b != 'object') return false; 881 | // Assume equality for cyclic structures. The algorithm for detecting cyclic 882 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. 883 | var length = aStack.length; 884 | while (length--) { 885 | // Linear search. Performance is inversely proportional to the number of 886 | // unique nested structures. 887 | if (aStack[length] == a) return bStack[length] == b; 888 | } 889 | // Objects with different constructors are not equivalent, but `Object`s 890 | // from different frames are. 891 | var aCtor = a.constructor, bCtor = b.constructor; 892 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && 893 | _.isFunction(bCtor) && (bCtor instanceof bCtor))) { 894 | return false; 895 | } 896 | // Add the first object to the stack of traversed objects. 897 | aStack.push(a); 898 | bStack.push(b); 899 | var size = 0, result = true; 900 | // Recursively compare objects and arrays. 901 | if (className == '[object Array]') { 902 | // Compare array lengths to determine if a deep comparison is necessary. 903 | size = a.length; 904 | result = size == b.length; 905 | if (result) { 906 | // Deep compare the contents, ignoring non-numeric properties. 907 | while (size--) { 908 | if (!(result = eq(a[size], b[size], aStack, bStack))) break; 909 | } 910 | } 911 | } else { 912 | // Deep compare objects. 913 | for (var key in a) { 914 | if (_.has(a, key)) { 915 | // Count the expected number of properties. 916 | size++; 917 | // Deep compare each member. 918 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; 919 | } 920 | } 921 | // Ensure that both objects contain the same number of properties. 922 | if (result) { 923 | for (key in b) { 924 | if (_.has(b, key) && !(size--)) break; 925 | } 926 | result = !size; 927 | } 928 | } 929 | // Remove the first object from the stack of traversed objects. 930 | aStack.pop(); 931 | bStack.pop(); 932 | return result; 933 | }; 934 | 935 | // Perform a deep comparison to check if two objects are equal. 936 | _.isEqual = function(a, b) { 937 | return eq(a, b, [], []); 938 | }; 939 | 940 | // Is a given array, string, or object empty? 941 | // An "empty" object has no enumerable own-properties. 942 | _.isEmpty = function(obj) { 943 | if (obj == null) return true; 944 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; 945 | for (var key in obj) if (_.has(obj, key)) return false; 946 | return true; 947 | }; 948 | 949 | // Is a given value a DOM element? 950 | _.isElement = function(obj) { 951 | return !!(obj && obj.nodeType === 1); 952 | }; 953 | 954 | // Is a given value an array? 955 | // Delegates to ECMA5's native Array.isArray 956 | _.isArray = nativeIsArray || function(obj) { 957 | return toString.call(obj) == '[object Array]'; 958 | }; 959 | 960 | // Is a given variable an object? 961 | _.isObject = function(obj) { 962 | return obj === Object(obj); 963 | }; 964 | 965 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. 966 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { 967 | _['is' + name] = function(obj) { 968 | return toString.call(obj) == '[object ' + name + ']'; 969 | }; 970 | }); 971 | 972 | // Define a fallback version of the method in browsers (ahem, IE), where 973 | // there isn't any inspectable "Arguments" type. 974 | if (!_.isArguments(arguments)) { 975 | _.isArguments = function(obj) { 976 | return !!(obj && _.has(obj, 'callee')); 977 | }; 978 | } 979 | 980 | // Optimize `isFunction` if appropriate. 981 | if (typeof (/./) !== 'function') { 982 | _.isFunction = function(obj) { 983 | return typeof obj === 'function'; 984 | }; 985 | } 986 | 987 | // Is a given object a finite number? 988 | _.isFinite = function(obj) { 989 | return isFinite(obj) && !isNaN(parseFloat(obj)); 990 | }; 991 | 992 | // Is the given value `NaN`? (NaN is the only number which does not equal itself). 993 | _.isNaN = function(obj) { 994 | return _.isNumber(obj) && obj != +obj; 995 | }; 996 | 997 | // Is a given value a boolean? 998 | _.isBoolean = function(obj) { 999 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; 1000 | }; 1001 | 1002 | // Is a given value equal to null? 1003 | _.isNull = function(obj) { 1004 | return obj === null; 1005 | }; 1006 | 1007 | // Is a given variable undefined? 1008 | _.isUndefined = function(obj) { 1009 | return obj === void 0; 1010 | }; 1011 | 1012 | // Shortcut function for checking if an object has a given property directly 1013 | // on itself (in other words, not on a prototype). 1014 | _.has = function(obj, key) { 1015 | return hasOwnProperty.call(obj, key); 1016 | }; 1017 | 1018 | // Utility Functions 1019 | // ----------------- 1020 | 1021 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its 1022 | // previous owner. Returns a reference to the Underscore object. 1023 | _.noConflict = function() { 1024 | root._ = previousUnderscore; 1025 | return this; 1026 | }; 1027 | 1028 | // Keep the identity function around for default iterators. 1029 | _.identity = function(value) { 1030 | return value; 1031 | }; 1032 | 1033 | // Run a function **n** times. 1034 | _.times = function(n, iterator, context) { 1035 | var accum = Array(Math.max(0, n)); 1036 | for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); 1037 | return accum; 1038 | }; 1039 | 1040 | // Return a random integer between min and max (inclusive). 1041 | _.random = function(min, max) { 1042 | if (max == null) { 1043 | max = min; 1044 | min = 0; 1045 | } 1046 | return min + Math.floor(Math.random() * (max - min + 1)); 1047 | }; 1048 | 1049 | // List of HTML entities for escaping. 1050 | var entityMap = { 1051 | escape: { 1052 | '&': '&', 1053 | '<': '<', 1054 | '>': '>', 1055 | '"': '"', 1056 | "'": ''', 1057 | '/': '/' 1058 | } 1059 | }; 1060 | entityMap.unescape = _.invert(entityMap.escape); 1061 | 1062 | // Regexes containing the keys and values listed immediately above. 1063 | var entityRegexes = { 1064 | escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), 1065 | unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') 1066 | }; 1067 | 1068 | // Functions for escaping and unescaping strings to/from HTML interpolation. 1069 | _.each(['escape', 'unescape'], function(method) { 1070 | _[method] = function(string) { 1071 | if (string == null) return ''; 1072 | return ('' + string).replace(entityRegexes[method], function(match) { 1073 | return entityMap[method][match]; 1074 | }); 1075 | }; 1076 | }); 1077 | 1078 | // If the value of the named `property` is a function then invoke it with the 1079 | // `object` as context; otherwise, return it. 1080 | _.result = function(object, property) { 1081 | if (object == null) return void 0; 1082 | var value = object[property]; 1083 | return _.isFunction(value) ? value.call(object) : value; 1084 | }; 1085 | 1086 | // Add your own custom functions to the Underscore object. 1087 | _.mixin = function(obj) { 1088 | each(_.functions(obj), function(name){ 1089 | var func = _[name] = obj[name]; 1090 | _.prototype[name] = function() { 1091 | var args = [this._wrapped]; 1092 | push.apply(args, arguments); 1093 | return result.call(this, func.apply(_, args)); 1094 | }; 1095 | }); 1096 | }; 1097 | 1098 | // Generate a unique integer id (unique within the entire client session). 1099 | // Useful for temporary DOM ids. 1100 | var idCounter = 0; 1101 | _.uniqueId = function(prefix) { 1102 | var id = ++idCounter + ''; 1103 | return prefix ? prefix + id : id; 1104 | }; 1105 | 1106 | // By default, Underscore uses ERB-style template delimiters, change the 1107 | // following template settings to use alternative delimiters. 1108 | _.templateSettings = { 1109 | evaluate : /<%([\s\S]+?)%>/g, 1110 | interpolate : /<%=([\s\S]+?)%>/g, 1111 | escape : /<%-([\s\S]+?)%>/g 1112 | }; 1113 | 1114 | // When customizing `templateSettings`, if you don't want to define an 1115 | // interpolation, evaluation or escaping regex, we need one that is 1116 | // guaranteed not to match. 1117 | var noMatch = /(.)^/; 1118 | 1119 | // Certain characters need to be escaped so that they can be put into a 1120 | // string literal. 1121 | var escapes = { 1122 | "'": "'", 1123 | '\\': '\\', 1124 | '\r': 'r', 1125 | '\n': 'n', 1126 | '\t': 't', 1127 | '\u2028': 'u2028', 1128 | '\u2029': 'u2029' 1129 | }; 1130 | 1131 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; 1132 | 1133 | // JavaScript micro-templating, similar to John Resig's implementation. 1134 | // Underscore templating handles arbitrary delimiters, preserves whitespace, 1135 | // and correctly escapes quotes within interpolated code. 1136 | _.template = function(text, data, settings) { 1137 | var render; 1138 | settings = _.defaults({}, settings, _.templateSettings); 1139 | 1140 | // Combine delimiters into one regular expression via alternation. 1141 | var matcher = new RegExp([ 1142 | (settings.escape || noMatch).source, 1143 | (settings.interpolate || noMatch).source, 1144 | (settings.evaluate || noMatch).source 1145 | ].join('|') + '|$', 'g'); 1146 | 1147 | // Compile the template source, escaping string literals appropriately. 1148 | var index = 0; 1149 | var source = "__p+='"; 1150 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 1151 | source += text.slice(index, offset) 1152 | .replace(escaper, function(match) { return '\\' + escapes[match]; }); 1153 | 1154 | if (escape) { 1155 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; 1156 | } 1157 | if (interpolate) { 1158 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; 1159 | } 1160 | if (evaluate) { 1161 | source += "';\n" + evaluate + "\n__p+='"; 1162 | } 1163 | index = offset + match.length; 1164 | return match; 1165 | }); 1166 | source += "';\n"; 1167 | 1168 | // If a variable is not specified, place data values in local scope. 1169 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; 1170 | 1171 | source = "var __t,__p='',__j=Array.prototype.join," + 1172 | "print=function(){__p+=__j.call(arguments,'');};\n" + 1173 | source + "return __p;\n"; 1174 | 1175 | try { 1176 | render = new Function(settings.variable || 'obj', '_', source); 1177 | } catch (e) { 1178 | e.source = source; 1179 | throw e; 1180 | } 1181 | 1182 | if (data) return render(data, _); 1183 | var template = function(data) { 1184 | return render.call(this, data, _); 1185 | }; 1186 | 1187 | // Provide the compiled function source as a convenience for precompilation. 1188 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; 1189 | 1190 | return template; 1191 | }; 1192 | 1193 | // Add a "chain" function, which will delegate to the wrapper. 1194 | _.chain = function(obj) { 1195 | return _(obj).chain(); 1196 | }; 1197 | 1198 | // OOP 1199 | // --------------- 1200 | // If Underscore is called as a function, it returns a wrapped object that 1201 | // can be used OO-style. This wrapper holds altered versions of all the 1202 | // underscore functions. Wrapped objects may be chained. 1203 | 1204 | // Helper function to continue chaining intermediate results. 1205 | var result = function(obj) { 1206 | return this._chain ? _(obj).chain() : obj; 1207 | }; 1208 | 1209 | // Add all of the Underscore functions to the wrapper object. 1210 | _.mixin(_); 1211 | 1212 | // Add all mutator Array functions to the wrapper. 1213 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { 1214 | var method = ArrayProto[name]; 1215 | _.prototype[name] = function() { 1216 | var obj = this._wrapped; 1217 | method.apply(obj, arguments); 1218 | if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; 1219 | return result.call(this, obj); 1220 | }; 1221 | }); 1222 | 1223 | // Add all accessor Array functions to the wrapper. 1224 | each(['concat', 'join', 'slice'], function(name) { 1225 | var method = ArrayProto[name]; 1226 | _.prototype[name] = function() { 1227 | return result.call(this, method.apply(this._wrapped, arguments)); 1228 | }; 1229 | }); 1230 | 1231 | _.extend(_.prototype, { 1232 | 1233 | // Start chaining a wrapped Underscore object. 1234 | chain: function() { 1235 | this._chain = true; 1236 | return this; 1237 | }, 1238 | 1239 | // Extracts the result from a wrapped and chained object. 1240 | value: function() { 1241 | return this._wrapped; 1242 | } 1243 | 1244 | }); 1245 | 1246 | // AMD define happens at the end for compatibility with AMD loaders 1247 | // that don't enforce next-turn semantics on modules. 1248 | if (typeof define === 'function' && define.amd) { 1249 | define('underscore', function() { 1250 | return _; 1251 | }); 1252 | } 1253 | 1254 | }).call(this); 1255 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/views/addMessage.js: -------------------------------------------------------------------------------- 1 | define(['backbone','channel'],function(Backbone,Channel){ 2 | 3 | return Backbone.View.extend({ 4 | el:'.input-area', 5 | events:{ 6 | 'click .submit' : 'submit', 7 | 'keypress textarea':'submitOnEnter' 8 | }, 9 | 10 | submit : function(){ 11 | nwmsg = this.$el.find('textarea').val(); 12 | this.$el.find('textarea').val(''); 13 | Channel.trigger('addMsg',nwmsg); // reciever messages.view 14 | //auto_scroll(); 15 | }, 16 | submitOnEnter:function(e){ 17 | console.log(e.keyCode); 18 | if(e.keyCode===13 && !e.shiftKey){ 19 | this.submit(); 20 | } 21 | } 22 | }); 23 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/views/message.js: -------------------------------------------------------------------------------- 1 | define(['backbone','underscore','text!templates/message.tmpl'],function(Backbone,_,MessageTmpl){ 2 | 3 | return Backbone.View.extend({ 4 | tagName : 'div', 5 | className : 'monologue', 6 | template : _.template(MessageTmpl), 7 | 8 | render : function(){ 9 | this.$el.html(this.template(this.model.toJSON())); 10 | return this; 11 | } 12 | }); 13 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/views/messages.js: -------------------------------------------------------------------------------- 1 | define(['backbone','views/message','channel'],function(Backbone,MsgView,Channel){ 2 | 3 | return Backbone.View.extend({ 4 | 5 | tagName : 'div', 6 | className : 'chatMsgs', 7 | initialize : function(){ 8 | $('.chatBox').html(this.el); 9 | this.collection.on("add", this.addOne, this); 10 | Channel.on('addMsg',this.addMsg,this); 11 | this.render(); 12 | //scroll to bottom after render 13 | $("html, body").animate({ scrollTop: $(document).height() }, 1000); 14 | }, 15 | render : function(){ 16 | this.collection.each(this.addone,this); 17 | return this; 18 | }, 19 | addOne : function(msg){ 20 | var newMsg = new MsgView({model:msg}); 21 | this.$el.append(newMsg.render().el); 22 | //autoscroll 23 | if($(window).scrollTop() + $(window).height() > $(document).height() - 100) { 24 | 25 | $('html, body').animate({scrollTop:$(document).height()}, 500); 26 | } 27 | 28 | }, 29 | addone : function(msg){ 30 | // for inital rnder without scroll animation 31 | var newMsg = new MsgView({model:msg}); 32 | this.$el.append(newMsg.render().el); 33 | }, 34 | addMsg : function(m){ 35 | this.collection.create({msg:m},{wait:true}); 36 | } 37 | }); 38 | 39 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/views/user.js: -------------------------------------------------------------------------------- 1 | define(['backbone','underscore','text!templates/user.tmpl'],function(Backbone,_,usrTmpl){ 2 | return Backbone.View.extend({ 3 | tagName : 'div', 4 | className : 's_user', 5 | template : _.template(usrTmpl), 6 | 7 | render : function(){ 8 | this.$el.html(this.template(this.model.toJSON())); 9 | return this; 10 | } 11 | }); 12 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/app/scripts/views/users.js: -------------------------------------------------------------------------------- 1 | define(['backbone','views/user'],function(Backbone,usrView){ 2 | 3 | return Backbone.View.extend({ 4 | 5 | el : '.onlineUsers', 6 | initialize : function(){ 7 | 8 | this.collection.fetch(); 9 | //this.collection.on("add", this.addOne, this); 10 | this.collection.on('add',this.render,this); 11 | this.collection.on('remove',this.render,this); 12 | }, 13 | render : function(){ 14 | console.log('........................................rendering............'); 15 | this.$el.html(''); 16 | this.collection.each(this.addOne,this); 17 | return this; 18 | }, 19 | addOne : function(usr){ 20 | var newUsr = new usrView({model:usr}); 21 | this.$el.append(newUsr.render().el); 22 | } 23 | }); 24 | }); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Chat", 3 | "version":"0.2", 4 | "dependencies":{ 5 | "jquery-legacy":"jquery#1.10", 6 | "jquery":null, 7 | "underscore-amd":null, 8 | "backbone-amd":null, 9 | "requirejs":null, 10 | "requirejs-text":null 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000000; 3 | background-color: #E9E9E9; 4 | } 5 | .clear-both { 6 | clear: both; 7 | float: none; 8 | height: 0; 9 | } 10 | .chatBox { 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | width: 80%; 15 | } 16 | .chatBox .chatMsgs { 17 | margin-bottom: 100px; 18 | } 19 | .monologue { 20 | margin-bottom: 10px; 21 | } 22 | .monologue .signature { 23 | float: left; 24 | width: 10%; 25 | margin-right: 20px; 26 | } 27 | .monologue .signature .username { 28 | width: 70%; 29 | float: right; 30 | font-size: 12px; 31 | line-height: 1.2em; 32 | overflow: hidden; 33 | margin-top: 5px; 34 | text-align: right; 35 | word-wrap: break-word; 36 | } 37 | .monologue .signature .avatar { 38 | width: 20%; 39 | float: right; 40 | margin-left: 5px; 41 | 42 | } 43 | .monologue .signature .avatar img{ 44 | box-shadow: 0px 1px 3px #aaa; 45 | } 46 | .monologue .messages { 47 | float: left; 48 | width: 80%; 49 | padding: 5px 10px; 50 | background-color: #fff; 51 | border-radius: 5px; 52 | word-wrap: break-word; 53 | box-shadow: 1px 1px 1px 0px #bbb; 54 | color:#444; 55 | } 56 | .monologue .msg span{ 57 | font-size: 7px; 58 | float: right; 59 | background-color: #eee; 60 | padding: 5px; 61 | font-weight: bold; 62 | 63 | } 64 | /*=======================================================================*/ 65 | .sidebar { 66 | width: 18%; 67 | z-index: 5; 68 | position: fixed; 69 | right: 0; 70 | } 71 | .sidebar .side { 72 | background-color: #fff; 73 | border-radius: 5px; 74 | padding: 10px; 75 | margin-right: 20px; 76 | box-shadow: 0px 1px 3px #aaa; 77 | } 78 | .side h2 { 79 | color: #333; 80 | } 81 | .onlineUsers .s_user { 82 | margin-bottom: 10px; 83 | } 84 | .onlineUsers .s_user .s_avatar { 85 | float: left; 86 | } 87 | .onlineUsers .s_user .s_username { 88 | float: left; 89 | } 90 | .onlineUsers .s_user .s_username a { 91 | text-decoration: none; 92 | font-size: 18px; 93 | color: #333; 94 | margin-left: 5px; 95 | word-wrap: break-word; 96 | } 97 | /* ================================================================= */ 98 | .input-area { 99 | position: fixed; 100 | bottom: 0; 101 | z-index: 6; 102 | width: 100%; 103 | background-color: #ddd; 104 | height: 75px; 105 | box-shadow: 0px -2px 10px 1px #555555; 106 | } 107 | .input-area img { 108 | float: left; 109 | text-align: center; 110 | margin: 5px; 111 | } 112 | .input-area .input-box { 113 | float: left; 114 | width: 60%; 115 | background-color: #fff; 116 | resize: none; 117 | border: none; 118 | margin: 5px; 119 | height: 64px; 120 | } 121 | .input-area .submit { 122 | float: left; 123 | width: 8%; 124 | height: 64px; 125 | margin: 5px; 126 | } 127 | #footer { 128 | position: fixed; 129 | left: 0px; 130 | bottom: 0px; 131 | height: 70px; 132 | width: 100%; 133 | background: #999; 134 | z-index: 9; 135 | } 136 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.1.3 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /** 8 | * Correct `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | main, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | 26 | /** 27 | * Correct `inline-block` display not defined in IE 8/9. 28 | */ 29 | 30 | audio, 31 | canvas, 32 | video { 33 | display: inline-block; 34 | } 35 | 36 | /** 37 | * Prevent modern browsers from displaying `audio` without controls. 38 | * Remove excess height in iOS 5 devices. 39 | */ 40 | 41 | audio:not([controls]) { 42 | display: none; 43 | height: 0; 44 | } 45 | 46 | /** 47 | * Address `[hidden]` styling not present in IE 8/9. 48 | * Hide the `template` element in IE, Safari, and Firefox < 22. 49 | */ 50 | 51 | [hidden], 52 | template { 53 | display: none; 54 | } 55 | 56 | /* ========================================================================== 57 | Base 58 | ========================================================================== */ 59 | 60 | /** 61 | * 1. Set default font family to sans-serif. 62 | * 2. Prevent iOS text size adjust after orientation change, without disabling 63 | * user zoom. 64 | */ 65 | 66 | html { 67 | font-family: sans-serif; /* 1 */ 68 | -ms-text-size-adjust: 100%; /* 2 */ 69 | -webkit-text-size-adjust: 100%; /* 2 */ 70 | } 71 | 72 | /** 73 | * Remove default margin. 74 | */ 75 | 76 | body { 77 | margin: 0; 78 | } 79 | 80 | /* ========================================================================== 81 | Links 82 | ========================================================================== */ 83 | 84 | /** 85 | * Remove the gray background color from active links in IE 10. 86 | */ 87 | 88 | a { 89 | background: transparent; 90 | } 91 | 92 | /** 93 | * Address `outline` inconsistency between Chrome and other browsers. 94 | */ 95 | 96 | a:focus { 97 | outline: thin dotted; 98 | } 99 | 100 | /** 101 | * Improve readability when focused and also mouse hovered in all browsers. 102 | */ 103 | 104 | a:active, 105 | a:hover { 106 | outline: 0; 107 | } 108 | 109 | /* ========================================================================== 110 | Typography 111 | ========================================================================== */ 112 | 113 | /** 114 | * Address variable `h1` font-size and margin within `section` and `article` 115 | * contexts in Firefox 4+, Safari 5, and Chrome. 116 | */ 117 | 118 | h1 { 119 | font-size: 2em; 120 | margin: 0.67em 0; 121 | } 122 | 123 | /** 124 | * Address styling not present in IE 8/9, Safari 5, and Chrome. 125 | */ 126 | 127 | abbr[title] { 128 | border-bottom: 1px dotted; 129 | } 130 | 131 | /** 132 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 133 | */ 134 | 135 | b, 136 | strong { 137 | font-weight: bold; 138 | } 139 | 140 | /** 141 | * Address styling not present in Safari 5 and Chrome. 142 | */ 143 | 144 | dfn { 145 | font-style: italic; 146 | } 147 | 148 | /** 149 | * Address differences between Firefox and other browsers. 150 | */ 151 | 152 | hr { 153 | -moz-box-sizing: content-box; 154 | box-sizing: content-box; 155 | height: 0; 156 | } 157 | 158 | /** 159 | * Address styling not present in IE 8/9. 160 | */ 161 | 162 | mark { 163 | background: #ff0; 164 | color: #000; 165 | } 166 | 167 | /** 168 | * Correct font family set oddly in Safari 5 and Chrome. 169 | */ 170 | 171 | code, 172 | kbd, 173 | pre, 174 | samp { 175 | font-family: monospace, serif; 176 | font-size: 1em; 177 | } 178 | 179 | /** 180 | * Improve readability of pre-formatted text in all browsers. 181 | */ 182 | 183 | pre { 184 | white-space: pre-wrap; 185 | } 186 | 187 | /** 188 | * Set consistent quote types. 189 | */ 190 | 191 | q { 192 | quotes: "\201C" "\201D" "\2018" "\2019"; 193 | } 194 | 195 | /** 196 | * Address inconsistent and variable font size in all browsers. 197 | */ 198 | 199 | small { 200 | font-size: 80%; 201 | } 202 | 203 | /** 204 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 205 | */ 206 | 207 | sub, 208 | sup { 209 | font-size: 75%; 210 | line-height: 0; 211 | position: relative; 212 | vertical-align: baseline; 213 | } 214 | 215 | sup { 216 | top: -0.5em; 217 | } 218 | 219 | sub { 220 | bottom: -0.25em; 221 | } 222 | 223 | /* ========================================================================== 224 | Embedded content 225 | ========================================================================== */ 226 | 227 | /** 228 | * Remove border when inside `a` element in IE 8/9. 229 | */ 230 | 231 | img { 232 | border: 0; 233 | } 234 | 235 | /** 236 | * Correct overflow displayed oddly in IE 9. 237 | */ 238 | 239 | svg:not(:root) { 240 | overflow: hidden; 241 | } 242 | 243 | /* ========================================================================== 244 | Figures 245 | ========================================================================== */ 246 | 247 | /** 248 | * Address margin not present in IE 8/9 and Safari 5. 249 | */ 250 | 251 | figure { 252 | margin: 0; 253 | } 254 | 255 | /* ========================================================================== 256 | Forms 257 | ========================================================================== */ 258 | 259 | /** 260 | * Define consistent border, margin, and padding. 261 | */ 262 | 263 | fieldset { 264 | border: 1px solid #c0c0c0; 265 | margin: 0 2px; 266 | padding: 0.35em 0.625em 0.75em; 267 | } 268 | 269 | /** 270 | * 1. Correct `color` not being inherited in IE 8/9. 271 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 272 | */ 273 | 274 | legend { 275 | border: 0; /* 1 */ 276 | padding: 0; /* 2 */ 277 | } 278 | 279 | /** 280 | * 1. Correct font family not being inherited in all browsers. 281 | * 2. Correct font size not being inherited in all browsers. 282 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 283 | */ 284 | 285 | button, 286 | input, 287 | select, 288 | textarea { 289 | font-family: inherit; /* 1 */ 290 | font-size: 100%; /* 2 */ 291 | margin: 0; /* 3 */ 292 | } 293 | 294 | /** 295 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 296 | * the UA stylesheet. 297 | */ 298 | 299 | button, 300 | input { 301 | line-height: normal; 302 | } 303 | 304 | /** 305 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 306 | * All other form control elements do not inherit `text-transform` values. 307 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. 308 | * Correct `select` style inheritance in Firefox 4+ and Opera. 309 | */ 310 | 311 | button, 312 | select { 313 | text-transform: none; 314 | } 315 | 316 | /** 317 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 318 | * and `video` controls. 319 | * 2. Correct inability to style clickable `input` types in iOS. 320 | * 3. Improve usability and consistency of cursor style between image-type 321 | * `input` and others. 322 | */ 323 | 324 | button, 325 | html input[type="button"], /* 1 */ 326 | input[type="reset"], 327 | input[type="submit"] { 328 | -webkit-appearance: button; /* 2 */ 329 | cursor: pointer; /* 3 */ 330 | } 331 | 332 | /** 333 | * Re-set default cursor for disabled elements. 334 | */ 335 | 336 | button[disabled], 337 | html input[disabled] { 338 | cursor: default; 339 | } 340 | 341 | /** 342 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 343 | * 2. Remove excess padding in IE 8/9/10. 344 | */ 345 | 346 | input[type="checkbox"], 347 | input[type="radio"] { 348 | box-sizing: border-box; /* 1 */ 349 | padding: 0; /* 2 */ 350 | } 351 | 352 | /** 353 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 354 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 355 | * (include `-moz` to future-proof). 356 | */ 357 | 358 | input[type="search"] { 359 | -webkit-appearance: textfield; /* 1 */ 360 | -moz-box-sizing: content-box; 361 | -webkit-box-sizing: content-box; /* 2 */ 362 | box-sizing: content-box; 363 | } 364 | 365 | /** 366 | * Remove inner padding and search cancel button in Safari 5 and Chrome 367 | * on OS X. 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Remove inner padding and border in Firefox 4+. 377 | */ 378 | 379 | button::-moz-focus-inner, 380 | input::-moz-focus-inner { 381 | border: 0; 382 | padding: 0; 383 | } 384 | 385 | /** 386 | * 1. Remove default vertical scrollbar in IE 8/9. 387 | * 2. Improve readability and alignment in all browsers. 388 | */ 389 | 390 | textarea { 391 | overflow: auto; /* 1 */ 392 | vertical-align: top; /* 2 */ 393 | } 394 | 395 | /* ========================================================================== 396 | Tables 397 | ========================================================================== */ 398 | 399 | /** 400 | * Remove most spacing between table cells. 401 | */ 402 | 403 | table { 404 | border-collapse: collapse; 405 | border-spacing: 0; 406 | } 407 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/build.txt: -------------------------------------------------------------------------------- 1 | 2 | scripts/main.js 3 | ---------------- 4 | scripts/vendor/underscore-amd/underscore.js 5 | scripts/vendor/jquery/jquery.js 6 | scripts/vendor/backbone-amd/backbone.js 7 | scripts/vendor/requirejs-text/text.js 8 | text!templates/message.tmpl 9 | scripts/views/message.js 10 | scripts/channel.js 11 | scripts/views/messages.js 12 | scripts/views/addMessage.js 13 | scripts/models/message.js 14 | scripts/collections/messages.js 15 | text!templates/user.tmpl 16 | scripts/views/user.js 17 | scripts/views/users.js 18 | scripts/models/user.js 19 | scripts/collections/users.js 20 | scripts/main.js 21 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/build/app.build.js: -------------------------------------------------------------------------------- 1 | ({appDir:"../",baseUrl:"scripts",dir:"../../dist",mainConfigFile:"../scripts/main.js",name:"main",optimizeCss:"standard"}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/channel.js: -------------------------------------------------------------------------------- 1 | define(["backbone"],function(e){var t=_.extend({},e.Events);return t}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/collections/messages.js: -------------------------------------------------------------------------------- 1 | define(["backbone","models/message"],function(e,t){return Messages=e.Collection.extend({model:t,url:"/chat/api/"}),Messages}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/collections/users.js: -------------------------------------------------------------------------------- 1 | define(["backbone","models/user"],function(e,t){return e.Collection.extend({url:"/chat/api/users/",model:t})}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/models/message.js: -------------------------------------------------------------------------------- 1 | define(["backbone","jquery"],function(e,t){return Message=e.Model.extend({validate:function(e){m=e.msg;if(t.trim(m)==="")return"empty messege"},initialize:function(){this.on("invalid",function(e,t){console.log(t)})}}),Message}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/models/user.js: -------------------------------------------------------------------------------- 1 | define(["backbone"],function(){return Backbone.Model.extend({})}); -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/templates/message.tmpl: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%=user%> 4 |
5 |
<%=user%>
6 |

7 |
8 |
9 |
10 | <%=msg%> 11 | <%=time%> 12 |
13 |
14 |

-------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/templates/user.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | <%= username %> 6 |
7 |

-------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/vendor/backbone-amd/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backbone-amd", 3 | "homepage": "https://github.com/amdjs/backbone", 4 | "version": "1.0.0", 5 | "_release": "1.0.0", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "1.0.0", 9 | "commit": "df9a95275594eee98cd3d372464ee1467fdb7b1f" 10 | }, 11 | "_source": "git://github.com/amdjs/backbone.git", 12 | "_target": "*", 13 | "_originalSource": "backbone-amd" 14 | } -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/vendor/backbone-amd/.gitignore: -------------------------------------------------------------------------------- 1 | raw 2 | *.sw? 3 | .DS_Store 4 | node_modules 5 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/vendor/backbone-amd/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | Rakefile 3 | docs/ 4 | raw/ 5 | examples/ 6 | index.html 7 | .jshintrc 8 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/vendor/backbone-amd/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /djangoChat/static/djangoChat/dist/scripts/vendor/backbone-amd/backbone.js: -------------------------------------------------------------------------------- 1 | // (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc. 2 | // Backbone may be freely distributed under the MIT license. 3 | // For all details and documentation: 4 | // http://backbonejs.org 5 | 6 | (function(e,t){typeof exports!="undefined"?t(e,exports,require("underscore")):typeof define=="function"&&define.amd?define(["underscore","jquery","exports"],function(n,r,i){e.Backbone=t(e,i,n,r)}):e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)})(this,function(e,t,n,r){var i=e.Backbone,s=[],o=s.push,u=s.slice,a=s.splice;t.VERSION="1.0.0",t.$=r,t.noConflict=function(){return e.Backbone=i,this},t.emulateHTTP=!1,t.emulateJSON=!1;var f=t.Events={on:function(e,t,n){if(!c(this,"on",e,[t,n])||!t)return this;this._events||(this._events={});var r=this._events[e]||(this._events[e]=[]);return r.push({callback:t,context:n,ctx:n||this}),this},once:function(e,t,r){if(!c(this,"once",e,[t,r])||!t)return this;var i=this,s=n.once(function(){i.off(e,s),t.apply(this,arguments)});return s._callback=t,this.on(e,s,r)},off:function(e,t,r){var i,s,o,u,a,f,l,h;if(!this._events||!c(this,"off",e,[t,r]))return this;if(!e&&!t&&!r)return this._events={},this;u=e?[e]:n.keys(this._events);for(a=0,f=u.length;a").attr(e);this.setElement(r,!1)}else this.setElement(n.result(this,"el"),!1)}}),t.sync=function(e,r,i){var s=N[e];n.defaults(i||(i={}),{emulateHTTP:t.emulateHTTP,emulateJSON:t.emulateJSON});var o={type:s,dataType:"json"};i.url||(o.url=n.result(r,"url")||j()),i.data==null&&r&&(e==="create"||e==="update"||e==="patch")&&(o.contentType="application/json",o.data=JSON.stringify(i.attrs||r.toJSON(i))),i.emulateJSON&&(o.contentType="application/x-www-form-urlencoded",o.data=o.data?{model:o.data}:{});if(i.emulateHTTP&&(s==="PUT"||s==="DELETE"||s==="PATCH")){o.type="POST",i.emulateJSON&&(o.data._method=s);var u=i.beforeSend;i.beforeSend=function(e){e.setRequestHeader("X-HTTP-Method-Override",s);if(u)return u.apply(this,arguments)}}o.type!=="GET"&&!i.emulateJSON&&(o.processData=!1),o.type==="PATCH"&&window.ActiveXObject&&(!window.external||!window.external.msActiveXFilteringEnabled)&&(o.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")});var a=i.xhr=t.ajax(n.extend(o,i));return r.trigger("request",r,a,i),a};var N={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};t.ajax=function(){return t.$.ajax.apply(t.$,arguments)};var C=t.Router=function(e){e||(e={}),e.routes&&(this.routes=e.routes),this._bindRoutes(),this.initialize.apply(this,arguments)},k=/\((.*?)\)/g,L=/(\(\?)?:\w+/g,A=/\*\w+/g,O=/[\-{}\[\]+?.,\\\^$|#\s]/g;n.extend(C.prototype,f,{initialize:function(){},route:function(e,r,i){n.isRegExp(e)||(e=this._routeToRegExp(e)),n.isFunction(r)&&(i=r,r=""),i||(i=this[r]);var s=this;return t.history.route(e,function(n){var o=s._extractParameters(e,n);i&&i.apply(s,o),s.trigger.apply(s,["route:"+r].concat(o)),s.trigger("route",r,o),t.history.trigger("route",s,r,o)}),this},navigate:function(e,n){return t.history.navigate(e,n),this},_bindRoutes:function(){if(!this.routes)return;this.routes=n.result(this,"routes");var e,t=n.keys(this.routes);while((e=t.pop())!=null)this.route(e,this.routes[e])},_routeToRegExp:function(e){return e=e.replace(O,"\\$&").replace(k,"(?:$1)?").replace(L,function(e,t){return t?e:"([^/]+)"}).replace(A,"(.*?)"),new RegExp("^"+e+"$")},_extractParameters:function(e,t){var r=e.exec(t).slice(1);return n.map(r,function(e){return e?decodeURIComponent(e):null})}});var M=t.History=function(){this.handlers=[],n.bindAll(this,"checkUrl"),typeof window!="undefined"&&(this.location=window.location,this.history=window.history)},_=/^[#\/]|\s+$/g,D=/^\/+|\/+$/g,P=/msie [\w.]+/,H=/\/$/;M.started=!1,n.extend(M.prototype,f,{interval:50,getHash:function(e){var t=(e||this).location.href.match(/#(.*)$/);return t?t[1]:""},getFragment:function(e,t){if(e==null)if(this._hasPushState||!this._wantsHashChange||t){e=this.location.pathname;var n=this.root.replace(H,"");e.indexOf(n)||(e=e.substr(n.length))}else e=this.getHash();return e.replace(_,"")},start:function(e){if(M.started)throw new Error("Backbone.history has already been started");M.started=!0,this.options=n.extend({},{root:"/"},this.options,e),this.root=this.options.root,this._wantsHashChange=this.options.hashChange!==!1,this._wantsPushState=!!this.options.pushState,this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment(),i=document.documentMode,s=P.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(D,"/"),s&&this._wantsHashChange&&(this.iframe=t.$('