Added close buttons

This commit is contained in:
Mattias Erming 2014-03-14 22:57:54 +01:00
parent dd9dec5d1c
commit aa40319ee9
6 changed files with 445 additions and 41 deletions

View File

@ -273,6 +273,365 @@ hr {
clip: rect(0, 0, 0, 0);
border: 0;
}
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.btn:focus,
.btn:active:focus,
.btn.active:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.btn:hover,
.btn:focus {
color: #333333;
text-decoration: none;
}
.btn:active,
.btn.active {
outline: 0;
background-image: none;
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
.btn.disabled,
.btn[disabled],
fieldset[disabled] .btn {
cursor: not-allowed;
pointer-events: none;
opacity: 0.65;
filter: alpha(opacity=65);
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-default {
color: #333333;
background-color: #ffffff;
border-color: #cccccc;
}
.btn-default:hover,
.btn-default:focus,
.btn-default:active,
.btn-default.active,
.open .dropdown-toggle.btn-default {
color: #333333;
background-color: #ebebeb;
border-color: #adadad;
}
.btn-default:active,
.btn-default.active,
.open .dropdown-toggle.btn-default {
background-image: none;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #ffffff;
border-color: #cccccc;
}
.btn-default .badge {
color: #ffffff;
background-color: #333333;
}
.btn-primary {
color: #ffffff;
background-color: #428bca;
border-color: #357ebd;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.open .dropdown-toggle.btn-primary {
color: #ffffff;
background-color: #3276b1;
border-color: #285e8e;
}
.btn-primary:active,
.btn-primary.active,
.open .dropdown-toggle.btn-primary {
background-image: none;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
background-color: #428bca;
border-color: #357ebd;
}
.btn-primary .badge {
color: #428bca;
background-color: #ffffff;
}
.btn-success {
color: #ffffff;
background-color: #5cb85c;
border-color: #4cae4c;
}
.btn-success:hover,
.btn-success:focus,
.btn-success:active,
.btn-success.active,
.open .dropdown-toggle.btn-success {
color: #ffffff;
background-color: #47a447;
border-color: #398439;
}
.btn-success:active,
.btn-success.active,
.open .dropdown-toggle.btn-success {
background-image: none;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
.btn-success.disabled.active,
.btn-success[disabled].active,
fieldset[disabled] .btn-success.active {
background-color: #5cb85c;
border-color: #4cae4c;
}
.btn-success .badge {
color: #5cb85c;
background-color: #ffffff;
}
.btn-info {
color: #ffffff;
background-color: #5bc0de;
border-color: #46b8da;
}
.btn-info:hover,
.btn-info:focus,
.btn-info:active,
.btn-info.active,
.open .dropdown-toggle.btn-info {
color: #ffffff;
background-color: #39b3d7;
border-color: #269abc;
}
.btn-info:active,
.btn-info.active,
.open .dropdown-toggle.btn-info {
background-image: none;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
.btn-info.disabled.active,
.btn-info[disabled].active,
fieldset[disabled] .btn-info.active {
background-color: #5bc0de;
border-color: #46b8da;
}
.btn-info .badge {
color: #5bc0de;
background-color: #ffffff;
}
.btn-warning {
color: #ffffff;
background-color: #f0ad4e;
border-color: #eea236;
}
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active,
.btn-warning.active,
.open .dropdown-toggle.btn-warning {
color: #ffffff;
background-color: #ed9c28;
border-color: #d58512;
}
.btn-warning:active,
.btn-warning.active,
.open .dropdown-toggle.btn-warning {
background-image: none;
}
.btn-warning.disabled,
.btn-warning[disabled],
fieldset[disabled] .btn-warning,
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
.btn-warning.disabled.active,
.btn-warning[disabled].active,
fieldset[disabled] .btn-warning.active {
background-color: #f0ad4e;
border-color: #eea236;
}
.btn-warning .badge {
color: #f0ad4e;
background-color: #ffffff;
}
.btn-danger {
color: #ffffff;
background-color: #d9534f;
border-color: #d43f3a;
}
.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active,
.btn-danger.active,
.open .dropdown-toggle.btn-danger {
color: #ffffff;
background-color: #d2322d;
border-color: #ac2925;
}
.btn-danger:active,
.btn-danger.active,
.open .dropdown-toggle.btn-danger {
background-image: none;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
.btn-danger.disabled.active,
.btn-danger[disabled].active,
fieldset[disabled] .btn-danger.active {
background-color: #d9534f;
border-color: #d43f3a;
}
.btn-danger .badge {
color: #d9534f;
background-color: #ffffff;
}
.btn-link {
color: #428bca;
font-weight: normal;
cursor: pointer;
border-radius: 0;
}
.btn-link,
.btn-link:active,
.btn-link[disabled],
fieldset[disabled] .btn-link {
background-color: transparent;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-link,
.btn-link:hover,
.btn-link:focus,
.btn-link:active {
border-color: transparent;
}
.btn-link:hover,
.btn-link:focus {
color: #2a6496;
text-decoration: underline;
background-color: transparent;
}
.btn-link[disabled]:hover,
fieldset[disabled] .btn-link:hover,
.btn-link[disabled]:focus,
fieldset[disabled] .btn-link:focus {
color: #999999;
text-decoration: none;
}
.btn-lg {
padding: 10px 16px;
font-size: 18px;
line-height: 1.33;
border-radius: 6px;
}
.btn-sm {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
.btn-xs {
padding: 1px 5px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
.btn-block {
display: block;
width: 100%;
padding-left: 0;
padding-right: 0;
}
.btn-block + .btn-block {
margin-top: 5px;
}
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%;
}
.badge {
display: inline-block;
min-width: 10px;

View File

@ -65,6 +65,9 @@ h2 {
position: absolute;
width: 100%;
}
#chat .network .close {
display: none;
}
#chat .network .users {
display: none;
}
@ -73,15 +76,25 @@ h2 {
}
#chat .title {
border-bottom: 1px solid #ccc;
color: #333;
font-size: 18px;
height: 42px;
line-height: 42px;
height: 43px;
padding-left: 10px;
position: absolute;
top: 0;
width: 100%;
}
#chat .title h1 {
color: #333;
display: inline-block;
font-size: 18px;
line-height: 43px;
}
#chat .title .btn {
float: right;
margin: 6px 6px 0 0;
}
#chat .title .btn:focus {
outline: none;
}
#chat .users {
border-left: 1px solid #ccc;
bottom: 32px;
@ -89,7 +102,7 @@ h2 {
padding: 4px 0;
position: absolute;
right: 0px;
top: 42px;
top: 43px;
width: 159px;
}
#chat .users .user {
@ -105,7 +118,7 @@ h2 {
padding: 4px 8px;
position: absolute;
right: 160px;
top: 42px;
top: 43px;
word-wrap: break-word;
z-index: 0;
}

View File

@ -29,7 +29,10 @@
<script type="text/html" id="channels">
{{#channels}}
<div class="window {{type}}" data-id="{{id}}">
<h1 class="title">{{name}}</h1>
<div class="title">
<h1>{{name}}</h1>
<button class="close btn btn-danger btn-sm ">Leave</button>
</div>
<div class="users">
{{> users}}
</div>
@ -56,7 +59,7 @@
{{#messages}}
<div class="message {{type}}">
<span class="time">{{time}}</span>
<span class="user">{{user}}</span>
<span class="user">{{mode}}{{user}}</span>
<span class="text">{{text}}</span>
</div>
{{/messages}}

View File

@ -2,10 +2,10 @@ $(function() {
var socket = io.connect("");
$.each([
"networks",
"channels",
"users",
"messages"
"NETWORKS",
"CHANNELS",
"MESSAGES",
"USERS"
], function(i, type) {
socket.on(type, function(data) {
render(type, data);
@ -28,7 +28,7 @@ $(function() {
}
switch (type) {
case "networks":
case "NETWORKS":
var partials = {
users: users,
messages: messages
@ -53,12 +53,12 @@ $(function() {
.bringToTop();
break;
case "users":
case "USERS":
target = target.find(".users");
target.html(Mustache.render(users, {users: data.data}));
break;
case "messages":
case "MESSAGES":
target = target.find(".messages");
target.append(Mustache.render(messages, {messages: data.data}));
break;
@ -76,16 +76,22 @@ $(function() {
});
}
});
chat.on("click", ".close", function() {
var btn = $(this);
btn.prop("disabled", true);
socket.emit("input", {
id: btn.closest(".window").data("id"),
text: "/leave"
});
});
sidebar.on("click", ".channel", function(e) {
e.preventDefault();
sidebar.find(".active").removeClass("active");
$(this).addClass("active");
chat.find(".window[data-id='" + $(this).data("id") + "']")
.bringToTop();
// Prevent link from triggering
e.preventDefault();
});
});

View File

@ -13,7 +13,6 @@ var id = 1;
models.User = Backbone.Model.extend({
defaults: {
mode: "",
name: ""
}
});
@ -21,7 +20,6 @@ models.User = Backbone.Model.extend({
models.UserCollection = Backbone.Collection.extend({
model: models.User,
comparator: function(user) {
// Keep the collection sorted in alphabetical order
return user.get("name");
}
});
@ -54,7 +52,7 @@ models.Channel = Backbone.Model.extend({
this.set("users", new models.UserCollection());
this.get("users").on("all", function() {
this.trigger("users", {
this.trigger("USERS", {
target: this.get("id"),
data: this.get("users")
});
@ -62,7 +60,7 @@ models.Channel = Backbone.Model.extend({
this.set("messages", new models.MessageCollection());
this.get("messages").on("all", function() {
this.trigger("messages", {
this.trigger("MESSAGES", {
target: this.get("id"),
data: this.get("messages").last()
});
@ -86,10 +84,10 @@ models.Network = Backbone.Model.extend({
this.set("channels", new models.ChannelCollection());
this.get("channels").on("all", function(type, data) {
if (type == "users" || type == "messages") {
if (type == "USERS" || type == "MESSAGES") {
this.trigger(type, data);
} else {
this.trigger("channels");
this.trigger("CHANNELS");
}
}, this);
this.get("channels").add(new models.Channel({

View File

@ -19,13 +19,12 @@ Server.prototype.listen = function(port) {
.listen(port);
this.networks.on("all", function(type, data) {
if (type == "users" || type == "messages") {
if (type == "USERS" || type == "MESSAGES") {
this.sockets.emit(type, data);
} else {
// Network and channel events will force
// a full refresh.
// Force a refresh on network and channel events.
this.sockets.emit(
"networks", self.networks
"NETWORKS", self.networks
);
}
}, this);
@ -33,7 +32,7 @@ Server.prototype.listen = function(port) {
this.sockets = io.listen(http, {log: false}).sockets;
this.sockets.on("connection", function(socket) {
socket.emit(
"networks", self.networks
"NETWORKS", self.networks
);
socket.on(
"input",
@ -106,6 +105,21 @@ function handleInput(input) {
}
break;
case "UNQUERY":
case "LEAVE":
var channel = target.channel;
if (channel.get("name").charAt(0) == "#") {
handleInput.call(this, {
id: input.id,
text: "/part"
});
} else if (channel.get("type") != "network") {
network.get("channels").remove(
channel
);
}
break;
case "NOTICE":
var irc = network.irc;
if (!argv[2] || typeof irc === "undefined") {
@ -266,8 +280,15 @@ function handleEvent(argv) {
);
}
var mode;
var user = channel.get("users").findWhere({name: argv.nick});
if (typeof user !== "undefined") {
mode = user.get("mode");
}
channel.get("messages").add(
new models.Message({
mode: mode,
user: argv.nick,
text: message
})
@ -408,19 +429,23 @@ function handleEvent(argv) {
if (typeof channel === "undefined") {
break;
}
var target = argv.args[2] || argv.args[0];
var messages = channel.get("messages");
messages.add(
new models.Message({
user: argv.nick,
text: "sets mode: " + argv.args[1] + " " + argv.args[2],
text: "sets mode: " + argv.args[1] + " " + target,
type: "mode"
})
);
var irc = network.irc;
if (typeof irc !== "undefined") {
irc.send("NAMES", argv.args[0]);
if (argv.args[2] && typeof irc !== "undefined") {
irc.send(
"NAMES",
channel.get("name")
);
}
break;
@ -463,13 +488,12 @@ function handleEvent(argv) {
);
}
var names = argv.args[3].split(' ');
var first = names[0].replace(/^\W/, ''); // Strip mode prefixes
if (first == network.get("nick")) {
users.reset();
if (typeof rpl_namreply === "undefined") {
channel.get("users").reset({silent: true});
}
rpl_namreply = true;
var names = argv.args[3].split(' ');
for (var i in names) {
users.add(
new models.User({name: names[i]}), {
@ -482,7 +506,8 @@ function handleEvent(argv) {
case "rpl_endofnames":
var channel = channels.findWhere({name: argv.args[1]});
var users = channel.get("users");
delete rpl_namreply;
users.trigger(
"add", {}, users
);