Commit 38c26013 authored by JC Brand's avatar JC Brand

Simplify the boilerplate HTML require even more.

Use id 'conversejs' instead of 'chatpanel'.

The controlbox toggle is now generated via a backbone view, you don't need to
manually include it in your markup.
parent 90a5df87
......@@ -4,10 +4,15 @@ Changelog
0.7.0 (Unreleased)
------------------
.. Note ::
This release introduces a backward incompatible change. The boilerplate
HTML needed in your webpage for converse.js to work has been reduced to a
single div: <div id="conversejs"></div>
* Add a toolbar for single user chat [jcbrand]
* Add support for OTR (off-the-record) encryption [jcbrand]
* Add support for smileys [jcbrand]
* Simplified initial boilerplate markup [jcbrand]
* Simplified boilerplate markup [jcbrand]
* New configuration settings, ``xhr_custom_status_url`` and ``xhr_user_search_url`` [jcbrand]
0.6.6 (2013-10-16)
......
......@@ -17,12 +17,12 @@
user-select: none;
}
#chatpanel, #chatpanel input {
#conversejs, #conversejs input {
color: rgb(79, 79, 79);
}
#chatpanel .emoticon {
#conversejs .emoticon {
font-size: 14px;
}
......@@ -54,7 +54,7 @@ span.spinner.hor_centered {
position: absolute;
}
#chatpanel {
#conversejs {
z-index: 99; /*--Keeps the panel on top of all other elements--*/
position: fixed;
bottom: 0; right: 0;
......@@ -478,7 +478,7 @@ a.close-chatbox-button:active {
margin-top: 0.5em;
}
#chatpanel dd.available-chatroom {
#conversejs dd.available-chatroom {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
......@@ -486,7 +486,7 @@ a.close-chatbox-button:active {
width: 175px;
}
#chatpanel dd.available-chatroom a.open-room {
#conversejs dd.available-chatroom a.open-room {
width: 148px;
}
......@@ -613,7 +613,7 @@ dd.available-chatroom:hover a.room-info {
background-color: #DCEAC5;
}
#chatpanel div.controlbox-panes {
#conversejs div.controlbox-panes {
background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(240,240,240,1) 100%); /* FF3.6+ */
background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* IE10+ */
background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Opera 11.10+ */
......
......@@ -110,7 +110,7 @@
// Translation machinery
// ---------------------
var __ = $.proxy(function (str) {
// Translation factory
// Translation factory
if (this.i18n === undefined) {
this.i18n = locales.en;
}
......@@ -332,35 +332,6 @@
this.updateMsgCounter();
};
this.showControlBox = function () {
var controlbox = this.chatboxes.get('controlbox');
if (!controlbox) {
this.chatboxes.add({
id: 'controlbox',
box_id: 'controlbox',
visible: true
});
if (this.connection) {
this.chatboxes.get('controlbox').save();
}
} else {
controlbox.trigger('show');
}
};
this.toggleControlBox = function () {
if ($("div#controlbox").is(':visible')) {
var controlbox = this.chatboxes.get('controlbox');
if (this.connection) {
controlbox.destroy();
} else {
controlbox.trigger('hide');
}
} else {
this.showControlBox();
}
};
this.initStatus = function (callback) {
this.xmppstatus = new this.XMPPStatus();
var id = hex_sha1('converse.xmppstatus-'+this.bare_jid);
......@@ -455,7 +426,7 @@
this.set({
'user_id' : Strophe.getNodeFromJid(this.get('jid')),
'box_id' : hex_sha1(this.get('jid')),
'otr_status': this.get('otr_status') || UNENCRYPTED
'otr_status': this.get('otr_status') || UNENCRYPTED
});
}
},
......@@ -479,14 +450,14 @@
'instance_tag': instance_tag
};
}
}
}
// We need to generate a new key and instance tag
result = alert(__('Your browser needs to generate a private key, which will be used in your encrypted chat session. This can take up to 30 seconds during which your browser might freeze and become unresponsive.'));
instance_tag = otr.OTR.makeInstanceTag();
key = new otr.DSA();
// Encrypt the key and set in sessionStorage. Also store
// instance tag
window.sessionStorage[hex_sha1(this.id+'priv_key')] =
window.sessionStorage[hex_sha1(this.id+'priv_key')] =
cipher.encrypt(crypto.algo.AES, key.packPrivate(), pass).toString();
window.sessionStorage[hex_sha1(this.id+'instance_tag')] = instance_tag;
......@@ -1107,10 +1078,10 @@
this.$el.find('div.chat-event').remove();
}
}
}
}
if (_.has(item.changed, 'status')) {
this.showStatusMessage(item.get('status'));
}
}
if (_.has(item.changed, 'image')) {
this.renderAvatar();
}
......@@ -1183,7 +1154,7 @@
data.allow_otr = converse.allow_otr && !this.is_chatroom;
data.show_emoticons = converse.show_emoticons;
data.otr_translated_status = OTR_TRANSLATED_MAPPING[data.otr_status];
data.otr_status_class = OTR_CLASS_MAPPING[data.otr_status];
data.otr_status_class = OTR_CLASS_MAPPING[data.otr_status];
this.$el.find('.chat-toolbar').html(this.toolbar_template(data));
}
return this;
......@@ -2348,7 +2319,7 @@
});
this.ChatBoxesView = Backbone.View.extend({
el: '#chatpanel',
el: '#conversejs',
initialize: function () {
// boxesviewinit
......@@ -2503,7 +2474,7 @@
} else if (ask === 'request') {
this.$el.addClass('requesting-xmpp-contact');
this.$el.html(this.request_template(item.toJSON()));
converse.showControlBox();
converse.controlboxtoggle.showControlBox();
} else if (subscription === 'both' || subscription === 'to') {
this.$el.addClass('current-xmpp-contact');
this.$el.html(this.template(
......@@ -3204,7 +3175,8 @@
'submit form#converse-login': 'authenticate'
},
tab_template: _.template(
'<li><a class="current" href="#login">'+__('Sign in')+'</a></li>'),
'<li><a class="current" href="#login">'+__('Sign in')+'</a></li>'
),
template: _.template(
'<form id="converse-login">' +
'<label>'+__('XMPP/Jabber Username:')+'</label>' +
......@@ -3212,11 +3184,12 @@
'<label>'+__('Password:')+'</label>' +
'<input type="password" name="password">' +
'<input class="login-submit" type="submit" value="'+__('Log In')+'">' +
'</form">'),
'</form">'
),
bosh_url_input: _.template(
'<label>'+__('BOSH Service URL:')+'</label>' +
'<input type="text" id="bosh_service_url">'),
'<input type="text" id="bosh_service_url">'
),
connect: function ($form, jid, password) {
if ($form) {
......@@ -3283,18 +3256,69 @@
}
});
this.ControlBoxToggle = Backbone.View.extend({
tagName: 'a',
className: 'toggle-online-users',
id: 'toggle-controlbox',
events: {
'click': 'onClick'
},
attributes: {
'href': "#"
},
template: _.template(
'<strong class="conn-feedback">Toggle chat</strong>'+
'<strong style="display: none" id="online-count">(0)</strong>'
),
initialize: function () {
this.render();
},
render: function () {
$('#conversejs').append(this.$el.html(this.template()));
return this;
},
showControlBox: function () {
var controlbox = converse.chatboxes.get('controlbox');
if (!controlbox) {
converse.chatboxes.add({
id: 'controlbox',
box_id: 'controlbox',
visible: true
});
if (converse.connection) {
converse.chatboxes.get('controlbox').save();
}
} else {
controlbox.trigger('show');
}
},
onClick: function (e) {
e.preventDefault();
if ($("div#controlbox").is(':visible')) {
var controlbox = converse.chatboxes.get('controlbox');
if (converse.connection) {
controlbox.destroy();
} else {
controlbox.trigger('hide');
}
} else {
this.showControlBox();
}
}
});
// Initialization
// --------------
// This is the end of the initialize method.
this.chatboxes = new this.ChatBoxes();
this.chatboxesview = new this.ChatBoxesView({model: this.chatboxes});
$('.toggle-online-users').bind(
'click',
$.proxy(function (e) {
e.preventDefault(); this.toggleControlBox();
}, this)
);
this.controlboxtoggle = new this.ControlBoxToggle();
if ((this.prebind) && (!this.connection)) {
if ((!this.jid) || (!this.sid) || (!this.rid) || (!this.bosh_service_url)) {
this.log('If you set prebind=true, you MUST supply JID, RID and SID values');
......@@ -3305,7 +3329,7 @@
} else if (this.connection) {
this.onConnected();
}
if (this.show_controlbox_by_default) { this.showControlBox(); }
if (this.show_controlbox_by_default) { this.controlboxtoggle.showControlBox(); }
};
return {
'initialize': function (settings, callback) {
......
This diff is collapsed.
......@@ -108,16 +108,19 @@
<li><a class="reference internal" href="#prebind" id="id32">prebind</a></li>
<li><a class="reference internal" href="#show-controlbox-by-default" id="id33">show_controlbox_by_default</a></li>
<li><a class="reference internal" href="#show-only-online-users" id="id34">show_only_online_users</a></li>
<li><a class="reference internal" href="#xhr-user-search" id="id35">xhr_user_search</a></li>
<li><a class="reference internal" href="#xhr-custom-status" id="id35">xhr_custom_status</a></li>
<li><a class="reference internal" href="#xhr-custom-status-url" id="id36">xhr_custom_status_url</a></li>
<li><a class="reference internal" href="#xhr-user-search" id="id37">xhr_user_search</a></li>
<li><a class="reference internal" href="#xhr-user-search-url" id="id38">xhr_user_search_url</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#minification" id="id36">Minification</a><ul>
<li><a class="reference internal" href="#minifying-javascript-and-css" id="id37">Minifying Javascript and CSS</a></li>
<li><a class="reference internal" href="#minification" id="id39">Minification</a><ul>
<li><a class="reference internal" href="#minifying-javascript-and-css" id="id40">Minifying Javascript and CSS</a></li>
</ul>
</li>
<li><a class="reference internal" href="#translations" id="id38">Translations</a></li>
<li><a class="reference internal" href="#translations" id="id41">Translations</a></li>
</ul>
</div>
<div class="section" id="quickstart-to-get-a-demo-up-and-running">
......@@ -152,14 +155,7 @@ bottom of your page (after the closing <em>&lt;/body&gt;</em> element).</p>
});</pre>
</div>
<p>Finally, Converse.js requires a special snippet of HTML markup to be included in your page:</p>
<div class="highlight-python"><pre>&lt;div id="chatpanel"&gt;
&lt;div id="collective-xmpp-chat-data"&gt;&lt;/div&gt;
&lt;div id="toggle-controlbox"&gt;
&lt;a href="#" class="chat toggle-online-users"&gt;
&lt;strong class="conn-feedback"&gt;Toggle chat&lt;/strong&gt; &lt;strong style="display: none" id="online-count"&gt;(0)&lt;/strong&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;</pre>
<div class="highlight-python"><pre>&lt;div id="conversejs"&gt;&lt;/div&gt;</pre>
</div>
<p>The <a class="reference external" href="https://github.com/jcbrand/converse.js/blob/master/index.html">index.html</a> file inside the
Converse.js repository serves as a nice usable example of this.</p>
......@@ -547,23 +543,62 @@ page load.</p>
<p>If set to <tt class="docutils literal"><span class="pre">true</span></tt>, only online users will be shown in the contacts roster.
Users with any other status (e.g. away, busy etc.) will not be shown.</p>
</div>
<div class="section" id="xhr-custom-status">
<h3><a class="toc-backref" href="#id35">xhr_custom_status</a><a class="headerlink" href="#xhr-custom-status" title="Permalink to this headline"></a></h3>
<p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
</div>
<p>This option will let converse.js make an AJAX POST with your changed custom chat status to a
remote server.</p>
</div>
<div class="section" id="xhr-custom-status-url">
<h3><a class="toc-backref" href="#id36">xhr_custom_status_url</a><a class="headerlink" href="#xhr-custom-status-url" title="Permalink to this headline"></a></h3>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
</div>
<p>Default = Empty string</p>
<p>Used only in conjunction with <tt class="docutils literal"><span class="pre">xhr_custom_status</span></tt>.</p>
<p>This is the URL to which the AJAX POST request to set the user&#8217;s custom status
message will be made.</p>
<p>The message itself is sent in the request under the key <tt class="docutils literal"><span class="pre">msg</span></tt>.</p>
</div>
<div class="section" id="xhr-user-search">
<h3><a class="toc-backref" href="#id35">xhr_user_search</a><a class="headerlink" href="#xhr-user-search" title="Permalink to this headline"></a></h3>
<h3><a class="toc-backref" href="#id37">xhr_user_search</a><a class="headerlink" href="#xhr-user-search" title="Permalink to this headline"></a></h3>
<p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
</div>
<p>There are two ways to add users.</p>
<ul class="simple">
<li>The user inputs a valid JID (Jabber ID), and the user is added as a pending contact.</li>
<li>The user inputs some text (for example part of a firstname or lastname), an XHR will be made to a backend, and a list of matches are returned. The user can then choose one of the matches to add as a contact.</li>
<li>The user inputs some text (for example part of a firstname or lastname), an XHR (Ajax Request) will be made to a remote server, and a list of matches are returned. The user can then choose one of the matches to add as a contact.</li>
</ul>
<p>This setting enables the second mechanism, otherwise by default the first will
be used.</p>
<p>This setting enables the second mechanism, otherwise by default the first will be used.</p>
<p><em>What is expected from the remote server?</em></p>
<p>A default JSON encoded list of objects must be returned. Each object
corresponds to a matched user and needs the keys <tt class="docutils literal"><span class="pre">id</span></tt> and <tt class="docutils literal"><span class="pre">fullname</span></tt>.</p>
</div>
<div class="section" id="xhr-user-search-url">
<h3><a class="toc-backref" href="#id38">xhr_user_search_url</a><a class="headerlink" href="#xhr-user-search-url" title="Permalink to this headline"></a></h3>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
</div>
<p>Default = Empty string</p>
<p>Used only in conjunction with <tt class="docutils literal"><span class="pre">xhr_user_search</span></tt>.</p>
<p>This is the URL to which an AJAX GET request will be made to fetch user data from your remote server.
The query string will be included in the request with <tt class="docutils literal"><span class="pre">q</span></tt> as its key.</p>
</div>
</div>
</div>
<div class="section" id="minification">
<h1><a class="toc-backref" href="#id36">Minification</a><a class="headerlink" href="#minification" title="Permalink to this headline"></a></h1>
<h1><a class="toc-backref" href="#id39">Minification</a><a class="headerlink" href="#minification" title="Permalink to this headline"></a></h1>
<div class="section" id="minifying-javascript-and-css">
<h2><a class="toc-backref" href="#id37">Minifying Javascript and CSS</a><a class="headerlink" href="#minifying-javascript-and-css" title="Permalink to this headline"></a></h2>
<h2><a class="toc-backref" href="#id40">Minifying Javascript and CSS</a><a class="headerlink" href="#minifying-javascript-and-css" title="Permalink to this headline"></a></h2>
<p>Please make sure to read the section <a class="reference internal" href="#development">Development</a> and that you have installed
all development dependencies (long story short, you can run <tt class="docutils literal"><span class="pre">npm</span> <span class="pre">install</span></tt>
and then <tt class="docutils literal"><span class="pre">grunt</span> <span class="pre">fetch</span></tt>).</p>
......@@ -580,7 +615,7 @@ using <a class="reference external" href="https://github.com/jrburke/almond">alm
</div>
</div>
<div class="section" id="translations">
<h1><a class="toc-backref" href="#id38">Translations</a><a class="headerlink" href="#translations" title="Permalink to this headline"></a></h1>
<h1><a class="toc-backref" href="#id41">Translations</a><a class="headerlink" href="#translations" title="Permalink to this headline"></a></h1>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Translations take up a lot of space and will bloat your minified file.
......
This diff is collapsed.
......@@ -57,14 +57,7 @@ Finally, Converse.js requires a special snippet of HTML markup to be included in
::
<div id="chatpanel">
<div id="collective-xmpp-chat-data"></div>
<div id="toggle-controlbox">
<a href="#" class="chat toggle-online-users">
<strong class="conn-feedback">Toggle chat</strong> <strong style="display: none" id="online-count">(0)</strong>
</a>
</div>
</div>
<div id="conversejs"></div>
The `index.html <https://github.com/jcbrand/converse.js/blob/master/index.html>`_ file inside the
Converse.js repository serves as a nice usable example of this.
......@@ -222,7 +215,7 @@ but this will require custom code on your server.
Jack Moffitt has a great `blogpost`_ about this and even provides an `example Django application`_ to demonstrate it.
.. Note::
.. Note ::
If you want to enable single session support, make sure to pass **prebind: true**
when you call **converse.initialize** (see ./index.html).
Additionally you need to pass in valid **jid**, **sid**, **rid** and
......@@ -594,7 +587,7 @@ xhr_custom_status
Default = ``false``
Note::
.. Note ::
XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).
This option will let converse.js make an AJAX POST with your changed custom chat status to a
......@@ -603,7 +596,7 @@ remote server.
xhr_custom_status_url
---------------------
Note::
.. Note ::
XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).
Default = Empty string
......@@ -620,7 +613,7 @@ xhr_user_search
Default = ``false``
Note::
.. Note ::
XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).
There are two ways to add users.
......@@ -638,7 +631,7 @@ corresponds to a matched user and needs the keys ``id`` and ``fullname``.
xhr_user_search_url
-------------------
Note::
.. Note ::
XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).
Default = Empty string
......
......@@ -178,11 +178,7 @@
</footer>
</div>
<div id="chatpanel">
<a id="toggle-controlbox" href="#" class="chat toggle-online-users">
<strong class="conn-feedback">Toggle chat</strong> <strong style="display: none" id="online-count">(0)</strong>
</a>
</div>
<div id="conversejs"></div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
......
......@@ -19,7 +19,7 @@
</header>
</div>
<div id="chatpanel" style="width: 100%;">
<div id="conversejs" style="width: 100%;">
<div id="controlbox" class="chatbox" style="opacity: 1; display: inline;">
<div class="chat-head oc-chat-head">
<ul id="controlbox-tabs">
......
......@@ -163,7 +163,7 @@
</footer>
</div>
<div id="chatpanel">
<div id="conversejs">
<div id="collective-xmpp-chat-data"></div>
<div id="toggle-controlbox">
<a href="#" class="chat toggle-online-users">
......
......@@ -46,11 +46,13 @@
// This spec will only pass if the controlbox is not currently
// open yet.
expect($("div#controlbox").is(':visible')).toBe(false);
spyOn(this, 'toggleControlBox').andCallThrough();
spyOn(this, 'showControlBox').andCallThrough();
spyOn(this.controlboxtoggle, 'onClick').andCallThrough();
spyOn(this.controlboxtoggle, 'showControlBox').andCallThrough();
// Redelegate so that the spies are now registered as the event handlers (specifically for 'onClick')
this.controlboxtoggle.delegateEvents();
$('.toggle-online-users').click();
expect(this.toggleControlBox).toHaveBeenCalled();
expect(this.showControlBox).toHaveBeenCalled();
expect(this.controlboxtoggle.onClick).toHaveBeenCalled();
expect(this.controlboxtoggle.showControlBox).toHaveBeenCalled();
expect($("div#controlbox").is(':visible')).toBe(true);
}, converse);
it("can be opened by clicking a DOM element with class 'toggle-online-users'", open_controlbox);
......@@ -345,7 +347,7 @@
it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
var i, t;
spyOn(this.rosterview, 'render').andCallThrough();
spyOn(this, 'showControlBox').andCallThrough();
spyOn(this.controlboxtoggle, 'showControlBox').andCallThrough();
for (i=0; i<req_names.length; i++) {
this.roster.create({
jid: req_names[i].replace(/ /g,'.').toLowerCase() + '@localhost',
......@@ -360,7 +362,7 @@
expect(t).toEqual(req_names.slice(0,i+1).sort().join(''));
// When a requesting contact is added, the controlbox must
// be opened.
expect(this.showControlBox).toHaveBeenCalled();
expect(this.controlboxtoggle.showControlBox).toHaveBeenCalled();
}
}, converse));
......
......@@ -19,7 +19,7 @@
</header>
</div>
<div id="chatpanel">
<div id="conversejs">
<div id="collective-xmpp-chat-data"></div>
<div id="toggle-controlbox">
<a href="#" class="chat toggle-online-users">
......
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