Mobile UI example
authorDarren <darren@darrenwhitlen.com>
Mon, 24 Oct 2011 14:28:52 +0000 (15:28 +0100)
committerDarren <darren@darrenwhitlen.com>
Mon, 24 Oct 2011 14:28:52 +0000 (15:28 +0100)
client/js/mobile.html [new file with mode: 0644]
client/js/mobile.js [new file with mode: 0644]

diff --git a/client/js/mobile.html b/client/js/mobile.html
new file mode 100644 (file)
index 0000000..95806ae
--- /dev/null
@@ -0,0 +1,73 @@
+<!DOCTYPE html> \r
+<html> \r
+<head>\r
+\r
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"> \r
+<meta name="viewport" content="width=device-width, user-scalable=no" />\r
+\r
+<title>KiwiIRC</title> \r
+\r
+<script type='text/javascript' src='http://code.jquery.com/jquery-1.6.3.js'></script>\r
+<script type='text/javascript' src='jquery.json-2.2.min.js'></script>\r
+<script type='text/javascript' src='/socket.io/socket.io.js'></script>\r
+<script type='text/javascript' src='mobile.js'></script> \r
+<script type='text/javascript' src='gateway.js'></script> \r
+\r
+<script type='text/javascript'>\r
+    $(function () {\r
+        console.log('starting');\r
+        kiwi.init();\r
+        kiwi.gateway.nick = "efhoerufre";\r
+        kiwi.gateway.start('/kiwi');\r
+    });\r
+\r
+    function k(){\r
+        console.log('goooing gogo');\r
+        kiwi.gateway.connect('irc.anonnet.org', 6667, false);\r
+    }\r
+</script>\r
+<style type='text/css'> \r
+* { margin:0px; padding:0px; }\r
+\r
+body { font-family:arial; font-size:14px; color:rgb(233,242,237); background:rgb(138,150,143); }\r
+\r
+.fixed { position:fixed; width:100%; background:rgb(138,150,143); z-index:1; }\r
+#hover_top { top:0px; }\r
+#hover_bottom { bottom:0px; background:red; }\r
+\r
+#nav { padding:10px 1em 0px 1em; }\r
+#nav a { display:block; float:right; margin-right:1em; }\r
+\r
+#chan_list { margin:1em 0px 1em 0px; }\r
+#chan_list li {\r
+    display:inline; list-style:none;\r
+    padding:5px 3px; margin:0.5em;\r
+    border:1px solid gray; border-radius:3px;\r
+    line-height:2.5em;\r
+}\r
+\r
+#msgs { position:absolute; width:100%; top:0px; z-index:0; }\r
+#msgs > div { display:none; }\r
+#msgs > div.active { display:block; }\r
+.msg { border-bottom:1px solid gray; padding:4px 3px; }\r
+.msg .time { color: gray; display:block; font-size:0.9em; display:none; }\r
+.msg .nick { color: rgb(199,199,199); }\r
+.msg .body { margin-left:2em; white-space:pre-wrap; word-wrap:break-word; }\r
+\r
+#msginp { width:100%; border:0px; margin:0px; padding:5px 3px; }\r
+</style>  \r
+</head> \r
+<body>\r
+\r
+    <div id="hover_top" class="fixed">\r
+        <div id="nav">KiwiIRC - irc.server.com <button onclick="k();">Connect</button><a>Opts</a> </div>\r
+        <ul id="chan_list"></ul>\r
+    </div>\r
+\r
+    <div id="hover_bottom" class="fixed">\r
+        <input id="msginp" type="text" value="" />\r
+    </div>\r
+\r
+    <div id="msgs"></div>\r
+</body>\r
+</html> 
\ No newline at end of file
diff --git a/client/js/mobile.js b/client/js/mobile.js
new file mode 100644 (file)
index 0000000..65d0aea
--- /dev/null
@@ -0,0 +1,396 @@
+if (typeof String.prototype.lpad === 'undefined') {\r
+    String.prototype.lpad = function (length, character) {\r
+        var padding = "",\r
+            i;\r
+        for (i = 0; i < length; i++) {\r
+            padding += character;\r
+        }\r
+        return (padding + this).slice(-length);\r
+    };\r
+}\r
+\r
+\r
+var kiwi = {};\r
+kiwi.objects = {};\r
+kiwi.ui = {};\r
+kiwi.events = {};\r
+kiwi.gateway = {};\r
+\r
+\r
+/**\r
+ * Any user interface methods\r
+ */\r
+kiwi.ui = {\r
+    views: {},\r
+    current_view: null,\r
+\r
+    doLayout: function () {\r
+        var msgs = $('#msgs');\r
+        msgs.css('padding-top', $('#hover_top').outerHeight());\r
+        msgs.css('padding-bottom', $('#hover_bottom').outerHeight());\r
+    },\r
+\r
+\r
+    formatIRCMsg: function (msg) {\r
+        var re, next;\r
+\r
+        if ((!msg) || (typeof msg !== 'string')) {\r
+            return '';\r
+        }\r
+\r
+        // bold\r
+        if (msg.indexOf(String.fromCharCode(2)) !== -1) {\r
+            next = '<b>';\r
+            while (msg.indexOf(String.fromCharCode(2)) !== -1) {\r
+                msg = msg.replace(String.fromCharCode(2), next);\r
+                next = (next === '<b>') ? '</b>' : '<b>';\r
+            }\r
+            if (next === '</b>') {\r
+                msg = msg + '</b>';\r
+            }\r
+        }\r
+\r
+        // underline\r
+        if (msg.indexOf(String.fromCharCode(31)) !== -1) {\r
+            next = '<u>';\r
+            while (msg.indexOf(String.fromCharCode(31)) !== -1) {\r
+                msg = msg.replace(String.fromCharCode(31), next);\r
+                next = (next === '<u>') ? '</u>' : '<u>';\r
+            }\r
+            if (next === '</u>') {\r
+                msg = msg + '</u>';\r
+            }\r
+        }\r
+\r
+        // colour\r
+        /**\r
+        *   @inner\r
+        */\r
+        msg = (function (msg) {\r
+            var replace, colourMatch, col, i, match, to, endCol, fg, bg, str;\r
+            replace = '';\r
+            /**\r
+            *   @inner\r
+            */\r
+            colourMatch = function (str) {\r
+                var re = /^\x03([0-9][0-5]?)(,([0-9][0-5]?))?/;\r
+                return re.exec(str);\r
+            };\r
+            /**\r
+            *   @inner\r
+            */\r
+            col = function (num) {\r
+                switch (parseInt(num, 10)) {\r
+                case 0:\r
+                    return '#FFFFFF';\r
+                case 1:\r
+                    return '#000000';\r
+                case 2:\r
+                    return '#000080';\r
+                case 3:\r
+                    return '#008000';\r
+                case 4:\r
+                    return '#FF0000';\r
+                case 5:\r
+                    return '#800040';\r
+                case 6:\r
+                    return '#800080';\r
+                case 7:\r
+                    return '#FF8040';\r
+                case 8:\r
+                    return '#FFFF00';\r
+                case 9:\r
+                    return '#80FF00';\r
+                case 10:\r
+                    return '#008080';\r
+                case 11:\r
+                    return '#00FFFF';\r
+                case 12:\r
+                    return '#0000FF';\r
+                case 13:\r
+                    return '#FF55FF';\r
+                case 14:\r
+                    return '#808080';\r
+                case 15:\r
+                    return '#C0C0C0';\r
+                default:\r
+                    return null;\r
+                }\r
+            };\r
+            if (msg.indexOf('\x03') !== -1) {\r
+                i = msg.indexOf('\x03');\r
+                replace = msg.substr(0, i);\r
+                while (i < msg.length) {\r
+                    /**\r
+                    *   @inner\r
+                    */\r
+                    match = colourMatch(msg.substr(i, 6));\r
+                    if (match) {\r
+                        //console.log(match);\r
+                        // Next colour code\r
+                        to = msg.indexOf('\x03', i + 1);\r
+                        endCol = msg.indexOf(String.fromCharCode(15), i + 1);\r
+                        if (endCol !== -1) {\r
+                            if (to === -1) {\r
+                                to = endCol;\r
+                            } else {\r
+                                to = ((to < endCol) ? to : endCol);\r
+                            }\r
+                        }\r
+                        if (to === -1) {\r
+                            to = msg.length;\r
+                        }\r
+                        //console.log(i, to);\r
+                        fg = col(match[1]);\r
+                        bg = col(match[3]);\r
+                        str = msg.substring(i + 1 + match[1].length + ((bg !== null) ? match[2].length + 1 : 0), to);\r
+                        //console.log(str);\r
+                        replace += '<span style="' + ((fg !== null) ? 'color: ' + fg + '; ' : '') + ((bg !== null) ? 'background-color: ' + bg + ';' : '') + '">' + str + '</span>';\r
+                        i = to;\r
+                    } else {\r
+                        if ((msg[i] !== '\x03') && (msg[i] !== String.fromCharCode(15))) {\r
+                            replace += msg[i];\r
+                        }\r
+                        i++;\r
+                    }\r
+                }\r
+                return replace;\r
+            }\r
+            return msg;\r
+        }(msg));\r
+        \r
+        return msg;\r
+    },\r
+\r
+\r
+    run: function (msg) {\r
+        var parts, dest, t, pos, textRange, plugin_event, msg_sliced, tab, nick;\r
+\r
+        if (msg.substring(0, 1) === '/') {\r
+            console.log("running " + msg);\r
+            parts = msg.split(' ');\r
+            switch (parts[0].toLowerCase()) {\r
+            case '/nick':\r
+                if (parts[1] === undefined) {\r
+                    console.log("calling show nick");\r
+                    kiwi.front.ui.showChangeNick();\r
+                } else {\r
+                    console.log("sending nick");\r
+                    kiwi.gateway.nick(msg.substring(1));\r
+                }\r
+                break;\r
+                \r
+            case '/q':\r
+            case '/query':\r
+                if (typeof parts[1] !== "undefined") {\r
+                    tab = new kiwi.objects.MessageView(parts[1]);\r
+                }\r
+                break;\r
+                \r
+            case '/k':\r
+            case '/kick':\r
+                if (typeof parts[1] === 'undefined') {\r
+                    return;\r
+                }\r
+                t = msg.split(' ', 3);\r
+                nick = t[1];\r
+                kiwi.gateway.kick(Tabview.getCurrent().title, nick, t[2]);\r
+                break;\r
+                \r
+            case '/j':\r
+            case '/join':\r
+                kiwi.ui.joinChannel(parts[1]);\r
+                break;\r
+\r
+            case '/part':\r
+                break;\r
+\r
+            case '/quote':\r
+                kiwi.gateway.raw(msg.replace(/^\/quote /i, ''));\r
+                break;\r
+                \r
+            case '/me':\r
+                tab = kiwi.objects.getCurrent();\r
+                kiwi.gateway.ctcp(true, 'ACTION', tab.title, msg.substring(4));\r
+                tab.addMsg(' ', '* ' + kiwi.gateway.nick + ' ' + msg.substring(4));\r
+                break;\r
+\r
+            case '/quit':\r
+                kiwi.gateway.quit(parts.slice(1).join(' '));\r
+                break;\r
+            }\r
+\r
+        } else {\r
+            if (msg.trim() === '') {\r
+                return;\r
+            }\r
+            tab = kiwi.objects.MessageView.getCurrent();\r
+            if (tab.title !== 'server') {\r
+                kiwi.gateway.privmsg(tab.title, msg);\r
+                tab.addMsg(kiwi.gateway.nick, msg);\r
+            }\r
+        }\r
+\r
+    },\r
+\r
+    joinChannel: function (chan_name) {\r
+        var chans = chan_name.split(','),\r
+            i,\r
+            chan,\r
+            tab;\r
+        for (i in chans) {\r
+            chan = chans[i];\r
+            tab = kiwi.objects.MessageView.get(chan);\r
+            if ((!tab) || (tab.safe_to_close === true)) {\r
+                kiwi.gateway.join(chan);\r
+                tab = new kiwi.objects.MessageView(chan);\r
+            }\r
+        }\r
+\r
+        if (tab) {\r
+            tab.show();\r
+        }\r
+    },\r
+};\r
+\r
+\r
+/**\r
+ * Entry point for Kiwi\r
+ */\r
+kiwi.init = function () {\r
+    var server,\r
+        gateway = $(kiwi.gateway);\r
+    \r
+    server = new kiwi.objects.MessageView('server');\r
+    server.show();\r
+    server.addMsg('', 'KiwiIRC Mobile client');\r
+    console.log = function (w) {\r
+        server.addMsg('log', w);\r
+    }\r
+\r
+    kiwi.ui.doLayout();\r
+\r
+    $('#msginp').bind('keydown', function (e) {\r
+        switch (true) {\r
+            case e.which === 13:            // return\r
+                msg = $(this).val();\r
+                msg = msg.trim();\r
+\r
+                kiwi.ui.run(msg);\r
+                $(this).val('');\r
+\r
+                break;\r
+        }\r
+    });\r
+\r
+    gateway.bind('onconnect', function (e, data) {\r
+        kiwi.objects.MessageView.getServer().addMsg('', 'Connected :)');\r
+    });\r
+    gateway.bind('onmotd', function (e, data) {\r
+        kiwi.objects.MessageView.getServer().addMsg('', data.msg);\r
+    });\r
+    gateway.bind('onmsg', function (e, data) {\r
+        var destination, plugin_event, tab;\r
+        // Is this message from a user?\r
+        if (data.channel === kiwi.gateway.nick) {\r
+            destination = data.nick.toLowerCase();\r
+        } else {\r
+            destination = data.channel.toLowerCase();\r
+        }\r
+        \r
+        tab = kiwi.objects.MessageView.get(destination);\r
+        if (!tab) {\r
+            tab = new kiwi.objects.MessageView(destination);\r
+        }\r
+        tab.addMsg(data.nick, data.msg);\r
+    });\r
+};\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ * Basic container that holds content on the page\r
+ */\r
+kiwi.objects.View = function (title) {\r
+    var that = this;\r
+\r
+    this.title = title;\r
+    this.tab = $('<li>' + title + '</li>');\r
+    this.content = $('<div></div>');\r
+\r
+    $('#chan_list').append(this.tab);\r
+    $('#msgs').append(this.content);\r
+\r
+    this.tab.click(function () { that.show.call(that); });\r
+};\r
+kiwi.objects.View.prototype.title = 'View';\r
+kiwi.objects.View.prototype.tab = null;\r
+kiwi.objects.View.prototype.content = null;\r
+kiwi.objects.View.prototype.show = function () {\r
+    $('#msgs > div.active').removeClass('active');\r
+    this.content.addClass('active');\r
+    kiwi.ui.current_view = this;\r
+    this.scrollBottom();\r
+}\r
+kiwi.objects.View.prototype.scrollBottom = function () {\r
+    $(window).scrollTop($(document).height());\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ * A type of View that contains mainly messages\r
+ */\r
+kiwi.objects.MessageView = function (name) {\r
+    // Call the parent constructor\r
+    kiwi.objects.View.prototype.constructor.call(this, name);\r
+\r
+    // Add this MessageView to the array\r
+    kiwi.ui.views[name.toLowerCase()] = this;\r
+}\r
+kiwi.objects.MessageView.prototype = new kiwi.objects.View();\r
+kiwi.objects.MessageView.prototype.addMsg = function (nick, text) {\r
+    var msg, d = new Date(),\r
+        time;\r
+    \r
+    msg = $('<div class="msg"><span class="time"></span><span class="nick"></span><span class="body"></span></div>');\r
+    time = d.getHours().toString().lpad(2, "0") + ":" + d.getMinutes().toString().lpad(2, "0") + ":" + d.getSeconds().toString().lpad(2, "0");\r
+\r
+    $('.time', msg).text(time);\r
+    $('.nick', msg).text(nick);\r
+    $('.body', msg).text(kiwi.ui.formatIRCMsg(text));\r
+    this.content.append(msg);\r
+\r
+    this.scrollBottom();\r
+}\r
+// Static functions\r
+kiwi.objects.MessageView.exists = function (name) {\r
+    if ((!name) || (typeof name !== 'string')) {\r
+        return false;\r
+    }\r
+    var ret = (typeof kiwi.ui.views[name.toLowerCase()] !== 'undefined');\r
+    return ret;\r
+};\r
+kiwi.objects.MessageView.get = function (name) {\r
+    if (kiwi.objects.MessageView.exists(name)) {\r
+        var ret = kiwi.ui.views[name.toLowerCase()];\r
+        return ret;\r
+    } else {\r
+        return null;\r
+    }\r
+};\r
+kiwi.objects.MessageView.getServer = function () {\r
+    return kiwi.ui.views.server;\r
+};\r
+kiwi.objects.MessageView.getAlls = function () {\r
+    return kiwi.ui.views;\r
+};\r
+kiwi.objects.MessageView.getCurrent = function () {\r
+    return kiwi.ui.current_view;\r
+};
\ No newline at end of file