diff --git a/package.json b/package.json index 7674b60..b9916b6 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,14 @@ { -"name": "Web4.0", +"name": "Hookio-sparql-example", "version" : "0.0.1", "dependencies":{ "socket.io":"*", "hook.io":"*", "Hook.io-mailer":"git+https://github.com/balkian/Hookio-Mailer.git" + "express": "2.5.5", + "jade": "0.16.4", + "stylus": "0.19.0", + "nib": "0.2.0" + } } diff --git a/web/app.js b/web/app.js new file mode 100644 index 0000000..55024d3 --- /dev/null +++ b/web/app.js @@ -0,0 +1,81 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , stylus = require('stylus') + , nib = require('nib') + , sio = require('../../lib/socket.io'); + +/** + * App. + */ + +var app = express.createServer(); + +/** + * App configuration. + */ + +app.configure(function () { + app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })); + app.use(express.static(__dirname + '/public')); + app.set('views', __dirname); + app.set('view engine', 'jade'); + + function compile (str, path) { + return stylus(str) + .set('filename', path) + .use(nib()); + }; +}); + +/** + * App routes. + */ + +app.get('/', function (req, res) { + res.render('index', { layout: false }); +}); + +/** + * App listen. + */ + +app.listen(3000, function () { + var addr = app.address(); + console.log(' app listening on http://' + addr.address + ':' + addr.port); +}); + +/** + * Socket.IO server (single process only) + */ + +var io = sio.listen(app) + , nicknames = {}; + +io.sockets.on('connection', function (socket) { + socket.on('user message', function (msg) { + console.log('User message:'+msg); + //socket.broadcast.emit('user message', socket.nickname, msg); + }); + + socket.on('nickname', function (nick, fn) { + if (nicknames[nick]) { + fn(true); + } else { + fn(false); + nicknames[nick] = socket.nickname = nick; + //socket.broadcast.emit('announcement', nick + ' connected'); + //io.sockets.emit('nicknames', nicknames); + } + }); + + socket.on('disconnect', function () { + if (!socket.nickname) return; + + delete nicknames[socket.nickname]; + // socket.broadcast.emit('announcement', socket.nickname + ' disconnected'); + // socket.broadcast.emit('nicknames', nicknames); + }); +}); diff --git a/web/index.jade b/web/index.jade new file mode 100644 index 0000000..0633d8b --- /dev/null +++ b/web/index.jade @@ -0,0 +1,83 @@ +doctype 5 +html + head + link(href='/stylesheets/style.css', rel='stylesheet') + script(src='http://code.jquery.com/jquery-1.6.1.min.js') + script(src='/socket.io/socket.io.js') + script + // socket.io specific code + var socket = io.connect(); + + socket.on('connect', function () { + $('#chat').addClass('connected'); + }); + + socket.on('announcement', function (msg) { + $('#lines').append($('

').append($('').text(msg))); + }); + + socket.on('nicknames', function (nicknames) { + $('#nicknames').empty().append($('Online: ')); + for (var i in nicknames) { + $('#nicknames').append($('').text(nicknames[i])); + } + }); + + socket.on('user message', message); + socket.on('reconnect', function () { + $('#lines').remove(); + message('System', 'Reconnected to the server'); + }); + + socket.on('reconnecting', function () { + message('System', 'Attempting to re-connect to the server'); + }); + + socket.on('error', function (e) { + message('System', e ? e : 'A unknown error occurred'); + }); + + function message (from, msg) { + $('#lines').append($('

').append($('').text(from), msg)); + } + + // dom manipulation + $(function () { + $('#set-nickname').submit(function (ev) { + socket.emit('nickname', $('#nick').val(), function (set) { + if (!set) { + clear(); + return $('#chat').addClass('nickname-set'); + } + $('#nickname-err').css('visibility', 'visible'); + }); + return false; + }); + + $('#send-message').submit(function () { + message('me', $('#message').val()); + socket.emit('user message', $('#message').val()); + clear(); + $('#lines').get(0).scrollTop = 10000000; + return false; + }); + + function clear () { + $('#message').val('').focus(); + }; + }); + body + #chat + #nickname + form.wrap#set-nickname + p Please type in your nickname and press enter. + input#nick + p#nickname-err Nickname already in use + #connecting + .wrap Connecting to socket.io server + #messages + #nicknames + #lines + form#send-message + input#message + button Send diff --git a/web/public/stylesheets/mixins.styl b/web/public/stylesheets/mixins.styl new file mode 100644 index 0000000..fb5644c --- /dev/null +++ b/web/public/stylesheets/mixins.styl @@ -0,0 +1,96 @@ +border-radius(n) + -webkit-border-radius n + -moz-border-radius n + border-radius n + +// replace str with val + +replace(expr, str, val) + expr = clone(expr) + for e, i in expr + if str == e + expr[i] = val + expr + +// normalize gradient point (webkit) + +grad-point(pos) + if length(pos) == 1 + return left pos if pos in (top bottom) + return pos top if pos in (left right) + else if pos[0] in (top bottom) + pos[1] pos[0] + else + pos + +// implicit color stop position + +pos-in-stops(i, stops) + len = length(stops) + if len - 1 == i + 100% + else if i + unit(i / len * 100, '%') + else + 0% + +// normalize color stops +// - (color pos) -> (pos color) +// - (color) -> (implied-pos color) + +normalize-stops(stops) + stops = clone(stops) + for stop, i in stops + if length(stop) == 1 + color = stop[0] + stop[0] = pos-in-stops(i, stops) + stop[1] = color + else if typeof(stop[1]) == 'unit' + pos = stop[1] + stop[1] = stop[0] + stop[0] = pos + stops + +// join color stops with the given translation function + +join-stops(stops, translate) + str = '' + len = length(stops) + for stop, i in stops + str += ', ' if i + pos = stop[0] + color = stop[1] + str += translate(color, pos) + unquote(str) + +// webkit translation function + +webkit-stop(color, pos) + s('color-stop(%d, %s)', pos / 100, color) + +// mozilla translation function + +moz-stop(color, pos) + s('%s %s', color, pos) + +// create a linear gradient with the given start +// position, followed by color stops + +linear-gradient(start, stops...) + error('color stops required') unless length(stops) + prop = current-property[0] + val = current-property[1] + stops = normalize-stops(stops) + + // webkit + end = grad-point(opposite-position(start)) + webkit = s('-webkit-gradient(linear, %s, %s, %s)', grad-point(start), end, join-stops(stops, webkit-stop)) + add-property(prop, replace(val, '__CALL__', webkit)) + + // moz + stops = join-stops(stops, moz-stop) + moz = s('-moz-linear-gradient(%s, %s)', start, stops) + add-property(prop, replace(val, '__CALL__', moz)) + + // literal + s('linear-gradient(%s, %s)', start, stops) diff --git a/web/public/stylesheets/style.css b/web/public/stylesheets/style.css new file mode 100644 index 0000000..42cf98f --- /dev/null +++ b/web/public/stylesheets/style.css @@ -0,0 +1,188 @@ +#chat, +#nickname, +#messages { + width: 600px; +} +#chat { + position: relative; + border: 1px solid #ccc; +} +#nickname, +#connecting { + position: absolute; + height: 410px; + z-index: 100; + left: 0; + top: 0; + background: #fff; + text-align: center; + width: 600px; + font: 15px Georgia; + color: #666; + display: block; +} +#nickname .wrap, +#connecting .wrap { + padding-top: 150px; +} +#nickname input { + border: 1px solid #ccc; + padding: 10px; +} +#nickname input:focus { + border-color: #999; + outline: 0; +} +#nickname #nickname-err { + color: #8b0000; + font-size: 12px; + visibility: hidden; +} +.connected #connecting { + display: none; +} +.nickname-set #nickname { + display: none; +} +#messages { + height: 380px; + background: #eee; +} +#messages em { + text-shadow: 0 1px 0 #fff; + color: #999; +} +#messages p { + padding: 0; + margin: 0; + font: 12px Helvetica, Arial; + padding: 5px 10px; +} +#messages p b { + display: inline-block; + padding-right: 10px; +} +#messages p:nth-child(even) { + background: #fafafa; +} +#messages #nicknames { + background: #ccc; + padding: 2px 4px 4px; + font: 11px Helvetica; +} +#messages #nicknames span { + color: #000; +} +#messages #nicknames b { + display: inline-block; + color: #fff; + background: #999; + padding: 3px 6px; + margin-right: 5px; + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + text-shadow: 0 1px 0 #666; +} +#messages #lines { + height: 355px; + overflow: auto; + overflow-x: hidden; + overflow-y: auto; +} +#messages #lines::-webkit-scrollbar { + width: 6px; + height: 6px; +} +#messages #lines::-webkit-scrollbar-button:start:decrement, +#messages #lines ::-webkit-scrollbar-button:end:increment { + display: block; + height: 10px; +} +#messages #lines::-webkit-scrollbar-button:vertical:increment { + background-color: #fff; +} +#messages #lines::-webkit-scrollbar-track-piece { + background-color: #fff; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:vertical { + height: 50px; + background-color: #ccc; + -webkit-border-radius: 3px; +} +#messages #lines::-webkit-scrollbar-thumb:horizontal { + width: 50px; + background-color: #fff; + -webkit-border-radius: 3px; +} +#send-message { + background: #fff; + position: relative; +} +#send-message input { + border: none; + height: 30px; + padding: 0 10px; + line-height: 30px; + vertical-align: middle; + width: 580px; +} +#send-message input:focus { + outline: 0; +} +#send-message button { + position: absolute; + top: 5px; + right: 5px; +} +button { + margin: 0; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + display: inline-block; + text-decoration: none; + background: #43a1f7; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #377ad0)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #377ad0 100%); + background: linear-gradient(top, #43a1f7 0%, #377ad0 100%); + border: 1px solid #2e70c4; + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; + color: #fff; + font-family: "lucida grande", sans-serif; + font-size: 11px; + font-weight: normal; + line-height: 1; + padding: 3px 10px 5px 10px; + text-align: center; + text-shadow: 0 -1px 1px #2d6dc0; +} +button:hover, +button.hover { + background: darker; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #2e70c4)); + background: -webkit-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: -moz-linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + background: linear-gradient(top, #43a1f7 0%, #2e70c4 100%); + border: 1px solid #2e70c4; + cursor: pointer; + text-shadow: 0 -1px 1px #2c6bbb; +} +button:active, +button.active { + background: #2e70c4; + border: 1px solid #2e70c4; + border-bottom: 1px solid #2861aa; + text-shadow: 0 -1px 1px #2b67b5; +} +button:focus, +button.focus { + outline: none; + -webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + -moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; + box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0; +} diff --git a/web/public/stylesheets/style.styl b/web/public/stylesheets/style.styl new file mode 100644 index 0000000..6289c94 --- /dev/null +++ b/web/public/stylesheets/style.styl @@ -0,0 +1,118 @@ +@import 'nib' + +#chat, #nickname, #messages + width 600px + +#chat + position relative + border 1px solid #ccc + +#nickname, #connecting + position absolute + height 410px + z-index 100 + left 0 + top 0 + background #fff + text-align center + width 600px + font 15px Georgia + color #666 + display block + .wrap + padding-top 150px + +#nickname + input + border 1px solid #ccc + padding 10px + &:focus + border-color #999 + outline 0 + #nickname-err + color darkred + font-size 12px + visibility hidden + +.connected + #connecting + display none + +.nickname-set + #nickname + display none + +#messages + height 380px + background #eee + em + text-shadow 0 1px 0 #fff + color #999 + p + padding 0 + margin 0 + font 12px Helvetica, Arial + padding 5px 10px + b + display inline-block + padding-right 10px + p:nth-child(even) + background #fafafa + #nicknames + background #ccc + padding 2px 4px 4px + font 11px Helvetica + span + color black + b + display inline-block + color #fff + background #999 + padding 3px 6px + margin-right 5px + border-radius 10px + text-shadow 0 1px 0 #666 + #lines + height 355px + overflow auto + overflow-x hidden + overflow-y auto + &::-webkit-scrollbar + width 6px + height 6px + &::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment + display block + height 10px + &::-webkit-scrollbar-button:vertical:increment + background-color #fff + &::-webkit-scrollbar-track-piece + background-color #fff + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:vertical + height 50px + background-color #ccc + -webkit-border-radius 3px + &::-webkit-scrollbar-thumb:horizontal + width 50px + background-color #fff + -webkit-border-radius 3px + +#send-message + background #fff + position relative + input + border none + height 30px + padding 0 10px + line-height 30px + vertical-align middle + width 580px + &:focus + outline 0 + button + position absolute + top 5px + right 5px + +button + download-button()