Commit 125e3b73 authored by JC Brand's avatar JC Brand

Merge branch 'vcard' of github.com:jcbrand/converse.js

Conflicts:
	CHANGES.rst
	converse.js
parents f8056be8 b1a80ac5
Changelog Changelog
========= =========
0.2 (unreleased) 0.3 (unreleased)
----------------
- Add vCard support [jcbrand]
- Remember custom status messages upon reload. [jcbrand]
- Remove jquery-ui dependency. [jcbrand]
- Use backbone.localStorage to store the contacts roster, open chatboxes and
chat messages. [jcbrand]
- Fixed user status handling, which wasn't 100% according to the
spec. [jcbrand]
- Separate messages according to day in chats. [jcbrand]
0.2 (2013-03-28)
---------------- ----------------
- Performance enhancements and general script cleanup [ichim-david] - Performance enhancements and general script cleanup [ichim-david]
......
This diff is collapsed.
/**
* Backbone localStorage Adapter
* Version 1.1.0
*
* https://github.com/jeromegn/Backbone.localStorage
*/
(function (root, factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["underscore","backbone"], function(_, Backbone) {
// Use global variables if the locals is undefined.
return factory(_ || root._, Backbone || root.Backbone);
});
} else {
// RequireJS isn't being used. Assume underscore and backbone is loaded in <script> tags
factory(_, Backbone);
}
}(this, function(_, Backbone) {
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.
// Hold reference to Underscore.js and Backbone.js in the closure in order
// to make things work even if they are removed from the global namespace
// Generate four random hex digits.
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};
// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
// window.Store is deprectated, use Backbone.LocalStorage instead
Backbone.LocalStorage = window.Store = function(name) {
this.name = name;
var store = this.localStorage().getItem(this.name);
this.records = (store && store.split(",")) || [];
};
_.extend(Backbone.LocalStorage.prototype, {
// Save the current state of the **Store** to *localStorage*.
save: function() {
this.localStorage().setItem(this.name, this.records.join(","));
},
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) {
model.id = guid();
model.set(model.idAttribute, model.id);
}
this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
this.records.push(model.id.toString());
this.save();
return this.find(model);
},
// Update a model by replacing its copy in `this.data`.
update: function(model) {
this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
if (!_.include(this.records, model.id.toString()))
this.records.push(model.id.toString()); this.save();
return this.find(model);
},
// Retrieve a model from `this.data` by id.
find: function(model) {
return this.jsonData(this.localStorage().getItem(this.name+"-"+model.id));
},
// Return the array of all models currently in storage.
findAll: function() {
return _(this.records).chain()
.map(function(id){
return this.jsonData(this.localStorage().getItem(this.name+"-"+id));
}, this)
.compact()
.value();
},
// Delete a model from `this.data`, returning it.
destroy: function(model) {
if (model.isNew())
return false
this.localStorage().removeItem(this.name+"-"+model.id);
this.records = _.reject(this.records, function(id){
return id === model.id.toString();
});
this.save();
return model;
},
localStorage: function() {
return localStorage;
},
// fix for "illegal access" error on Android when JSON.parse is passed null
jsonData: function (data) {
return data && JSON.parse(data);
}
});
// localSync delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
// window.Store.sync and Backbone.localSync is deprectated, use Backbone.LocalStorage.sync instead
Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) {
var store = model.localStorage || model.collection.localStorage;
var resp, errorMessage, syncDfd = $.Deferred && $.Deferred(); //If $ is having Deferred - use it.
try {
switch (method) {
case "read":
resp = model.id != undefined ? store.find(model) : store.findAll();
break;
case "create":
resp = store.create(model);
break;
case "update":
resp = store.update(model);
break;
case "delete":
resp = store.destroy(model);
break;
}
} catch(error) {
if (error.code === DOMException.QUOTA_EXCEEDED_ERR && window.localStorage.length === 0)
errorMessage = "Private browsing is unsupported";
else
errorMessage = error.message;
}
if (resp) {
if (options && options.success)
if (Backbone.VERSION === "0.9.10") {
options.success(model, resp, options);
} else {
options.success(resp);
}
if (syncDfd)
syncDfd.resolve(resp);
} else {
errorMessage = errorMessage ? errorMessage
: "Record Not Found";
if (options && options.error)
if (Backbone.VERSION === "0.9.10") {
options.error(model, errorMessage, options);
} else {
options.error(errorMessage);
}
if (syncDfd)
syncDfd.reject(errorMessage);
}
// add compatibility with $.ajax
// always execute callback for success and error
if (options && options.complete) options.complete(resp);
return syncDfd && syncDfd.promise();
};
Backbone.ajaxSync = Backbone.sync;
Backbone.getSyncMethod = function(model) {
if(model.localStorage || (model.collection && model.collection.localStorage)) {
return Backbone.localSync;
}
return Backbone.ajaxSync;
};
// Override 'Backbone.sync' to default to localSync,
// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
Backbone.sync = function(method, model, options) {
return Backbone.getSyncMethod(model).apply(this, [method, model, options]);
};
return Backbone.LocalStorage;
}));
Copyright (c) 2012 Yiorgis Gozadinos, Riot AS
Postboks 2236, 3103 Tønsberg, Norway
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# burry.js
A simple caching layer on the browser's localStorage
## Usage
### Creation
Create a Burry `Store`, optionally passing a namespace. A default store is always available with no namespace:
```javascript
var burry = new Burry.Store('mystuff');
```
If you want to also set a default time-to-live on a namespaced store, pass the time-to-live as a second parameter. For instance,
```javascript
var burrywithttl = new Burry.Store('mystuff', 10);
```
will create a store where the default time-to-live when you set items is 10 minutes.
You can obtain all available stores, by invoking `stores()`:
```javascript
var stores = Burry.stores(); // stores is ['', 'mystuff']
```
### Getting/Setting
`set` and `get` JSON-serializable javascript objects easily to and from the cache.
```javascript
burry.set('foo', {bar: 'burry'});
var foo = burry.get('foo'); // foo is {bar: 'burry'}
foo = burry.get('unknown'); // foo is undefined
```
You can specify a time-to-live per key/value. This is expressed in minutes:
```javascript
burry.set('foo', {bar: 'burry'}, 10);
var foo = burry.get('foo'); // foo is {bar: 'burry'}
...
// Ten minutes later...
foo = burry.get('foo'); // foo is undefined and also removed from localStorage
```
Attempting to `set` when the `localStorage` is full, will try again after flushing expired key/values from the cache. If this does not succeed either, your `set` will be ignored.
### Counters
You can increment/decrement persistent counters. If the counter does not exist, it is initialized with the value 0.
```javascript
burry.incr('counter');
burry.incr('counter');
var counter = burry.get('counter'); // counter === 2
burry.decr('counter');
counter = burry.get('counter'); // counter === 1
```
### Helpers
The following more esoteric functions are also exposed:
* `burry.add(key, value, ttl)`, same as `set` except it will only add the key if it does not already exist, or it has already expired.
* `burry.replace(key, value, ttl)`, same as `set` except it will only add the key if it does already exist and has not expired.
* `burry.flush()`, removes from `localStorage` all Burry items.
* `burry.flushExpired()`, removes from `localStorage` all expired Burry items of the store.
* `Burry.flushExpired()`, removes from `localStorage` all expired Burry items of all stores.
* `burry.keys()`, returns all stored keys.
* `burry.expirableKeys()` return an dictionary of key/values where the values are the TTL of the keys from Epoch.
* `burry.hasExpired(key)`, returns whether a key has expired.
* `Burry.isSupported()`, returns whether `localStorage` and `JSON` serialization are supported on the browser.
## License
Backbone.xmpp.storage is Copyright (C) 2012 Yiorgis Gozadinos, Riot AS.
It is distributed under the MIT license.
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 16px;
line-height: 24px;
color: #252519;
margin: 0; padding: 0;
}
a {
color: #261a3b;
}
a:visited {
color: #261a3b;
}
p {
margin: 0 0 15px 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 40px 0 15px 0;
}
h2, h3, h4, h5, h6 {
margin-top: 0;
}
#container, div.section {
position: relative;
}
#background {
position: fixed;
top: 0; left: 580px; right: 0; bottom: 0;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
z-index: -1;
}
#jump_to, #jump_page {
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 10px Arial;
text-transform: uppercase;
cursor: pointer;
text-align: right;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
display: none;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 5px 10px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
div.docs {
float: left;
max-width: 500px;
min-width: 500px;
min-height: 5px;
padding: 10px 25px 1px 50px;
vertical-align: top;
text-align: left;
}
.docs pre {
margin: 15px 0 15px;
padding-left: 15px;
}
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
.octowrap {
position: relative;
}
.octothorpe {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
div.docs:hover .octothorpe {
opacity: 1;
}
div.code {
margin-left: 580px;
padding: 14px 15px 16px 50px;
vertical-align: top;
}
.code pre, .docs p code {
font-size: 12px;
}
pre, tt, code {
line-height: 18px;
font-family: Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
div.clearall {
clear: both;
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<title>Jasmine Spec Runner</title>
<link rel="stylesheet" type="text/css" href="./vendor/jasmine/jasmine.css"/>
<script src="./vendor/jquery.js"></script>
<script src="../burry.js"></script>
<script src="./vendor/jasmine/jasmine.js"></script>
<script src="./vendor/jasmine/jasmine-html.js"></script>
<script src="./specs/burry_spec.js"></script>
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
</body>
</html>
/*globals jasmine:false */
(function ($) {
$(function () {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
jasmineEnv.execute();
});
})(this.jQuery);
\ No newline at end of file
This diff is collapsed.
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
#HTMLReporter a { text-decoration: none; }
#HTMLReporter a:hover { text-decoration: underline; }
#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
#HTMLReporter .version { color: #aaaaaa; }
#HTMLReporter .banner { margin-top: 14px; }
#HTMLReporter .duration { color: #aaaaaa; float: right; }
#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
#HTMLReporter .runningAlert { background-color: #666666; }
#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
#HTMLReporter .passingAlert { background-color: #a6b779; }
#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
#HTMLReporter .failingAlert { background-color: #cf867e; }
#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
#HTMLReporter .results { margin-top: 14px; }
#HTMLReporter #details { display: none; }
#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter.showDetails .summary { display: none; }
#HTMLReporter.showDetails #details { display: block; }
#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
#HTMLReporter .summary { margin-top: 14px; }
#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
#HTMLReporter .description + .suite { margin-top: 0; }
#HTMLReporter .suite { margin-top: 14px; }
#HTMLReporter .suite a { color: #333333; }
#HTMLReporter #details .specDetail { margin-bottom: 28px; }
#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
#HTMLReporter .resultMessage span.result { display: block; }
#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
#TrivialReporter .runner.running { background-color: yellow; }
#TrivialReporter .options { text-align: right; font-size: .8em; }
#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
#TrivialReporter .suite .suite { margin: 5px; }
#TrivialReporter .suite.passed { background-color: #dfd; }
#TrivialReporter .suite.failed { background-color: #fdd; }
#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
#TrivialReporter .spec.skipped { background-color: #bbb; }
#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
#TrivialReporter .passed { background-color: #cfc; display: none; }
#TrivialReporter .failed { background-color: #fbb; }
#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
#TrivialReporter .resultMessage .mismatch { color: black; }
#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
} }
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define([ define([
"Libraries/strophe", "strophe"
"Libraries/underscore"
], function () { ], function () {
if (console===undefined || console.log===undefined) { if (console===undefined || console.log===undefined) {
console = { log: function () {}, error: function () {} }; console = { log: function () {}, error: function () {} };
......
...@@ -98,6 +98,7 @@ Strophe.addConnectionPlugin('roster', ...@@ -98,6 +98,7 @@ Strophe.addConnectionPlugin('roster',
}; };
Strophe.addNamespace('ROSTER_VER', 'urn:xmpp:features:rosterver'); Strophe.addNamespace('ROSTER_VER', 'urn:xmpp:features:rosterver');
Strophe.addNamespace('NICK', 'http://jabber.org/protocol/nick');
}, },
/** Function: supportVersioning /** Function: supportVersioning
* return true if roster versioning is enabled on server * return true if roster versioning is enabled on server
...@@ -183,13 +184,17 @@ Strophe.addConnectionPlugin('roster', ...@@ -183,13 +184,17 @@ Strophe.addConnectionPlugin('roster',
* *
* Parameters: * Parameters:
* (String) jid * (String) jid
* (String) message * (String) message (optional)
* (String) nick (optional)
*/ */
subscribe: function(jid, message) subscribe: function(jid, message, nick) {
{
var pres = $pres({to: jid, type: "subscribe"}); var pres = $pres({to: jid, type: "subscribe"});
if (message && message != "") if (message && message !== "") {
pres.c("status").t(message); pres.c("status").t(message);
}
if (nick && nick !== "") {
pres.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick);
}
this._connection.send(pres); this._connection.send(pres);
}, },
/** Function: unsubscribe /** Function: unsubscribe
...@@ -435,4 +440,4 @@ Strophe.addConnectionPlugin('roster', ...@@ -435,4 +440,4 @@ Strophe.addConnectionPlugin('roster',
item.groups = groups; item.groups = groups;
} }
} }
}); });
\ No newline at end of file
// Generated by CoffeeScript 1.3.3
/*
Plugin to implement the vCard extension.
http://xmpp.org/extensions/xep-0054.html
Author: Nathan Zorn (nathan.zorn@gmail.com)
CoffeeScript port: Andreas Guth (guth@dbis.rwth-aachen.de)
*/
/* jslint configuration:
*/
/* global document, window, setTimeout, clearTimeout, console,
XMLHttpRequest, ActiveXObject,
Base64, MD5,
Strophe, $build, $msg, $iq, $pres
*/
var buildIq;
buildIq = function(type, jid, vCardEl) {
var iq;
iq = $iq(jid ? {
type: type,
to: jid
} : {
type: type
});
iq.c("vCard", {
xmlns: Strophe.NS.VCARD
});
if (vCardEl) {
iq.cnode(vCardEl);
}
return iq;
};
Strophe.addConnectionPlugin('vcard', {
_connection: null,
init: function(conn) {
this._connection = conn;
return Strophe.addNamespace('VCARD', 'vcard-temp');
},
/*Function
Retrieve a vCard for a JID/Entity
Parameters:
(Function) handler_cb - The callback function used to handle the request.
(String) jid - optional - The name of the entity to request the vCard
If no jid is given, this function retrieves the current user's vcard.
*/
get: function(handler_cb, jid, error_cb) {
var iq;
iq = buildIq("get", jid);
return this._connection.sendIQ(iq, handler_cb, error_cb);
},
/* Function
Set an entity's vCard.
*/
set: function(handler_cb, vCardEl, jid, error_cb) {
var iq;
iq = buildIq("set", jid, vCardEl);
return this._connection.sendIQ(iq, handler_cb, error_rb);
}
});
This diff is collapsed.
This diff is collapsed.
...@@ -5,4 +5,6 @@ TODO: ...@@ -5,4 +5,6 @@ TODO:
* Add /leave command * Add /leave command
* Inform users of /help via placeholder in textarea * Inform users of /help via placeholder in textarea
* Create a single sprite image from the current images * Create a single sprite image from the current images
* Add "keep me logged in" feature when logging in manually
* Add support for XMPP server feature detection
* Implement "Fetch user vCard" feature.
body {
font: 100% Arial, FreeSans, sans-serif;
font-family: "Helvetica Neue", Arial, FreeSans, sans-serif;
-webkit-font-smoothing: antialiased; /* Fix for webkit rendering */
-webkit-text-size-adjust: 100%;
text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
background: url('images/bg.png');
}
/* #Typography
================================================== */
h1, h2, h3, h4, h5, h6 {
color: #181818;
font-family: "Georgia", "Times New Roman", serif;
font-weight: normal; }
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; }
h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;}
h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; }
h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; }
h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; }
h5 { font-size: 17px; line-height: 24px; }
h6 { font-size: 14px; line-height: 21px; }
.subheader { color: #777; }
p { margin: 0 0 20px 0; }
p img { margin: 0; }
p.lead { font-size: 21px; line-height: 27px; color: #777; }
em { font-style: italic; }
strong { font-weight: bold; color: #333; }
small { font-size: 80%; }
blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; }
blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; }
blockquote cite { display: block; font-size: 12px; color: #555; }
blockquote cite:before { content: "\2014 \0020"; }
blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; }
hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; }
/* #Links
================================================== */
a, a:visited { text-decoration: none; outline: 0; color: rgb(70, 70, 70); }
a:hover, a:focus {color: rgb(164, 72, 72);}
p a, p a:visited { line-height: inherit; }
...@@ -25,10 +25,6 @@ ...@@ -25,10 +25,6 @@
height: 1.1em; height: 1.1em;
} }
#toggle-online-users {
display: none;
}
#connecting-to-chat { #connecting-to-chat {
background: url(images/spinner.gif) no-repeat left; background: url(images/spinner.gif) no-repeat left;
padding-left: 1.4em; padding-left: 1.4em;
...@@ -119,7 +115,6 @@ input.new-chatroom-name { ...@@ -119,7 +115,6 @@ input.new-chatroom-name {
.chat-textarea { .chat-textarea {
border: 0; border: 0;
height: 50px; height: 50px;
width: 100%;
} }
.chat-textarea-chatbox-selected { .chat-textarea-chatbox-selected {
...@@ -152,14 +147,24 @@ input.new-chatroom-name { ...@@ -152,14 +147,24 @@ input.new-chatroom-name {
font-weight: bold; font-weight: bold;
color: #F62817; color: #F62817;
white-space: nowrap; white-space: nowrap;
max-width: 100px;
text-overflow: ellipsis;
overflow: hidden;
display: inline-block;
} }
.chat-event, .chat-date, .chat-help { .chat-event, .chat-date, .chat-help {
color: #808080; color: #808080;
} }
.chat-date {
display: inline-block;
padding-top: 10px;
}
div#settings, div#settings,
div#chatrooms { div#chatrooms,
div#login-dialog {
height: 279px; height: 279px;
} }
...@@ -184,7 +189,6 @@ div.delayed .chat-message-me { ...@@ -184,7 +189,6 @@ div.delayed .chat-message-me {
} }
.chat-head .avatar { .chat-head .avatar {
height: 35px;
float: left; float: left;
margin-right: 6px; margin-right: 6px;
} }
...@@ -227,7 +231,7 @@ p.chatroom-topic { ...@@ -227,7 +231,7 @@ p.chatroom-topic {
a.subscribe-to-user { a.subscribe-to-user {
padding-left: 2em; padding-left: 2em;
background: url('/add_icon.png') no-repeat 3px top; background: url('images/add_icon.png') no-repeat 3px top;
font-weight: bold; font-weight: bold;
} }
...@@ -237,7 +241,7 @@ div.add-xmpp-contact { ...@@ -237,7 +241,7 @@ div.add-xmpp-contact {
padding: 3px 3px 3px 3px; padding: 3px 3px 3px 3px;
margin: 0 0.5em; margin: 0 0.5em;
clear: both; clear: both;
background: url('/add_icon.png') no-repeat 3px 3px; background: url('images/add_icon.png') no-repeat 3px 3px;
font-weight: bold; font-weight: bold;
} }
...@@ -248,7 +252,7 @@ div.add-xmpp-contact a.add-xmpp-contact { ...@@ -248,7 +252,7 @@ div.add-xmpp-contact a.add-xmpp-contact {
#fancy-xmpp-status-select a.change-xmpp-status-message { #fancy-xmpp-status-select a.change-xmpp-status-message {
text-shadow: 0 1px 0 rgba(250, 250, 250, 1); text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
background: url('/pencil_icon.png') no-repeat right top; background: url('images/pencil_icon.png') no-repeat right top;
float: right; float: right;
clear: right; clear: right;
width: 1em; width: 1em;
...@@ -353,8 +357,8 @@ form.search-xmpp-contact input { ...@@ -353,8 +357,8 @@ form.search-xmpp-contact input {
background: url(images/user_offline_panel.png) no-repeat 5px 2px; background: url(images/user_offline_panel.png) no-repeat 5px 2px;
} }
#xmppchat-roster dd.current-xmpp-contact.busy, #xmppchat-roster dd.current-xmpp-contact.dnd,
#xmppchat-roster dd.current-xmpp-contact.busy:hover { #xmppchat-roster dd.current-xmpp-contact.dnd:hover {
background: url(images/user_busy_panel.png) no-repeat 5px 2px; background: url(images/user_busy_panel.png) no-repeat 5px 2px;
} }
...@@ -368,8 +372,13 @@ form.search-xmpp-contact input { ...@@ -368,8 +372,13 @@ form.search-xmpp-contact input {
} }
#xmppchat-roster dd a { #xmppchat-roster dd a {
margin-left: 2em; margin-left: 1.5em;
text-shadow: 0 1px 0 rgba(250, 250, 250, 1); text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
display: inline-block;
width: 113px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
.remove-xmpp-contact-dialog .ui-dialog-buttonpane { .remove-xmpp-contact-dialog .ui-dialog-buttonpane {
...@@ -418,9 +427,10 @@ dd.available-chatroom, ...@@ -418,9 +427,10 @@ dd.available-chatroom,
} }
#xmppchat-roster dd a.remove-xmpp-contact { #xmppchat-roster dd a.remove-xmpp-contact {
background: url('/delete_icon.png') no-repeat right top; background: url('images/delete_icon.png') no-repeat right top;
padding: 0 1em 1em 0; padding: 0 1em 1em 0;
float: right; float: right;
width: 22px;
margin: 0; margin: 0;
} }
...@@ -435,7 +445,7 @@ dd.available-chatroom, ...@@ -435,7 +445,7 @@ dd.available-chatroom,
} }
.chatbox { .chatbox {
width: 200px; width: 201px;
} }
.chatroom { .chatroom {
...@@ -478,6 +488,14 @@ div#controlbox-panes { ...@@ -478,6 +488,14 @@ div#controlbox-panes {
width: 199px; width: 199px;
} }
form#xmppchat-login {
padding: 2em 0 0.3em 0.5em;
}
form#xmppchat-login input {
display: block;
}
form.set-xmpp-status, form.set-xmpp-status,
form.add-chatroom { form.add-chatroom {
padding: 0.5em 0 0.3em 0.5em; padding: 0.5em 0 0.3em 0.5em;
...@@ -545,6 +563,7 @@ ul#controlbox-tabs a.current, ul#controlbox-tabs a.current:hover { ...@@ -545,6 +563,7 @@ ul#controlbox-tabs a.current, ul#controlbox-tabs a.current:hover {
div#users, div#users,
div#chatrooms, div#chatrooms,
div#login-dialog,
div#settings { div#settings {
border: 0; border: 0;
font-size: 14px; font-size: 14px;
...@@ -565,6 +584,7 @@ form.sendXMPPMessage { ...@@ -565,6 +584,7 @@ form.sendXMPPMessage {
background-clip: padding-box; background-clip: padding-box;
border-top-left-radius: 0; border-top-left-radius: 0;
border-top-right-radius: 0; border-top-right-radius: 0;
height: 54px;
} }
#set-custom-xmpp-status { #set-custom-xmpp-status {
...@@ -631,7 +651,7 @@ input.custom-xmpp-status { ...@@ -631,7 +651,7 @@ input.custom-xmpp-status {
background: url(images/user_offline_panel.png) no-repeat left; background: url(images/user_offline_panel.png) no-repeat left;
} }
.dropdown a.busy { .dropdown a.dnd {
background: url(images/user_busy_panel.png) no-repeat left; background: url(images/user_busy_panel.png) no-repeat left;
} }
......
This diff is collapsed.
images/bg.png

723 Bytes

<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Converse.js Demo Page</title> <title>Converse.js Demo Page</title>
<!-- This is a special version of jQuery with RequireJS built-in --> <link rel="stylesheet" href="base.css" type="text/css" media="all">
<link rel="stylesheet" href="Libraries/css/jquery-ui-1.9.1.custom/ui-lightness/jquery-ui-1.9.1.custom.css" type="text/css" media="all"> <link rel="stylesheet" href="converse.css" type="text/css" media="all">
<link rel="stylesheet" href="converse.css" type="text/css" media="all"> <!-- This is a special version of jQuery with RequireJS built-in -->
<script data-main="main" src="Libraries/require-jquery.js"></script> <script data-main="main" src="Libraries/require-jquery.js"></script>
</head> </head>
<body> <body>
<h1>Converse.js Demo Page</h1> <article>
Log in with your Jabber/XMPP ID and password. <h1>Converse.js</h1>
<!-- login dialog --> <div>
<div id='login_dialog' class='hidden'> <p><tt>Converse.js</tt> implements an <a href="http://xmpp.org">XMPP</a> based instant messaging client in the browser.</p>
<label>Login ID:</label> <p>It's used by <a href="http://github.com/collective/collective.xmpp.chat">collective.xmpp.chat</a>, which is a <a href="http://plone.org">Plone</a> instant messaging add-on.</p>
<input type='text' id='jid'> <p>The ultimate goal is to enable anyone to add chat functionality to their websites, regardless of the server backend.</p>
<label>Password:</label> <p>Currently this is not yet 100% the case, as the code makes ajax calls to the (Plone) backend to fetch user info.</p>
<input type='password' id='password'> <h2>Features</h2>
<label>BOSH Service URL:</label> <ul>
<input type='text' id='bosh_service_url'> <li>Manually or automically subscribe to other users.</li>
</div> <li>Accept or decline contact requests</li>
<div id="collective-xmpp-chat-data"></div> <li>Chat status (online, busy, away, offline)</li>
</body> <li>Custom status messages</li>
<li>Typing notifications</li>
<li>Third person messages (/me )</li>
<li>Multi-user chat in chatrooms</li>
<li>Chatroom Topics</li>
<li>vCard support</li>
</ul>
<p>A screencast of (a very old version of) <tt>Converse.js</tt> in action via <tt>collective.xmpp.chat</tt>
can be seen <a href="http://opkode.com/media/blog/instant-messaging-for-plone-with-javascript-and-xmpp">here</a>.</p>
<h2>Dependencies</h2>
<p>It depends on quite a few third party libraries, including <a href="http://strophe.im/strophejs">strophe.js</a>,
<a href="http:/backbonejs.org">backbone.js</a> and <a href="http:/requirejs.org">require.js</a>.</p>
<h2>Licence</h2>
<p><tt>Converse.js</tt> is released under both the <a href="http://opensource.org/licenses/mit-license.php">MIT</a>
and <a href="http://opensource.org/licenses/gpl-license.php">GPL</a> licenses.</p>
<h2>Download</h2>
Head on down to our <a href="https://github.com/jcbrand/converse.js">Github repo</a>.
</div>
</article>
<div id="chatpanel" i18n:domain="collective.xmpp.chat">
<div id="collective-xmpp-chat-data"></div>
<div id="toggle-controlbox">
<a href="#" class="chat" id="toggle-online-users">
<span i18n:translate="">Online Users</span> (<strong id="online-count">0</strong>)
</a>
<span id="connecting-to-chat" i18n:translate="">Connecting to chat ...</span>
</div>
</div>
</body>
</html> </html>
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment