moksha/lib
by Luke Macken
moksha/lib/base.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
New commits:
commit bdc0667fcd28bbbf688b7ec0e6ec2dc525efd4bb
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:47:53 2009 -0400
Fix some comment formatting
diff --git a/moksha/lib/base.py b/moksha/lib/base.py
index 45fa8fc..c9c7a4f 100644
--- a/moksha/lib/base.py
+++ b/moksha/lib/base.py
@@ -59,13 +59,13 @@ class BaseController(TGController):
# url is already taken
tmpl_context.get_url = url
-
- # Add our global widget to the template context, and register it's resources
+ # Add our global widget to the template context, and register it's
+ # resources
tmpl_context.moksha_global_resources = global_resources
- # This is normally done when the widget is rendered, but we cannot assume that
- # moksha apps are going to be using our master index template, which renders
- # this widget for us.
+ # This is normally done when the widget is rendered, but we cannot
+ # assume that moksha apps are going to be using our master index
+ # template, which renders this widget for us.
global_resources.register_resources()
return TGController.__call__(self, environ, start_response)
14 years, 11 months
setup.py.demo
by Luke Macken
setup.py.demo | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
New commits:
commit d1fd540a9bcb8fb8a764a2d3335586ca60e08e65
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:44:18 2009 -0400
Finish moving moksha.examples
diff --git a/setup.py.demo b/setup.py.demo
index a69d6ba..e21d000 100644
--- a/setup.py.demo
+++ b/setup.py.demo
@@ -76,7 +76,7 @@ setup(
[moksha.stream]
#demo = moksha.streams.demo:MokshaDemoDataStream
feed = moksha.streams.feed:FeedStream
- #livegraph = moksha.examples.livegraph:LiveGraphDataStream
+ #livegraph = moksha.widgets.livegraph:LiveGraphDataStream
moksha_metrics = moksha.widgets.metrics:MokshaMetricsDataStream
[moksha.consumer]
@@ -96,7 +96,7 @@ setup(
chat = moksha.widgets.chat:LiveChatWidget
#livefeed_demo = moksha.widgets.demos:LiveFeedDemo
#liveflot = moksha.api.widgets.flot:LiveFlotWidget
- #livegraph = moksha.examples.livegraph:LiveGraphWidget
+ #livegraph = moksha.widgets.livegraph:LiveGraphWidget
grid = moksha.api.widgets:Grid
ptd = moksha.widgets.misc.ptd:ProcessedTowerDefense
placeholder = moksha.api.widgets:Placeholder
14 years, 11 months
moksha/examples moksha/widgets
by Luke Macken
moksha/examples/livegraph/__init__.py | 17 ------
moksha/examples/livegraph/livegraph.py | 66 -------------------------
moksha/examples/livegraph/static/livegraph.css | 6 --
moksha/examples/livegraph/static/livegraph.js | 42 ---------------
moksha/widgets/livegraph/__init__.py | 17 ++++++
moksha/widgets/livegraph/livegraph.py | 66 +++++++++++++++++++++++++
moksha/widgets/livegraph/static/livegraph.css | 6 ++
moksha/widgets/livegraph/static/livegraph.js | 42 +++++++++++++++
8 files changed, 131 insertions(+), 131 deletions(-)
New commits:
commit 41dde29c97ca624f952f3136e73cbe6029f13837
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:43:31 2009 -0400
Move moksha.examples.livegraph to moksha.widgets.livegraph, for now.
This app will probably eventually be encorporated with the demo application
diff --git a/moksha/examples/__init__.py b/moksha/examples/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/moksha/examples/livegraph/__init__.py b/moksha/examples/livegraph/__init__.py
deleted file mode 100644
index 9241973..0000000
--- a/moksha/examples/livegraph/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from livegraph import *
diff --git a/moksha/examples/livegraph/livegraph.py b/moksha/examples/livegraph/livegraph.py
deleted file mode 100644
index e346853..0000000
--- a/moksha/examples/livegraph/livegraph.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors: Luke Macken <lmacken(a)redhat.com>
-
-from random import random
-from datetime import timedelta
-
-from tw.api import CSSLink, JSLink, js_function
-
-from moksha.api.widgets import LiveWidget
-from moksha.api.streams import PollingDataStream
-
-class LiveGraphWidget(LiveWidget):
- """
- This is an example live graph widget based on Michael Carter's article
- "Scalable Real-Time Web Architecture, Part 2: A Live Graph with Orbited,
- MorbidQ, and js.io".
-
- http://cometdaily.com/2008/10/10/scalable-real-time-web-architecture-part...
- """
- params = ['id', 'onconnectedframe', 'onmessageframe']
- topic = 'graph_demo'
- onmessage = 'modify_graph(bars, frame.body)'
- javascript = [JSLink(filename='static/livegraph.js', modname=__name__)]
- css = [CSSLink(filename='static/livegraph.css', modname=__name__)]
- template = '<div id="${id}" />'
-
- def update_params(self, d):
- super(LiveGraphWidget, self).update_params(d)
- self.add_call(js_function('init_graph')(self.id))
-
-
-class LiveGraphDataStream(PollingDataStream):
- """
- This is the main data producer for our live graph widget.
- """
- frequency = timedelta(seconds=0.5)
-
- data_vector_length = 10
- delta_weight = 0.1
- max_value = 400 # NB: this in pixels
- data = [int(random()*max_value) for x in xrange(data_vector_length)]
-
- def poll(self):
- self.data = [
- min(max(datum + (random() - .5) * self.delta_weight *
- self.max_value, 0),
- self.max_value)
- for
- datum in self.data
- ]
- self.send_message('graph_demo', self.data)
diff --git a/moksha/examples/livegraph/static/livegraph.css b/moksha/examples/livegraph/static/livegraph.css
deleted file mode 100644
index a4f3493..0000000
--- a/moksha/examples/livegraph/static/livegraph.css
+++ /dev/null
@@ -1,6 +0,0 @@
-.bar {
- background-color: #38f;
- height: 12px;
- width: 200px;
- margin: 3px 0px;
-}
diff --git a/moksha/examples/livegraph/static/livegraph.js b/moksha/examples/livegraph/static/livegraph.js
deleted file mode 100644
index fe1664f..0000000
--- a/moksha/examples/livegraph/static/livegraph.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// This file is part of Moksha.
-// Copyright (C) 2008-2009 Red Hat, Inc.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-var bars = [];
-var num_bars = 10;
-
-// Make ten bars that are blue
-var init_graph = function(container_name) {
-
- var container = document.getElementById(container_name);
- for (var i=0; i< num_bars; i++) {
- var bar = document.createElement('div');
- bar.className = "bar";
- bar.style.width = "100px";
- bars.push(bar);
- container.appendChild(bar);
- }
- // some pizazz... one bar gets to be red.
- bars[3].style.backgroundColor = "red";
-};
-
-// Change the length of the bars to match given numerical data
-var modify_graph = function(bars, payload) {
- var vals = JSON.parse(payload);
- for (var i=0; i<bars.length; i++) {
- var bar = bars[i];
- bar.style.width = vals[i] + "px";
- }
-}
diff --git a/moksha/widgets/livegraph/__init__.py b/moksha/widgets/livegraph/__init__.py
new file mode 100644
index 0000000..9241973
--- /dev/null
+++ b/moksha/widgets/livegraph/__init__.py
@@ -0,0 +1,17 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from livegraph import *
diff --git a/moksha/widgets/livegraph/livegraph.py b/moksha/widgets/livegraph/livegraph.py
new file mode 100644
index 0000000..e346853
--- /dev/null
+++ b/moksha/widgets/livegraph/livegraph.py
@@ -0,0 +1,66 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors: Luke Macken <lmacken(a)redhat.com>
+
+from random import random
+from datetime import timedelta
+
+from tw.api import CSSLink, JSLink, js_function
+
+from moksha.api.widgets import LiveWidget
+from moksha.api.streams import PollingDataStream
+
+class LiveGraphWidget(LiveWidget):
+ """
+ This is an example live graph widget based on Michael Carter's article
+ "Scalable Real-Time Web Architecture, Part 2: A Live Graph with Orbited,
+ MorbidQ, and js.io".
+
+ http://cometdaily.com/2008/10/10/scalable-real-time-web-architecture-part...
+ """
+ params = ['id', 'onconnectedframe', 'onmessageframe']
+ topic = 'graph_demo'
+ onmessage = 'modify_graph(bars, frame.body)'
+ javascript = [JSLink(filename='static/livegraph.js', modname=__name__)]
+ css = [CSSLink(filename='static/livegraph.css', modname=__name__)]
+ template = '<div id="${id}" />'
+
+ def update_params(self, d):
+ super(LiveGraphWidget, self).update_params(d)
+ self.add_call(js_function('init_graph')(self.id))
+
+
+class LiveGraphDataStream(PollingDataStream):
+ """
+ This is the main data producer for our live graph widget.
+ """
+ frequency = timedelta(seconds=0.5)
+
+ data_vector_length = 10
+ delta_weight = 0.1
+ max_value = 400 # NB: this in pixels
+ data = [int(random()*max_value) for x in xrange(data_vector_length)]
+
+ def poll(self):
+ self.data = [
+ min(max(datum + (random() - .5) * self.delta_weight *
+ self.max_value, 0),
+ self.max_value)
+ for
+ datum in self.data
+ ]
+ self.send_message('graph_demo', self.data)
diff --git a/moksha/widgets/livegraph/static/livegraph.css b/moksha/widgets/livegraph/static/livegraph.css
new file mode 100644
index 0000000..a4f3493
--- /dev/null
+++ b/moksha/widgets/livegraph/static/livegraph.css
@@ -0,0 +1,6 @@
+.bar {
+ background-color: #38f;
+ height: 12px;
+ width: 200px;
+ margin: 3px 0px;
+}
diff --git a/moksha/widgets/livegraph/static/livegraph.js b/moksha/widgets/livegraph/static/livegraph.js
new file mode 100644
index 0000000..fe1664f
--- /dev/null
+++ b/moksha/widgets/livegraph/static/livegraph.js
@@ -0,0 +1,42 @@
+// This file is part of Moksha.
+// Copyright (C) 2008-2009 Red Hat, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+var bars = [];
+var num_bars = 10;
+
+// Make ten bars that are blue
+var init_graph = function(container_name) {
+
+ var container = document.getElementById(container_name);
+ for (var i=0; i< num_bars; i++) {
+ var bar = document.createElement('div');
+ bar.className = "bar";
+ bar.style.width = "100px";
+ bars.push(bar);
+ container.appendChild(bar);
+ }
+ // some pizazz... one bar gets to be red.
+ bars[3].style.backgroundColor = "red";
+};
+
+// Change the length of the bars to match given numerical data
+var modify_graph = function(bars, payload) {
+ var vals = JSON.parse(payload);
+ for (var i=0; i<bars.length; i++) {
+ var bar = bars[i];
+ bar.style.width = vals[i] + "px";
+ }
+}
14 years, 11 months
5 commits - moksha/api moksha/lib moksha/widgets setup.py.demo
by Luke Macken
moksha/api/widgets/__init__.py | 1
moksha/api/widgets/chat/__init__.py | 17
moksha/api/widgets/chat/chat.py | 50 -
moksha/api/widgets/chat/controllers/__init__.py | 17
moksha/api/widgets/chat/controllers/chat.py | 114 ----
moksha/api/widgets/chat/static/chat.css | 119 ----
moksha/api/widgets/chat/static/chrome.js | 83 ---
moksha/api/widgets/chat/static/gui.js | 215 --------
moksha/api/widgets/chat/static/index.html | 48 -
moksha/api/widgets/chat/static/irc2.js | 224 --------
moksha/api/widgets/chat/static/style.css | 153 -----
moksha/api/widgets/chat/static/themes/dojo/chrome.js | 83 ---
moksha/api/widgets/chat/static/themes/dojo/gui.js | 19
moksha/api/widgets/chat/static/themes/dojo/index.html | 226 --------
moksha/api/widgets/chat/static/themes/dojo/style.css | 151 -----
moksha/api/widgets/chat/static/themes/simple/chrome.js | 83 ---
moksha/api/widgets/chat/static/themes/simple/gui.js | 216 --------
moksha/api/widgets/chat/static/themes/simple/index.html | 58 --
moksha/api/widgets/chat/static/themes/simple/style.css | 151 -----
moksha/api/widgets/chat/static/willowchat.js | 337 ------------
moksha/api/widgets/chat/templates/bootstrap.mak | 419 ----------------
moksha/api/widgets/chat/templates/chat.mak | 31 -
moksha/api/widgets/iframe.py | 30 -
moksha/api/widgets/layout/layout.py | 51 -
moksha/lib/helpers.py | 5
moksha/widgets/chat/__init__.py | 17
moksha/widgets/chat/chat.py | 50 +
moksha/widgets/chat/controllers/__init__.py | 17
moksha/widgets/chat/controllers/chat.py | 114 ++++
moksha/widgets/chat/static/chat.css | 119 ++++
moksha/widgets/chat/static/chrome.js | 83 +++
moksha/widgets/chat/static/gui.js | 215 ++++++++
moksha/widgets/chat/static/index.html | 48 +
moksha/widgets/chat/static/irc2.js | 224 ++++++++
moksha/widgets/chat/static/style.css | 153 +++++
moksha/widgets/chat/static/themes/dojo/chrome.js | 83 +++
moksha/widgets/chat/static/themes/dojo/gui.js | 19
moksha/widgets/chat/static/themes/dojo/index.html | 226 ++++++++
moksha/widgets/chat/static/themes/dojo/style.css | 151 +++++
moksha/widgets/chat/static/themes/simple/chrome.js | 83 +++
moksha/widgets/chat/static/themes/simple/gui.js | 216 ++++++++
moksha/widgets/chat/static/themes/simple/index.html | 58 ++
moksha/widgets/chat/static/themes/simple/style.css | 151 +++++
moksha/widgets/chat/static/willowchat.js | 337 ++++++++++++
moksha/widgets/chat/templates/bootstrap.mak | 419 ++++++++++++++++
moksha/widgets/chat/templates/chat.mak | 31 +
moksha/widgets/deprecated/layout.py | 47 +
moksha/widgets/iframe.py | 33 +
setup.py.demo | 6
49 files changed, 2910 insertions(+), 2891 deletions(-)
New commits:
commit 97d6614c77d9c559f0be35b55bb87029bc683a9a
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:40:59 2009 -0400
More s/appz/apps/ nonsense
diff --git a/setup.py.demo b/setup.py.demo
index bf09429..a69d6ba 100644
--- a/setup.py.demo
+++ b/setup.py.demo
@@ -85,7 +85,7 @@ setup(
#[moksha.wsgiapp]
# Use this entry point to mount WSGI applications, which can then be
- # accessed the same as regular apps, through the `/appz/name` url.
+ # accessed the same as regular apps, through the `/apps/name` url.
[moksha.application]
menu = moksha.api.menus.controllers:MokshaMenuController
commit 798c0e6b74ea385c42dd11ca4ee16acf4b19f44b
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:39:05 2009 -0400
Move moksha.api.widgets.chat to moksha.widgets.chat
diff --git a/moksha/api/widgets/chat/__init__.py b/moksha/api/widgets/chat/__init__.py
deleted file mode 100644
index 5447654..0000000
--- a/moksha/api/widgets/chat/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from chat import LiveChatWidget, LiveChatFrameWidget
diff --git a/moksha/api/widgets/chat/chat.py b/moksha/api/widgets/chat/chat.py
deleted file mode 100644
index 98ef860..0000000
--- a/moksha/api/widgets/chat/chat.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors: Luke Macken <lmacken(a)redhat.com>
-
-from tw.api import Widget, JSLink, CSSLink
-from tw.jquery import jquery_js
-
-from moksha.api.widgets.orbited import orbited_js
-
-irc2_js = JSLink(filename='static/irc2.js',
- javascript=[orbited_js],
- modname=__name__)
-
-willowchat_js = JSLink(filename='static/willowchat.js',
- javascript=[jquery_js, irc2_js],
- modname=__name__)
-
-gui_js = JSLink(filename='static/gui.js',
- javascript=[willowchat_js],
- modname=__name__)
-
-willowchat_css = CSSLink(filename='static/style.css', modname=__name__)
-
-
-class LiveChatWidget(Widget):
- name = 'Chat'
- params = ['bootstrap']
- bootstrap = JSLink(link='/apps/chat/bootstrap')
- template = '<div id="willowchat" reposition="true">${bootstrap}</div>'
- visible = False
-
-
-class LiveChatFrameWidget(Widget):
- template = 'mako:moksha.api.widgets.chat.templates.chat'
- javascript = [orbited_js, willowchat_js, irc2_js, gui_js, jquery_js]
- css = [willowchat_css]
diff --git a/moksha/api/widgets/chat/controllers/__init__.py b/moksha/api/widgets/chat/controllers/__init__.py
deleted file mode 100644
index 10fd377..0000000
--- a/moksha/api/widgets/chat/controllers/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from chat import ChatController
diff --git a/moksha/api/widgets/chat/controllers/chat.py b/moksha/api/widgets/chat/controllers/chat.py
deleted file mode 100644
index b413a00..0000000
--- a/moksha/api/widgets/chat/controllers/chat.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors: Luke Macken <lmacken(a)redhat.com>
-
-import logging
-log = logging.getLogger(__name__)
-
-import urlparse
-urlparse.uses_netloc.append('irc')
-
-from tg import expose, tmpl_context, config
-from pylons import request
-
-from moksha.lib.base import BaseController
-from moksha.api.widgets.chat import LiveChatFrameWidget
-
-chat_frame_widget = LiveChatFrameWidget('chat_frame')
-
-
-class ChatController(BaseController):
-
- def __init__(self, *args, **kw):
- super(ChatController, self).__init__(*args, **kw)
- self.config = {}
- backend = config.get('chat.backend')
- if not backend:
- log.info('No `chat.backend` defined; disabling chat functionality')
- return
- backend = urlparse.urlparse(backend)
- if hasattr(backend, 'scheme'): # Python 2.5+
- self.config['backendProtocol'] = backend.scheme
- self.config['backendAddr'] = [backend.hostname, backend.port]
- else: # Python 2.4
- self.config['backendProtocol'] = backend[0]
- host, port = backend[1].split(':')
- self.config['backendAddr'] = [host, port]
- self.config['startBuiltin'] = config.get('chat.builtin', False)
- self.config['rooms'] = {}
- display_opts = {
- 'floating': True, 'floatingToggle': False, 'width': 400 ,
- 'height': 300, 'theme': 'simple', 'resizable': True,
- 'greeting': 'Moksha Chat',
- }
- for room in config['chat.rooms'].replace(',', ' ').split():
- self.config['rooms'][room] = {'display': {}}
- for display_opt, default in display_opts.items():
- self.config['rooms'][room]['display'][display_opt] = \
- config.get('chat.%s.display.%s' % (room, display_opt),
- default)
- self.config['rooms'][room]['roomAssignmentMode'] = \
- config.get('chat.%s.roomAssignmentMode' % room, 'static')
- self.config['rooms'][room]['staticRoomName'] = \
- config.get('chat.%s.staticRoomName' % room, room)
-
- log.debug('Chat config = %r' % self.config)
-
- @expose('mako:moksha.templates.widget')
- def index(self, *args, **kw):
- tmpl_context.widget = chat_frame_widget
- return dict(options={})
-
- @expose('mako:moksha.api.widgets.chat.templates.bootstrap',
- content_type='text/javascript')
- def bootstrap(self, *args, **kw):
- return dict(host=request.headers['host'])
-
- @expose('json')
- def rooms(self, roomClass='default', op=None, jsonp=None):
- opts = None
- if op:
- opts = self.jsonp(getattr(self, 'op_%s' % op,
- self.op_not_found)(roomClass), jsonp)
- else:
- opts = self.jsonp([False, ["op not specified"]], jsonp)
- return opts
-
- def jsonp(self, result, jsonp=None):
- result = str(result).replace('True', 'true').replace('False', 'false')
- if jsonp:
- result = jsonp + '(' + result + ')'
- return result
-
- def op_info(self, roomClass):
- if roomClass not in self.config['rooms']:
- return [False, ['unknown room class: ' + roomClass]]
- info = self.config['rooms'][roomClass]
- displayInfo = info.get('display', {})
- opts = {}
- opts.update(displayInfo)
- mode = info.get('roomAssignmentMode', 'static')
- if mode == 'static':
- opts['roomId'] = info.get('staticRoomName', 'default')
- elif mode == 'referrer':
- opts['roomId'] = request.headers.get('referer', 'default')
- opts['protocol'] = self.config['backendProtocol']
- opts['addr'] = self.config['backendAddr']
- return [True, opts]
-
- def op_not_found(self):
- return [False, ['unrecognized op']]
diff --git a/moksha/api/widgets/chat/static/chat.css b/moksha/api/widgets/chat/static/chat.css
deleted file mode 100644
index fe0d13f..0000000
--- a/moksha/api/widgets/chat/static/chat.css
+++ /dev/null
@@ -1,119 +0,0 @@
-#signin_popup {
- width:220pt;
- padding:2em;
- padding-bottom:3em;
- text-align:center;
- background-color: #A4C9D6;
- color:#0E3541;
- border: 5pt solid #195263;
- position:absolute;
- top:80pt;
- left:100pt;
- z-index:2;
-}
-#nickname {
- width:90pt;
-}
-#absorb_clicks {
- position:absolute;
- top:0;
- left:0;
- width:300pt;
- height:200pt;
-}
-
-.chatbox {
- width:490pt;
- font: 100% Verdana, sans-serif;
- background-color:#24758E;
- padding:5pt;
- position:relative;
-}
-.chatbox .left_column {
- width: 360pt;
-}
-.chatbox .chathistory {
- width:100%;
- height:217pt;
- overflow: auto;
- background-color: white;
-}
-.chatbox .chathistory div {
- background-color:#ffffee;
- padding:.2em;
- padding-left:1.5em;
- text-indent: -1em;
- border-bottom: 1px dotted #ccc;
-}
-.chatbox .chathistory .message .user {
- width:5em;
- font-weight: bold;
- color:#DD7200;
- padding-right:.2em;
- text-align:right;
-}
-.chatbox .chathistory .message.self .user{
- color: #B42600;
-}
-.chatbox .chathistory .message.mentioned{
- background-color: #d5c5ff;
-}
-.chatbox .chathistory .message.private{
- background-color: #ccc;
-}
-.chatbox .chathistory .message.ctcp {
- background-color: #f0f;
-}
-.chatbox .chathistory .action,
-.chatbox .chathistory .action .user {
- color: #D68850;
- font-style:italic;
-}
-.chatbox .chathistory .action.self,
-.chatbox .chathistory .action.self .user {
- color: #A94C3B;
- font-style:italic;
-}
-.chatbox .chathistory .informative {
- font-size: 85%;
- font-style: italic;
- color:#999;
- text-align:center;
- padding:.3em;
-}
-
-.chatbox .chatbox_input {
- width:100%;
- height:30pt;
- margin:0;
- margin-top:3pt;
- padding:0;
- border:0;
- font-family: Verdana, sans-serif;
-}
-
-.chatbox .user_list {
- float:right;
- position: absolute;
- padding:0;
- margin:0;
- right:5pt;
- top:5pt;
- background-color:white;
- width:127pt;
- height:250pt;
- overflow:auto;
-}
-.chatbox .user_list .user_entry{
- padding:.2em;
- padding-left:8pt;
- border-bottom: 1px dotted #ccc;
-}
-
-#events {
- visibility:hidden;
- border:0;
- width:0;
- height:0;
-/* display:none;*/
-}
diff --git a/moksha/api/widgets/chat/static/chrome.js b/moksha/api/widgets/chat/static/chrome.js
deleted file mode 100644
index 34caca5..0000000
--- a/moksha/api/widgets/chat/static/chrome.js
+++ /dev/null
@@ -1,83 +0,0 @@
-(function() {
-/* Boilerplate
- */
-if (!window.WillowChat) {
- Willowchat = {}
-}
-
-if (!WillowChat.chrome) {
- WillowChat.chrome = {}
-}
-
-if (!WillowChat.chrome.map) {
- WillowChat.chrome.map = {}
-}
-
-
-WillowChat.chrome.map.simple = WillowChat.chrome.SimpleChrome = function(container, opts) {
- /* Set configured height
- */
- container.style.width = opts.width + 'px'
- container.style.height = opts.height + 'px'
- container.style.background = "white";
- var toggles = document.createElement('div')
- toggles.setAttribute('id', 'willowchatToggles')
- var floatToggle = document.createElement('div')
- floatToggle.setAttribute('id', 'willowchatFloat')
- floatToggle.innerHTML = "↑"
- var minToggle = document.createElement('div')
- minToggle.setAttribute('id', 'willowchatMin')
- minToggle.innerHTML = "-"
- floatToggle.setAttribute('style', "float: left;")
- minToggle.setAttribute('style', "float: left;")
- var toggleElements = [ minToggle, floatToggle]
- for (var i = 0; i < 2; ++i) {
- var t = toggleElements[i]
- t.style.width = "20px"
- t.style.height = "20px"
- t.style.textAlign = "center"
- t.style.border = "1px solid black"
- t.style.padding = "2px"
- t.style.color = "white"
- t.style.fontWeight = "bold"
- t.style.background = "#005522"
- t.style.cursor = "pointer"
- t.style.cssFloat = "left"
- t.style.styleFloat = "left"
- t.style.display = "none"
- }
- container.appendChild(toggles)
- toggles.appendChild(floatToggle)
- toggles.appendChild(minToggle)
-
- /* Should it be floating?
- */
- if (opts.floating) {
- container.style.position = 'absolute';
- container.style.bottom = '0';
- container.style.right = '0';
- minToggle.style.display = "block"
- toggles.style.position = "absolute"
- toggles.style.top = "1px"
- toggles.style.left = "1px"
- if (opts.reposition) {
- container.parentNode.removeChild(container)
- document.body.appendChild(container)
-
- }
- }
- else {
- var ifr = container.getElementsByTagName('iframe')[0]
- toggles.style.marginBottom="-10px"
- ifr.style.marginTop="10px"
- container.removeChild(ifr)
- container.appendChild(ifr)
-// toggles.style.marginBottom = "-5px";
- }
- if (opts.floatingToggle) {
- floatToggle.style.display = "block"
- }
- toggles.style.border = "1ps solid yellow"
-}
-
-})();
\ No newline at end of file
diff --git a/moksha/api/widgets/chat/static/gui.js b/moksha/api/widgets/chat/static/gui.js
deleted file mode 100644
index 2972753..0000000
--- a/moksha/api/widgets/chat/static/gui.js
+++ /dev/null
@@ -1,215 +0,0 @@
-(function() {
-
-if (!window.WillowChat) {
- Willowchat = {}
-}
-
-if (!WillowChat.guis) {
- WillowChat.guis = {}
-}
-
-if (!WillowChat.guis.map) {
- WillowChat.guis.map = {}
-}
-var ENTER_KEY = 13
-WillowChat.guis.map.simple = WillowChat.guis.SimpleGui = function(wc, opts) {
- var self = this;
- self.presenceShown = true;
- var logger = Orbited.getLogger('WillowChatTest');
-// logger.enabled = true;
- var username = null;
- var presence = {}
-
- $('#nickname').focus();
- $('#nickname').keypress( function(e) {
- var key = e.charCode || e.keyCode || 0
- if (key == ENTER_KEY) {
- self.connect();
- };
- });
- $('#chatboxInput').keypress(function(e) {
- var key = e.charCode || e.keyCode || 0;
- if (key == ENTER_KEY) {
- self.sendMessage();
- return false;
- };
- });
- $("#popupContent p").html(opts.greeting)
- $("#presenceToggle").click(function() {
- if (self.presenceShown) {
- self.presenceShown = false;
- $("#presence").hide()
- $("#presenceToggle").html('←');
- }
- else {
- self.presenceShown = true;
- $("#presence").show();
- $("#presenceToggle").html('→');
- }
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- $('#chatboxInput').focus();
- }
- else {
- $('#nickname').focus();
- }
- })
- var scrollDown = function() {
- var box = $('#history')[0]
- box.scrollTop = box.scrollHeight;
- }
- var isSubstring = function (sub, str) {
- // case insensitive substring test
- return str.toLowerCase().indexOf(sub.toLowerCase()) >= 0;
- };
- var sanitize = (function(str) {
- // See http://bigdingus.com/2007/12/29/html-escaping-in-javascript/
- var MAP = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- };
- var repl = function(c) { return MAP[c]; };
- return function(s) {
- return s.replace(/[&<>'"]/g, repl);
- };
- })();
-
- // TODO: test this out
- var userRenamed = function(oldname, newname) {
- $("<div class='informative rename'></div>")
- .html("<span class='user'>" + oldname + "</span> is now known as " +
- "<span class='user'>" + newname + "</span>")
- .appendTo("#history");
- scrollDown();
- $("#user_" + oldname)
- .attr("id", "user_" + newname)
- .html(newname);
- }
-
- var addName = function (name) {
- presence[name] = 1
- $('<div class="user_entry" id="user_' + name + '">' + name + '</div>')
- .appendTo("#presenceList");
- };
-
- var removeName = function (name) {
- delete presence[name];
- $(".user_list #user_" + name).remove()
- };
-
- var sortNames = function () {
- $('#presenceList').empty();
- var list = [];
- for (var user in presence) {
- list.push(user);
- };
- list.sort()
- for (var i=0; i < list.length; i++) {
- var user = list[i];
- $('<div class="user_entry" id="user_' + user + '">' + user + '</div>')
- .appendTo("#presenceList");
- };
- };
- self.connect = function() {
- username = $("#nickname").val();
- if (!username) {
- logger.debug('please enter a username');
- return
- }
- $('#popup, #absorbClicks').hide();
- $('#chatboxInput').focus();
- $('#chatboxInput').val('')
-
- connected = true;
- wc.connect( {
- username: username
- })
- wc.onConnect = function(data) {
- /* This is somewhat important -- without this IE can run into some
- * issues with reconnecting
- */
-
- window.onbeforeunload = function() {
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- return 'Are you sure you want to quit and lose the chat connection?';
- }
- };
- window.onunload = function() {
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- wc.disconnect();
- }
- }
-
-
- $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
- for (var i = 0; i < wc.presence.length; ++i) {
- addName(wc.presence[i]);
- }
- sortNames();
- logger.debug('connected', data, wc.presence)
- }
- wc.onMessage = function(sender, message) {
- logger.debug('msg', sender, message);
- var messagediv = $('<div class="message"></div>');
-
- if (sender == username) {
- messagediv.addClass("self");
- }
- if (isSubstring(username, message)) {
- messagediv.addClass("mentioned");
- }
- messagediv.html('<span class="user">' + sender + ':</span> ' +
- sanitize(message))
- .appendTo("#history");
- scrollDown();
- }
- wc.onAction = function(s, m) { logger.debug('action', s, m); }
-
- wc.onJoin = function(joiner) {
- logger.debug('join', joiner);
- addName(joiner);
- sortNames();
- $("<div class='informative join'></div>")
- .html("<span class='user'>" + joiner + '</span> has joined')
- .appendTo("#history");
- scrollDown();
- }
- wc.onLeave = function(leaver) {
- logger.debug('leave', leaver);
- removeName(leaver);
- $("<div class='informative part'></div>")
- .html("<span class='user'>" + leaver + '</span> left')
- .appendTo("#history");
- scrollDown();
- }
- wc.onDisconnect = function() { logger.debug('disconneted'); }
- wc.onUsernameTaken = function() {
- logger.debug('onUsernameTaken', username);
- username += '_'
- try {
- wc.rename(username);
- logger.debug('rename sent');
- }
- catch(e) {
- logger.debug('rename failed:', e)
- }
- }
- }
- self.sendMessage = function() {
- var msg = $('#chatboxInput').val();
- wc.sendMessage(msg)
- $('#chatboxInput').val('');
- // the WillowChat server will not echo our message back, so simulate a send.
- wc.onMessage(username, msg)
- }
- self.sendAction = function() {
- var msg = getMessage()
- wc.sendAction(msg);
- logger.debug('action', username, msg)
- }
-
-}
-})()
-
diff --git a/moksha/api/widgets/chat/static/index.html b/moksha/api/widgets/chat/static/index.html
deleted file mode 100644
index d4277bf..0000000
--- a/moksha/api/widgets/chat/static/index.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!-- @@ HACK -->
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
-<script src="/toscawidgets/resources/tw.jquery.base/static/javascript/jquery-1.2.6.pack.js"></script>
-<link rel="stylesheet" type="text/css" href="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/style.css"></link>
- <script>
- TCPSocket = Orbited.TCPSocket
- document.domain = document.domain;
-/* Orbited.system.enabled = true;
- Orbited.loggers['Orbited.XSDR'].enabled = false
- Orbited.loggers['Orbited.CometSession'].enabled = true
- Orbited.loggers['Orbited.TCPSocket'].enabled = true
- Orbited.loggers['XSDRBridge'].enabled = true
- Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
- Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
- Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
- Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true.
- Orbited.loggers['WC.c.IRCClient'].enabled = true
-*/
- </script>
-
-<div id="popup">
-<div id="popupOuter">
- <div id="popupMiddle">
- <div id="popupContent">
- <p>Greeting</p>
- <label for="nickname">Nickname:</label>
- <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
- </div>
- </div>
-</div>
-</div>
-
- <div id="absorbClicks"></div>
- <div id="presenceToggle">
- →
- </div>
- <div id="presence">
- <div id="presenceTitle">Presence</div>
- <div id="presenceList">
- </div>
- </div>
- <div id="history">
- </div>
- <div id="inputBar">
- <textarea id="chatboxInput"></textarea>
- </div>
diff --git a/moksha/api/widgets/chat/static/irc2.js b/moksha/api/widgets/chat/static/irc2.js
deleted file mode 100644
index 175be14..0000000
--- a/moksha/api/widgets/chat/static/irc2.js
+++ /dev/null
@@ -1,224 +0,0 @@
-/* irc.js
- * This IRC client runs in a web browser using pure JavaScript
- * Orbited 0.5+ required
- *
- * Methods:
- * connect(hostname, port)
- * ident(nickname, modes, real_name)
- * join(channel)
- * names(channel)
- * part(channel)
- * quit(reason)
- * privmsg(destination, message)
- *
- * Callbacks:
- * Built-in callbacks are onconnect(), onerror(), onresponse(), and onclose()
- * onerror and onreply are passed numerical reponse codes, see:
- * http://www.irchelp.org/irchelp/rfc/chapter6.html for a list of IRC response
- * codes.
- *
- * To add callbacks for IRC actions, for instance PRIVMSG,
- * set onPRIVMSG = function(command) {...you code here...}
- * See the included IRC demo (/static/demos/irc) for example usage
- *
- * Frank Salim (frank.salim(a)gmail.com)
- * ©2008 The Orbited Project
- */
-
-// TODO DRY this by creating a common logging infrastructure (this is also on stomp.js)
-IRC_DEBUG = false;
-
-if (IRC_DEBUG && typeof(Orbited)) {
- var getIrcLogger = function(name) {
- var logger = Orbited.getLogger(name);
- if (!("dir" in logger)) {
- logger.dir = function() {};
- }
- return logger;
- }
-}
-else if (IRC_DEBUG && typeof(console)) {
- var getIrcLogger = function(name) {
- return {
- debug: function() {
- var args = Array.prototype.slice.call(arguments);
- args.unshift(name, ": ");
- console.debug.apply(console, args);
- },
- dir: function() {
- console.debug(name, ":");
- console.dir.apply(console, arguments);
- }
- };
- };
-}
-else {
- var getIrcLogger = function(name) {
- return {
- debug: function() {},
- dir: function() {}
- };
- };
-}
-
-IRCClient = function() {
- var log = getIrcLogger("IRCClient");
- var self = this
- var conn = null
- var buffer = ""
- var ENDL = "\r\n"
-
- self.onopen = function() {};
- self.onconnect = function() {} // Do nothing in default callbacks
- self.onclose = function() {}
- self.onerror = function(command) {}
- self.onresponse = function(command) {} // used for numerical replies
-
- self.connect = function(hostname, port) {
- log.debug("connect");
- conn = self._createTransport();
- conn.onopen = conn_opened
- conn.onclose = conn_closed
- conn.onread = conn_read
- conn.open(hostname, port)
- // TODO set onerror.
- }
- self._createTransport = function() {
- return new TCPSocket();
- };
- self.close = function() {
- log.debug("close");
- conn.close()
- conn.onopen = null;
- conn.onclose = null;
- conn.onread = null;
- self.onclose()
- }
- self.ident = function(nickname, modes, real_name) {
- send("USER", nickname + " " + modes + " :" + real_name)
- }
- self.nick = function(nickname) {
- send("NICK", nickname)
- }
- self.join = function(channel) {
- send("JOIN", channel)
- }
- self.names = function(channel) {
- send("NAMES", channel)
- }
- self.part = function(channel, reason) {
- send("PART", channel + " :" + reason)
- }
- self.quit = function(reason) {
- var reason = reason || "leaving";
- send("QUIT", ":" + reason)
- conn.close()
- }
- self.reset = function() {
- conn.reset();
- }
- self.action = function(destination, message) {
- send('PRIVMSG', destination + ' :\01ACTION ' + message + '\01')
- }
-
- self.privmsg = function(destination, message) {
- send('PRIVMSG', destination + ' :' + message)
- }
-
- // Socket Callbacks
- var conn_opened = function() {
- self.onopen()
- }
- var conn_closed = function() {
- self.onclose()
- }
- var conn_read = function(data) {
- log.debug("data:");
- log.debug(data);
- buffer += data
- parse_buffer()
- }
-
- // Internal Functions
- var send = function(type, payload) {
- log.debug("send: " + payload);
- conn.send(type + " " + payload + ENDL);
- };
- var parse_buffer= function() {
- var commands = buffer.split(ENDL);
- buffer = commands[commands.length-1];
- for (var i = 0, l = commands.length - 1; i < l; ++i) {
- var line = commands[i];
- if (line.length > 0)
- dispatch(line);
- }
- };
- var parse_command = function(s) {
- // See http://tools.ietf.org/html/rfc2812#section-2.3
-
- // all the arguments are split by a single space character until
- // the first ":" character. the ":" marks the start of the last
- // trailing argument which can contain embeded space characters.
- var i = s.indexOf(" :");
- if (i >= 0) {
- var args = s.slice(0, i).split(' ');
- args.push(s.slice(i + 2));
- } else {
- var args = s.split(' ');
- }
-
- // extract the prefix (if there is one).
- if (args[0].charAt(0) == ":") {
- var prefix = args.shift().slice(1);
- } else {
- var prefix = null;
- }
-
- var command = {
- prefix: prefix,
- type: args.shift(),
- args: args
- };
- log.debug("command:");
- log.dir(command);
- return command;
- };
- var dispatch = function(line) {
- command = parse_command(line);
- if (command.type == "PING") {
- send("PONG", ":" + command.args)
- }
- if (!isNaN(parseInt(command.type))) {
- var error_code = parseInt(command.type)
- if (error_code > 400)
- return self.onerror(command)
- else
- return self.onresponse(command)
- }
- if (command.type == "PRIVMSG") {
- msg = command.args[1]
- if (msg.charCodeAt(0) == 1 && msg.charCodeAt(msg.length-1) == 1) {
- var args = [command.args[0]]
- var newargs = msg.slice(1, msg.length - 1).split(' ')
- if (newargs[0] == 'ACTION') {
- command.type = newargs.shift()
- }
- else {
- command.type = 'CTCP'
- }
-
- for (var i = 0; i < newargs.length; ++i) {
- args.push(newargs[i])
- }
- command.args = args
- }
- }
- if (typeof(self["on" + command.type]) == "function") {
- // XXX the user is able to define unknown command handlers,
- // but cannot send any arbitrary command
- self["on" + command.type](command);
- } else {
- log.debug("unhandled command received: ", command.type);
- }
- };
-};
diff --git a/moksha/api/widgets/chat/static/style.css b/moksha/api/widgets/chat/static/style.css
deleted file mode 100644
index c92d64e..0000000
--- a/moksha/api/widgets/chat/static/style.css
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
-html, body {
- padding: 0px;
- margin: 0px;
- border: none;
- _overflow: hidden;
- }
- */
-#presenceToggle {
- border: 1px solid black;
- position: absolute;
- right: 1px;
- top: 1px;
- padding: 2px;
- background: #3f9824;
- color: white;
- font-weight: bold;
- cursor: pointer;
-}
-#presenceToggle:hover {
-}
-#presence {
- float: right;
- border: 1px solid gray;
- width: 130px;
- height: 83%;
- margin-left: 3px;
- margin-bottom: 0px;
- overflow: hidden;
-}
-#presenceTitle {
- text-decoration: underline;
-}
-#presenceList {
- overflow: auto;
- height: 90%;
-}
-#history {
- border: 1px solid gray;
- height: 83%;
- overflow: auto;
- margin-bottom: 0px;
-}
-#historySpacer {
- border: 1px solid red;
-}
-#inputBar {
- margin-top: 0px;
- height: 15%;
-}
-#inputBar textarea {
- width: 100%;
- height: 100%;
- border: 1px solid gray;
-}
-
-
-
-#popup {
- position: absolute;
- height: 100%;
- width: 70%;
- left: 15%;
- z-index: 2;
-}
-
-#popupOuter {
- height: 100%;
- width: 100%;
- overflow: hidden;
- position: relative;
-}
-#popupOuter[id] {display: table; position: static;}
-
-#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
-#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
-
-#popupContent {position: relative; top: -50%} /* for explorer only */
-/* optional: #popupContent[id] {position: static;} */
-
-#popupContent {
- font-size: 120%;
- text-align:center;
- background: #3f9824;
- color: white;
- border: 5pt solid #83cb22;
- padding: 8px;
- padding-bottom: 20px;
- width: 100%;
-}
-#popupContent p {
- font-size: 150%;
-}
-
-#absorbClicks {
- position:absolute;
- top:0;
- left:0;
- width:100%;
- height:100%;
-}
-
-
-#history div {
- background-color:#eeffee;
- padding:.2em;
- padding-left:1.5em;
- text-indent: -1em;
- border-bottom: 1px dotted #ccc;
-}
-#history .message .user {
- width:5em;
- font-weight: bold;
- color:#DD7200;
- padding-right:.2em;
- text-align:right;
-}
-#history .message.self .user{
- color: #B42600;
-}
-#history .message.mentioned{
- background-color: #d5c5ff;
-}
-#history .message.private{
- background-color: #ccc;
-}
-#history .message.ctcp {
- background-color: #f0f;
-}
-#history .action {
- color: #D68850;
- font-style:italic;
-}
-#history .action {
- color: #A94C3B;
- font-style:italic;
-}
-#history .informative {
- font-size: 85%;
- font-style: italic;
- color:#999;
- text-align:center;
- padding:.3em;
-}
-#presenceList .user_entry {
- font-size: 90%;
- padding:.2em;
- padding-left:8pt;
- border-bottom: 1px dotted #ccc;
-}
-
-
-
diff --git a/moksha/api/widgets/chat/static/themes/dojo/chrome.js b/moksha/api/widgets/chat/static/themes/dojo/chrome.js
deleted file mode 100644
index 770701f..0000000
--- a/moksha/api/widgets/chat/static/themes/dojo/chrome.js
+++ /dev/null
@@ -1,83 +0,0 @@
-(function() {
-/* Boilerplate
- */
-if (!window.WillowChat) {
- Willowchat = {}
-}
-
-if (!WillowChat.chrome) {
- WillowChat.chrome = {}
-}
-
-if (!WillowChat.chrome.map) {
- WillowChat.chrome.map = {}
-}
-
-
-WillowChat.chrome.map.dojo = WillowChat.chrome.DojoChrome = function(container, opts) {
- /* Set configured height
- */
- container.style.width = opts.width + 'px'
- container.style.height = opts.height + 'px'
- container.style.background = "white";
- var toggles = document.createElement('div')
- toggles.setAttribute('id', 'willowchatToggles')
- var floatToggle = document.createElement('div')
- floatToggle.setAttribute('id', 'willowchatFloat')
- floatToggle.innerHTML = "↑"
- var minToggle = document.createElement('div')
- minToggle.setAttribute('id', 'willowchatMin')
- minToggle.innerHTML = "-"
- floatToggle.setAttribute('style', "float: left;")
- minToggle.setAttribute('style', "float: left;")
- var toggleElements = [ minToggle, floatToggle]
- for (var i = 0; i < 2; ++i) {
- var t = toggleElements[i]
- t.style.width = "20px"
- t.style.height = "20px"
- t.style.textAlign = "center"
- t.style.border = "1px solid black"
- t.style.padding = "2px"
- t.style.color = "white"
- t.style.fontWeight = "bold"
- t.style.background = "#005522"
- t.style.cursor = "pointer"
- t.style.cssFloat = "left"
- t.style.styleFloat = "left"
- t.style.display = "none"
- }
- container.appendChild(toggles)
- toggles.appendChild(floatToggle)
- toggles.appendChild(minToggle)
-
- /* Should it be floating?
- */
- if (opts.floating) {
- container.style.position = 'absolute';
- container.style.bottom = '0';
- container.style.right = '0';
- minToggle.style.display = "block"
- toggles.style.position = "absolute"
- toggles.style.top = "1px"
- toggles.style.left = "1px"
- if (opts.reposition) {
- container.parentNode.removeChild(container)
- document.body.appendChild(container)
-
- }
- }
- else {
- var ifr = container.getElementsByTagName('iframe')[0]
- toggles.style.marginBottom="-10px"
- ifr.style.marginTop="10px"
- container.removeChild(ifr)
- container.appendChild(ifr)
-// toggles.style.marginBottom = "-5px";
- }
- if (opts.floatingToggle) {
- floatToggle.style.display = "block"
- }
- toggles.style.border = "1ps solid yellow"
-}
-
-})();
\ No newline at end of file
diff --git a/moksha/api/widgets/chat/static/themes/dojo/gui.js b/moksha/api/widgets/chat/static/themes/dojo/gui.js
deleted file mode 100644
index b042620..0000000
--- a/moksha/api/widgets/chat/static/themes/dojo/gui.js
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-if (!window.WillowChat) {
- Willowchat = {}
-}
-
-if (!WillowChat.guis) {
- WillowChat.guis = {}
-}
-
-if (!WillowChat.guis.map) {
- WillowChat.guis.map = {}
-}
-
-var willowConnection = null;
-WillowChat.guis.map.dojo = WillowChat.guis.DojoGui = function(wc, opts) {
- console.log("Neat? ", wc, opts);
- willowConnection = wc;
-}
diff --git a/moksha/api/widgets/chat/static/themes/dojo/index.html b/moksha/api/widgets/chat/static/themes/dojo/index.html
deleted file mode 100644
index fe50981..0000000
--- a/moksha/api/widgets/chat/static/themes/dojo/index.html
+++ /dev/null
@@ -1,226 +0,0 @@
-<html>
- <head>
- <link rel="stylesheet" type="text/css" href="style.css">
-<script src="http://localhost:9000/static/Orbited.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
-<script src="gui.js"></script>
- <script>
- TCPSocket = Orbited.TCPSocket
- document.domain = document.domain
-/* Orbited.system.enabled = true;
- Orbited.loggers['Orbited.XSDR'].enabled = false
- Orbited.loggers['Orbited.CometSession'].enabled = true
- Orbited.loggers['Orbited.TCPSocket'].enabled = true
- Orbited.loggers['XSDRBridge'].enabled = true
- Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
- Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
- Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
- Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true
- Orbited.loggers['WC.c.IRCClient'].enabled = true
-*/
- </script>
-
-
- <link rel="stylesheet"
- href="http://o.aolcdn.com/dojo/1.2/dijit/themes/soria/soria.css">
- <!-- load Dojo, and all the required modules -->
-
- <script type="text/javascript">
-
- djConfig = {
- isDebug: true,
- baseUrl: "./",
- xdWaitSeconds: 10,
- parseOnLoad: true
- };
- </script>
-
- <script src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js" ></script>
-
- <script>
-
- dojo.require("dijit.layout.BorderContainer");
- dojo.require("dijit.layout.AccordionContainer");
- dojo.require("dijit.layout.ContentPane");
- dojo.require("dijit.layout.TabContainer");
-
- dojo.require("dijit.form.TextBox");
- dojo.require("dijit.form.Button");
- dojo.require("dijit.Dialog");
-
-
- var username = null;
- var roomMembers = [];
-
- dojo.addOnLoad(function() {
- dijit.byId("logindialog").show();
- console.log("hi?", willowConnection);
-
-
- var mssageBox = dojo.byId("messageBox");
- dojo.connect(mssageBox, "keyup", function(e) {
- var key = e.charCode || e.keyCode || 0
- if (key == dojo.keys.ENTER) {
- var msg = mssageBox.value;
- willowConnection.sendMessage(msg)
- willowConnection.onMessage(username, msg);
- mssageBox.value = "";
- };
- });
-
-
- });
-
- function login(nickname) {
- username = nickname;
- willowConnection.connect( {
- username: nickname
- });
-
-
-
-
- willowConnection.onConnect = function(data) {
- /* This is somewhat important -- without this IE can run into some
- * issues with reconnecting
- */
-
- window.onbeforeunload = function() {
- if (willowConnection.readyState == willowConnection.READY_STATE_CONNECTED) {
- return 'Are you sure you want to quit and lose the chat connection?';
- }
- };
- window.onunload = function() {
- if (willowConnection.readyState == willowConnection.READY_STATE_CONNECTED) {
- willowConnection.disconnect();
- }
- }
-
-
- // $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
- for (var i = 0; i < willowConnection.presence.length; ++i) {
- addName(willowConnection.presence[i]);
- console.log("who?", willowConnection.presence[i]);
- }
- updateMembers();
- console.log('connected', data, willowConnection.presence)
- }
- willowConnection.onMessage = function(sender, message) {
- console.log('msg', sender, message);
- chatArea.domNode.innerHTML += "<div>" + sender + ": " + message + "</div>";
- scrollDown();
- /* var messagediv = $('<div class="message"></div>');
-
- if (sender == username) {
- messagediv.addClass("self");
- }
- if (isSubstring(username, message)) {
- messagediv.addClass("mentioned");
- }
- messagediv.html('<span class="user">' + sender + ':</span> ' +
- sanitize(message))
- .appendTo("#history");
- scrollDown();*/
- }
- willowConnection.onAction = function(s, m) { console.log('action', s, m); }
-
- willowConnection.onJoin = function(joiner) {
- console.log('join', joiner);
- addName(joiner);
- updateMembers();
- chatArea.domNode.innerHTML += "<span class='user'>" + joiner + "</span> has joined<br/>";
- scrollDown();
- }
-
- willowConnection.onLeave = function(leaver) {
- console.log('leave', leaver);
- var idx = -1;
- for(var i = 0; idx > -1 && i < roomMembers.length; i++) {
- if(leaver == roomMembers[i]) {
- idx = i;
- }
- }
- roomMembers.splice(i, 1);
- _updateMemberDisplay();
- }
-
- willowConnection.onDisconnect = function() { console.log('disconneted'); roomMembers = []; _updateMemberDisplay(); dijit.byId("logindialog").show();}
- willowConnection.onUsernameTaken = function() {
- console.log('onUsernameTaken', username);
- username += '_'
- try {
- willowConnection.rename(username);
- console.log('rename sent');
- }
- catch(e) {
- console.log('rename failed:', e)
- }
- }
-
-
-
-
-
- }
-
- function addName(name) {
- roomMembers.push(name);
- // presenceContainer.domNode.innerHTML += name + "<br/>";
- }
-
-
- function updateMembers() {
- roomMembers.sort();
- _updateMemberDisplay();
- }
-
- function _updateMemberDisplay() {
- presenceContainer.domNode.innerHTML = "";
- for(var i = 0; i < roomMembers.length; i++) {
- var member = roomMembers[i];
- presenceContainer.domNode.innerHTML += member + "<br/>";
- }
- }
-
- function scrollDown() {
- chatArea.domNode.scrollTop = chatArea.domNode.scrollHeight;
- }
-
- function logout() {
- willowConnection.disconnect();
- }
-
-
-
-
- </script>
-
-
- </head>
- <body class="soria" >
- <div dojoType="dijit.Dialog" id="logindialog" title="Chat"
- execute="login(arguments[0]['name'] ? arguments[0]['name'] : 'guest');">
- <label for="name">Nickname: </label>
- <input dojoType=dijit.form.TextBox type="text" maxlength="16" name="name" id="name" value="">
- <button dojoType=dijit.form.Button type="submit">OK</button>
- </div>
-
- <div>
- <div dojoType="dijit.layout.BorderContainer" style="width:100%; height:100%">
- <div dojoType="dijit.layout.ContentPane" region="top" style="border:1px solid gray; height: 20px; background: #eee;">
- WillowChat now with Dojo <button dojoType=dijit.form.Button onClick="logout();" style="font-size:10px;" type="submit">Leave</button>
- </div>
- <div dojoType="dijit.layout.ContentPane" region="left" jsId="presenceContainer" style="width: 100px; border:1px solid gray; background: #eee;" splitter="true" minSize="0" maxSize="250">
-
- </div>
- <div dojoType="dijit.layout.ContentPane" region="center" jsId="chatArea" style="border:1px solid gray; background: #eee;" >
-
- </div>
- <div dojoType="dijit.layout.ContentPane" region="bottom" style="height: 50px; border:1px solid gray; background: #eee;" >
- <textarea id="messageBox" style="width:90%"></textarea>
- </div>
- </div>
- </div>
-</html>
diff --git a/moksha/api/widgets/chat/static/themes/dojo/style.css b/moksha/api/widgets/chat/static/themes/dojo/style.css
deleted file mode 100644
index 29f0a19..0000000
--- a/moksha/api/widgets/chat/static/themes/dojo/style.css
+++ /dev/null
@@ -1,151 +0,0 @@
-html, body {
- padding: 0px;
- margin: 0px;
- border: none;
- _overflow: hidden;
- }
-#presenceToggle {
- border: 1px solid black;
- position: absolute;
- right: 1px;
- top: 1px;
- padding: 2px;
- background: #005522;
- color: white;
- font-weight: bold;
- cursor: pointer;
-}
-#presenceToggle:hover {
-}
-#presence {
- float: right;
- border: 1px solid gray;
- width: 130px;
- height: 83%;
- margin-left: 3px;
- margin-bottom: 0px;
- overflow: hidden;
-}
-#presenceTitle {
- text-decoration: underline;
-}
-#presenceList {
- overflow: auto;
- height: 90%;
-}
-#history {
- border: 1px solid gray;
- height: 83%;
- overflow: auto;
- margin-bottom: 0px;
-}
-#historySpacer {
- border: 1px solid red;
-}
-#inputBar {
- margin-top: 0px;
- height: 15%;
-}
-#inputBar textarea {
- width: 100%;
- height: 100%;
- border: 1px solid gray;
-}
-
-
-
-#popup {
- position: absolute;
- height: 100%;
- width: 70%;
- left: 15%;
- z-index: 2;
-}
-
-#popupOuter {
- height: 100%;
- width: 100%;
- overflow: hidden;
- position: relative;
-}
-#popupOuter[id] {display: table; position: static;}
-
-#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
-#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
-
-#popupContent {position: relative; top: -50%} /* for explorer only */
-/* optional: #popupContent[id] {position: static;} */
-
-#popupContent {
- font-size: 120%;
- text-align:center;
- background: #005522;
- color: white;
- border: 5pt solid #50A572;
- padding: 8px;
- padding-bottom: 20px;
- width: 100%;
-}
-#popupContent p {
- font-size: 150%;
-}
-
-#absorbClicks {
- position:absolute;
- top:0;
- left:0;
- width:100%;
- height:100%;
-}
-
-
-#history div {
- background-color:#eeffee;
- padding:.2em;
- padding-left:1.5em;
- text-indent: -1em;
- border-bottom: 1px dotted #ccc;
-}
-#history .message .user {
- width:5em;
- font-weight: bold;
- color:#DD7200;
- padding-right:.2em;
- text-align:right;
-}
-#history .message.self .user{
- color: #B42600;
-}
-#history .message.mentioned{
- background-color: #d5c5ff;
-}
-#history .message.private{
- background-color: #ccc;
-}
-#history .message.ctcp {
- background-color: #f0f;
-}
-#history .action {
- color: #D68850;
- font-style:italic;
-}
-#history .action {
- color: #A94C3B;
- font-style:italic;
-}
-#history .informative {
- font-size: 85%;
- font-style: italic;
- color:#999;
- text-align:center;
- padding:.3em;
-}
-#presenceList .user_entry {
- font-size: 90%;
- padding:.2em;
- padding-left:8pt;
- border-bottom: 1px dotted #ccc;
-}
-
-
-
diff --git a/moksha/api/widgets/chat/static/themes/simple/chrome.js b/moksha/api/widgets/chat/static/themes/simple/chrome.js
deleted file mode 100644
index 4379ce6..0000000
--- a/moksha/api/widgets/chat/static/themes/simple/chrome.js
+++ /dev/null
@@ -1,83 +0,0 @@
-(function() {
-/* Boilerplate
- */
-if (!window.WillowChat) {
- Willowchat = {}
-}
-
-if (!WillowChat.chrome) {
- WillowChat.chrome = {}
-}
-
-if (!WillowChat.chrome.map) {
- WillowChat.chrome.map = {}
-}
-
-
-WillowChat.chrome.map.simple = WillowChat.chrome.SimpleChrome = function(container, opts) {
- /* Set configured height
- */
- container.style.width = opts.width + 'px'
- container.style.height = opts.height + 'px'
- container.style.background = "white";
- var toggles = document.createElement('div')
- toggles.setAttribute('id', 'willowchatToggles')
- var floatToggle = document.createElement('div')
- floatToggle.setAttribute('id', 'willowchatFloat')
- floatToggle.innerHTML = "↑"
- var minToggle = document.createElement('div')
- minToggle.setAttribute('id', 'willowchatMin')
- minToggle.innerHTML = "-"
- floatToggle.setAttribute('style', "float: left;")
- minToggle.setAttribute('style', "float: left;")
- var toggleElements = [ minToggle, floatToggle]
- for (var i = 0; i < 2; ++i) {
- var t = toggleElements[i]
- t.style.width = "20px"
- t.style.height = "20px"
- t.style.textAlign = "center"
- t.style.border = "1px solid black"
- t.style.padding = "2px"
- t.style.color = "white"
- t.style.fontWeight = "bold"
- t.style.background = "#005522"
- t.style.cursor = "pointer"
- t.style.cssFloat = "left"
- t.style.styleFloat = "left"
- t.style.display = "none"
- }
- container.appendChild(toggles)
- toggles.appendChild(floatToggle)
- toggles.appendChild(minToggle)
-
- /* Should it be floating?
- */
- if (opts.floating) {
- container.style.position = 'absolute';
- container.style.bottom = '0';
- container.style.right = '0';
- minToggle.style.display = "block"
- toggles.style.position = "absolute"
- toggles.style.top = "1px"
- toggles.style.left = "1px"
- if (opts.reposition) {
- container.parentNode.removeChild(container)
- document.body.appendChild(container)
-
- }
- }
- else {
- var ifr = container.getElementsByTagName('iframe')[0]
- toggles.style.marginBottom="-10px"
- ifr.style.marginTop="10px"
- container.removeChild(ifr)
- container.appendChild(ifr)
-// toggles.style.marginBottom = "-5px";
- }
- if (opts.floatingToggle) {
- floatToggle.style.display = "block"
- }
- toggles.style.border = "1ps solid yellow"
-}
-
-})();
diff --git a/moksha/api/widgets/chat/static/themes/simple/gui.js b/moksha/api/widgets/chat/static/themes/simple/gui.js
deleted file mode 100644
index 2b5083f..0000000
--- a/moksha/api/widgets/chat/static/themes/simple/gui.js
+++ /dev/null
@@ -1,216 +0,0 @@
-(function() {
-
-if (!window.WillowChat) {
- console.log('no willochat found in gui?');
- Willowchat = {}
-}
-
-if (!WillowChat.guis) {
- WillowChat.guis = {}
-}
-
-if (!WillowChat.guis.map) {
- WillowChat.guis.map = {}
-}
-var ENTER_KEY = 13
-WillowChat.guis.map.simple = WillowChat.guis.SimpleGui = function(wc, opts) {
- var self = this;
- self.presenceShown = true;
- var logger = Orbited.getLogger('WillowChatTest');
-// logger.enabled = true;
- var username = null;
- var presence = {}
-
- $('#nickname').focus();
- $('#nickname').keypress( function(e) {
- var key = e.charCode || e.keyCode || 0
- if (key == ENTER_KEY) {
- self.connect();
- };
- });
- $('#chatboxInput').keypress(function(e) {
- var key = e.charCode || e.keyCode || 0;
- if (key == ENTER_KEY) {
- self.sendMessage();
- return false;
- };
- });
- $("#popupContent p").html(opts.greeting)
- $("#presenceToggle").click(function() {
- if (self.presenceShown) {
- self.presenceShown = false;
- $("#presence").hide()
- $("#presenceToggle").html('←');
- }
- else {
- self.presenceShown = true;
- $("#presence").show();
- $("#presenceToggle").html('→');
- }
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- $('#chatboxInput').focus();
- }
- else {
- $('#nickname').focus();
- }
- })
- var scrollDown = function() {
- var box = $('#history')[0]
- box.scrollTop = box.scrollHeight;
- }
- var isSubstring = function (sub, str) {
- // case insensitive substring test
- return str.toLowerCase().indexOf(sub.toLowerCase()) >= 0;
- };
- var sanitize = (function(str) {
- // See http://bigdingus.com/2007/12/29/html-escaping-in-javascript/
- var MAP = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- };
- var repl = function(c) { return MAP[c]; };
- return function(s) {
- return s.replace(/[&<>'"]/g, repl);
- };
- })();
-
- // TODO: test this out
- var userRenamed = function(oldname, newname) {
- $("<div class='informative rename'></div>")
- .html("<span class='user'>" + oldname + "</span> is now known as " +
- "<span class='user'>" + newname + "</span>")
- .appendTo("#history");
- scrollDown();
- $("#user_" + oldname)
- .attr("id", "user_" + newname)
- .html(newname);
- }
-
- var addName = function (name) {
- presence[name] = 1
- $('<div class="user_entry" id="user_' + name + '">' + name + '</div>')
- .appendTo("#presenceList");
- };
-
- var removeName = function (name) {
- delete presence[name];
- $(".user_list #user_" + name).remove()
- };
-
- var sortNames = function () {
- $('#presenceList').empty();
- var list = [];
- for (var user in presence) {
- list.push(user);
- };
- list.sort()
- for (var i=0; i < list.length; i++) {
- var user = list[i];
- $('<div class="user_entry" id="user_' + user + '">' + user + '</div>')
- .appendTo("#presenceList");
- };
- };
- self.connect = function() {
- username = $("#nickname").val();
- if (!username) {
- logger.debug('please enter a username');
- return
- }
- $('#popup, #absorbClicks').hide();
- $('#chatboxInput').focus();
- $('#chatboxInput').val('')
-
- connected = true;
- wc.connect( {
- username: username
- })
- wc.onConnect = function(data) {
- /* This is somewhat important -- without this IE can run into some
- * issues with reconnecting
- */
-
- window.onbeforeunload = function() {
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- return 'Are you sure you want to quit and lose the chat connection?';
- }
- };
- window.onunload = function() {
- if (wc.readyState == wc.READY_STATE_CONNECTED) {
- wc.disconnect();
- }
- }
-
-
- $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
- for (var i = 0; i < wc.presence.length; ++i) {
- addName(wc.presence[i]);
- }
- sortNames();
- logger.debug('connected', data, wc.presence)
- }
- wc.onMessage = function(sender, message) {
- logger.debug('msg', sender, message);
- var messagediv = $('<div class="message"></div>');
-
- if (sender == username) {
- messagediv.addClass("self");
- }
- if (isSubstring(username, message)) {
- messagediv.addClass("mentioned");
- }
- messagediv.html('<span class="user">' + sender + ':</span> ' +
- sanitize(message))
- .appendTo("#history");
- scrollDown();
- }
- wc.onAction = function(s, m) { logger.debug('action', s, m); }
-
- wc.onJoin = function(joiner) {
- logger.debug('join', joiner);
- addName(joiner);
- sortNames();
- $("<div class='informative join'></div>")
- .html("<span class='user'>" + joiner + '</span> has joined')
- .appendTo("#history");
- scrollDown();
- }
- wc.onLeave = function(leaver) {
- logger.debug('leave', leaver);
- removeName(leaver);
- $("<div class='informative part'></div>")
- .html("<span class='user'>" + leaver + '</span> left')
- .appendTo("#history");
- scrollDown();
- }
- wc.onDisconnect = function() { logger.debug('disconneted'); }
- wc.onUsernameTaken = function() {
- logger.debug('onUsernameTaken', username);
- username += '_'
- try {
- wc.rename(username);
- logger.debug('rename sent');
- }
- catch(e) {
- logger.debug('rename failed:', e)
- }
- }
- }
- self.sendMessage = function() {
- var msg = $('#chatboxInput').val();
- wc.sendMessage(msg)
- $('#chatboxInput').val('');
- // the WillowChat server will not echo our message back, so simulate a send.
- wc.onMessage(username, msg)
- }
- self.sendAction = function() {
- var msg = getMessage()
- wc.sendAction(msg);
- logger.debug('action', username, msg)
- }
-
-}
-})()
-
diff --git a/moksha/api/widgets/chat/static/themes/simple/index.html b/moksha/api/widgets/chat/static/themes/simple/index.html
deleted file mode 100644
index ee659cf..0000000
--- a/moksha/api/widgets/chat/static/themes/simple/index.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<html>
- <head>
- <link rel="stylesheet" type="text/css" href="style.css">
-<!-- @@ HACK -->
-<script src="http://localhost:9000/static/Orbited.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
-<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
-<script src="/toscawidgets/resources/tw.jquery.base/static/javascript/jquery-1.2.6.pack.js"></script>
- <script src="gui.js"></script>
- <script>
- TCPSocket = Orbited.TCPSocket
- document.domain = document.domain
-
-/* Orbited.system.enabled = true;
- Orbited.loggers['Orbited.XSDR'].enabled = false
- Orbited.loggers['Orbited.CometSession'].enabled = true
- Orbited.loggers['Orbited.TCPSocket'].enabled = true
- Orbited.loggers['XSDRBridge'].enabled = true
- Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
- Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
- Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
- Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true
- Orbited.loggers['WC.c.IRCClient'].enabled = true
-*/
- </script>
-
- </head>
- <body>
-<div id="popup">
-<div id="popupOuter">
- <div id="popupMiddle">
- <div id="popupContent">
- <p>Greeting</p>
- <label for="nickname">Nickname:</label>
- <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
- </div>
- </div>
-</div>
-</div>
-
-
- <div id="absorbClicks"></div>
- <div id="presenceToggle">
- →
- </div>
- <div id="presence">
- <div id="presenceTitle">Presence</div>
- <div id="presenceList">
- </div>
- </div>
- <div id="history">
- </div>
- <div id="inputBar">
- <textarea id="chatboxInput"></textarea>
- </div>
- </body>
-</html>
diff --git a/moksha/api/widgets/chat/static/themes/simple/style.css b/moksha/api/widgets/chat/static/themes/simple/style.css
deleted file mode 100644
index 29f0a19..0000000
--- a/moksha/api/widgets/chat/static/themes/simple/style.css
+++ /dev/null
@@ -1,151 +0,0 @@
-html, body {
- padding: 0px;
- margin: 0px;
- border: none;
- _overflow: hidden;
- }
-#presenceToggle {
- border: 1px solid black;
- position: absolute;
- right: 1px;
- top: 1px;
- padding: 2px;
- background: #005522;
- color: white;
- font-weight: bold;
- cursor: pointer;
-}
-#presenceToggle:hover {
-}
-#presence {
- float: right;
- border: 1px solid gray;
- width: 130px;
- height: 83%;
- margin-left: 3px;
- margin-bottom: 0px;
- overflow: hidden;
-}
-#presenceTitle {
- text-decoration: underline;
-}
-#presenceList {
- overflow: auto;
- height: 90%;
-}
-#history {
- border: 1px solid gray;
- height: 83%;
- overflow: auto;
- margin-bottom: 0px;
-}
-#historySpacer {
- border: 1px solid red;
-}
-#inputBar {
- margin-top: 0px;
- height: 15%;
-}
-#inputBar textarea {
- width: 100%;
- height: 100%;
- border: 1px solid gray;
-}
-
-
-
-#popup {
- position: absolute;
- height: 100%;
- width: 70%;
- left: 15%;
- z-index: 2;
-}
-
-#popupOuter {
- height: 100%;
- width: 100%;
- overflow: hidden;
- position: relative;
-}
-#popupOuter[id] {display: table; position: static;}
-
-#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
-#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
-
-#popupContent {position: relative; top: -50%} /* for explorer only */
-/* optional: #popupContent[id] {position: static;} */
-
-#popupContent {
- font-size: 120%;
- text-align:center;
- background: #005522;
- color: white;
- border: 5pt solid #50A572;
- padding: 8px;
- padding-bottom: 20px;
- width: 100%;
-}
-#popupContent p {
- font-size: 150%;
-}
-
-#absorbClicks {
- position:absolute;
- top:0;
- left:0;
- width:100%;
- height:100%;
-}
-
-
-#history div {
- background-color:#eeffee;
- padding:.2em;
- padding-left:1.5em;
- text-indent: -1em;
- border-bottom: 1px dotted #ccc;
-}
-#history .message .user {
- width:5em;
- font-weight: bold;
- color:#DD7200;
- padding-right:.2em;
- text-align:right;
-}
-#history .message.self .user{
- color: #B42600;
-}
-#history .message.mentioned{
- background-color: #d5c5ff;
-}
-#history .message.private{
- background-color: #ccc;
-}
-#history .message.ctcp {
- background-color: #f0f;
-}
-#history .action {
- color: #D68850;
- font-style:italic;
-}
-#history .action {
- color: #A94C3B;
- font-style:italic;
-}
-#history .informative {
- font-size: 85%;
- font-style: italic;
- color:#999;
- text-align:center;
- padding:.3em;
-}
-#presenceList .user_entry {
- font-size: 90%;
- padding:.2em;
- padding-left:8pt;
- border-bottom: 1px dotted #ccc;
-}
-
-
-
diff --git a/moksha/api/widgets/chat/static/willowchat.js b/moksha/api/widgets/chat/static/willowchat.js
deleted file mode 100644
index 0561630..0000000
--- a/moksha/api/widgets/chat/static/willowchat.js
+++ /dev/null
@@ -1,337 +0,0 @@
-(function() {
-
-Orbited.settings.streaming = true
-
-if (window.addEventListener) {
- window.addEventListener('load', function() { WillowChat.util.setup(); }, false);
-}
-else if (window.attachEvent) {
- window.attachEvent('onload', function() { WillowChat.util.setup(); });
-}
-
-
-if (!window.WillowChat) {
- WillowChat = {}
-}
-WillowChat.settings = {}
-WillowChat.settings.hostname = document.domain
-WillowChat.settings.port = (location.port.length > 0) ? location.port : 80
-WillowChat.settings.defaultTheme = 'simple'
-WillowChat.settings.client = 'irc'
-WillowChat.clients = {}
-WillowChat.clients.map = {}
-WillowChat.util = {}
-
-
-if (!WillowChat.guis) {
- WillowChat.guis = {}
-}
-if (!WillowChat.guis.map) {
- WillowChat.guis.map = {}
-}
-
-if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function(n) {
- for (var i = 0; i < this.length; ++i) {
- if (this[i] === n) {
- return i
- }
- }
- return -1
- }
-}
-
-
-
-
-WillowChat.util.setup = function() {
- // TODO: first setup from remote and url
- // TODO: this is a *really* ugly way to do this... Fix it
-
- try {
- var i = location.href.indexOf('&opts=')
- var opts = JSON.parse(unescape(location.href.slice(i+6)))
- }
- catch(e) {
- // If the options aren't there, then someone must be trying to use this
- // library manually, which we want to allow.
- return
- }
- // TODO: we actually need to get the "backend" hostname value
- WillowChat.settings.hostname = 'localhost'
- var client = new WillowChat.clients.map[WillowChat.settings.client](opts)
- var gui = new WillowChat.guis.map[opts.theme ? opts.theme : WillowChat.settings.defaultTheme](client, opts)
-
- return gui
-}
-
-
-
-
-
-WillowChat.BaseClient = function() {
- var self = this;
- self.readyState = self.READY_STATE_INITIALIZED;
- self.onUsernameTaken = function() { };
- self.onConnect = function() { };
- self.onPresence= function() { };
- self.onDisconnect = function() { };
- self.onMessage = function() { };
- self.onJoin = function() { };
- self.onLeave = function() { };
- self.onAction = function() { };
- self.onRename = function() { };
-}
-
-WillowChat.BaseClient.prototype.connect = function(options) {
- var self = this;
- if (!this.doConnect) {
- throw new Error("NotImplemented");
- }
- var username = options.username
- if (!username) {
- throw new Error("Missing username")
- }
- var roomId = options.roomId ? options.roomId : self.opts.roomId
- if (!roomId) {
- throw new Error("Missing roomId")
- }
- var hostname = options.hostname
- var port = options.port
- if (!port) {
- port = 6667
- }
- if (!hostname) {
- if (!self.opts.addr) {
- throw new Error("missing connection information");
- }
- hostname = self.opts.addr[0]
- port = self.opts.addr[1]
- }
- return self.doConnect(username, roomId, hostname, port);
-};
-WillowChat.BaseClient.prototype.rename = function(newName) {
- throw new Error("NotImplemented");
-};
-WillowChat.BaseClient.prototype.sendMessage = function(msg) {
- throw new Error("NotImplemented");
-};
-WillowChat.BaseClient.prototype.sendAction = function(action) {
- throw new Error("NotImplemented");
-};
-WillowChat.BaseClient.prototype.disconnect = function() {
- throw new Error("NotImplemented");
-};
-WillowChat.BaseClient.prototype.READY_STATE_INITIALIZED = 0;
-WillowChat.BaseClient.prototype.READY_STATE_CONNECTING = 1;
-WillowChat.BaseClient.prototype.READY_STATE_CONNECTED = 2;
-WillowChat.BaseClient.prototype.READY_STATE_DISCONNECTED = 3;
-
-
-WillowChat.clients.IRCClient = function(opts) {
- var self = this;
- self._conn = null;
- self.opts = opts
-};
-
-WillowChat.clients.IRCClient.prototype = new WillowChat.BaseClient();
-
-WillowChat.clients.IRCClient.prototype.logger = Orbited.getLogger('WC.c.IRCClient');
-WillowChat.clients.map.irc = WillowChat.clients.IRCClient
-
-WillowChat.clients.IRCClient.prototype.disconnect = function() {
- var self = this;
- if (self.readyState == self.READY_STATE_DISCONNECTED) {
- return
- }
- self.readyState = self.READY_STATE_DISCONNECTED;
- // TODO: would be nice to have a quit message or something
- self._conn.reset()
- self._conn = null;
- self.onDisconnect()
-}
-
-
-WillowChat.clients.IRCClient.prototype.doConnect = function(username, roomId, hostname, port) {
- var self = this;
- self.username = username
- self.roomId = roomId;
- if (self.roomId[0] != '#') {
- self.roomId = '#' + self.roomId
- }
- self._conn = new IRCClient()
- self.presence = []
- var irc = self._conn
- // By default, assume the irc server is on the same host as the willowchat
- // server
-
- function parseName(identity) {
- // TODO remove privileges from name head.
- return identity.split("!", 1)[0];
- }
- irc.onclose = function() {
- self.disconnect();
- }
- irc.onopen = function() {
- irc.ident(self.username, '8 *', self.username);
- irc.nick(self.username);
- }
-;;; self.logger.debug('do irc.connect', hostname, port)
- irc.connect(hostname, port)
- self.readyState = self.READY_STATE_CONNECTING
-
- irc.onJOIN = function(command) {
-;;; self.logger.debug('irc.onJOIN', command)
- // Ignore initial onJoin (before names)
- var joiner = parseName(command.prefix)
-;;; self.logger.debug('irc.onJoin.a')
- self.logger.debug('self.presence', self.presence, Orbited.JSON.stringify(self.presence))
- if (self.presence.indexOf(joiner) == -1) {
-;;; self.logger.debug('irc.onJoin.b')
- self.presence.push(joiner)
- }
-;;; self.logger.debug('irc.onJoin.c')
- if (self.readyState == self.READY_STATE_CONNECTED) {
-;;; self.logger.debug('irc.onJoin.d')
- self.onJoin(joiner);
- }
-;;; self.logger.debug('irc.onJoin.e')
- }
- irc.onPART = irc.onQUIT = function(command) {
- var leaver = parseName(command.prefix);
- var message = command.args.join(" ");
- var i = self.presence.indexOf(leaver)
- if (i != -1) {
- self.presence.splice(i,1)
- }
- self.onLeave(leaver);
- }
- irc.onNICK = function(command) {
- // See http://tools.ietf.org/html/rfc2812#section-3.1.2
- var previousNick = parseName(command.prefix);
- var i = self.presence.indexOf(previousNick)
- if (i != -1) {
- self.presence.splice(i,1)
- }
- var newNick = command.args[0];
- if (self.presence.indexOf(newNick) == -1) {
- self.presence.push(newNick)
- }
- self.onPresence()
- };
-
- irc.onPRIVMSG = function(command) {
- var sender = parseName(command.prefix);
- var target = command.args[0];
- var message = command.args[1];
- self.onMessage(sender, message);
- }
- irc.onACTION = function(command) {
-;;; self.logger.debug('irc.onACTION', command)
- var sender = parseName(command.prefix);
- var message = command.args.slice(1).join(" ")
- self.onAction(sender, message);
- }
-
- irc.onresponse = function(command) {
- self.logger.debug('onresponse', command)
- var responseCode = parseInt(command.type);
- if (responseCode == 353) {
- // 353 is the code for RPL_NAMEREPLY.
-
- // The args are:
- //
- // """
- // <target> ( "=" / "*" / "@" ) <channel>
- // :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
- //
- // - "@" is used for secret channels, "*" for private
- // channels, and "=" for others (public channels).
- // """ -- rfc2812
- var channel = command.args[2];
- if (channel != self.roomId)
- return;
- var partialUserList = command.args[3].split(' ');
- for (var i = 0, l = partialUserList.length; i < l; ++i) {
- // trim the name
- var name = partialUserList[i].replace(/^\s+|\s+$/g,"");
- if (name[0] == '@' || name[0] == '+') {
- name = name.slice(1);
- }
- if (name == "" || self.presence.indexOf(name) != -1) {
- continue;
- }
- self.presence.push(name)
- }
- }
- else if (responseCode == 366) {
- // 366 is the code for RPL_ENDOFNAMES.
- self.readyState = self.READY_STATE_CONNECTED
- self.onConnect();
- }
- else if (responseCode == 376) {
- // 376 RPL_ENDOFMOTD
- // :End of /MOTD command"
- irc.join(self.roomId);
- }
- }
- irc.onerror = function(command) {
- self.logger.debug('onerror', command)
- var responseCode = parseInt(command.type);
- if (responseCode == 431 || responseCode == 432 || responseCode == 433) {
- // 431 ERR_NONICKNAMEGIVEN
- // 432 ERR_ERRONEUSNICKNAME
- // 433 ERR_NICKNAMEINUSE
- self.onUsernameTaken();
- }
-/* else if (responseCode == 451) {
- // 451 is the code for ERR_NOTREGISTERED
- // Probably means the nick we chose was taken
- }
-*/
- }
-}
-WillowChat.clients.IRCClient.prototype.rename = function(newUserName) {
- var self = this;
- var irc = self._conn;
- switch(self.readyState) {
- case self.READY_STATE_CONNECTING:
- case self.READY_STATE_CONNECTED:
- irc.nick(newUserName);
- self.userName = newUserName;
- break;
- default:
- throw new Error("invalid readyState")
- }
-}
-
-WillowChat.clients.IRCClient.prototype.sendMessage = function(msg) {
- var self = this;
- if (self.readyState != self.READY_STATE_CONNECTED) {
- throw new Error('invalid readyState: ' + self.readyState);
- }
- var irc = self._conn;
- irc.privmsg(self.roomId, msg);
-}
-
-WillowChat.clients.IRCClient.prototype.sendAction = function(action) {
- var self = this;
- if (self.readyState != self.READY_STATE_CONNECTED) {
- throw new Error('invalid readyState: ' + self.readyState);
- }
- var irc = self._conn;
- irc.action(self.roomId, action);
-}
-
-
-var createXHR = function () {
- try { return new XMLHttpRequest(); } catch(e) {}
- try { return new ActiveXObject('MSXML3.XMLHTTP'); } catch(e) {}
- try { return new ActiveXObject('MSXML2.XMLHTTP.3.0'); } catch(e) {}
- try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
- try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
- throw new Error('Could not find XMLHttpRequest or an alternative.');
-}
-
-
-})()
diff --git a/moksha/api/widgets/chat/templates/__init__.py b/moksha/api/widgets/chat/templates/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/moksha/api/widgets/chat/templates/bootstrap.mak b/moksha/api/widgets/chat/templates/bootstrap.mak
deleted file mode 100644
index 65ab577..0000000
--- a/moksha/api/widgets/chat/templates/bootstrap.mak
+++ /dev/null
@@ -1,419 +0,0 @@
-(function() {
-var gatherOptions = function(roomOptions, container) {
- var opts = {}
- var containerOptions = [ 'width', 'height', 'roomClass', 'reposition', 'theme' ]
- for (var key in roomOptions) {
- opts[key] = roomOptions[key]
- }
- for (var i = 0; i < containerOptions.length; ++i) {
- var key = containerOptions[i]
- var option = container.getAttribute(key)
- if (option) {
- opts[key] = option
- }
- }
- if (!opts.roomId) {
- var roomId = container.getAttribute('roomId')
- opts.roomId = roomId ? roomId : 'default'
- }
- if (!opts.width) {
- opts.width = 350;
- }
- if (!opts.height) {
- opts.height = 240;
- }
- if (!opts.theme) {
- opts.theme = 'simple'
- }
- if (!opts.greeting) {
- opts.greeting = "Willow Chat"
- }
- return opts
-}
-
-var loaded = function() {
- if (!window.WillowChat) {
- WillowChat = {}
- }
- if (!WillowChat.util) {
- WillowChat.util = {}
- }
- var container = document.getElementById('willowchat');
- if (!container) {
- container = document.createElement('div');
- container.setAttribute('id', 'willowchat');
- }
-
-
- var roomClass = container.getAttribute('roomClass');
- var roomClass= roomClass ? roomClass : 'default'
- s = document.createElement('script')
- var baseurl = 'http://' + WillowChat.hostHeader
- s.src = baseurl + '/apps/chat/rooms?jsonp=WillowChat.util.optionsCallback&op=info&roomClass=' + roomClass
-
- WillowChat.util.optionsCallback = function(result) {
- success = result[0]
- if (!success) {
- throw new Error("Failed: " + result[1])
- }
- room = result[1]
- var opts = gatherOptions(room, container);
- ifr = document.createElement('iframe')
- var staticurl = baseurl + '/toscawidgets/resources/moksha.api.widgets.chat.chat/static'
- ifr.src = '/apps/chat/index?json=1&opts=' + escape(JSON.stringify(opts))
- ifr.style.border = "0px";
- ifr.style.width = "100%";
- ifr.style.height = "100%";
- var chromeCallback = function() {
- container.appendChild(ifr)
- chrome = new WillowChat.chrome.map[opts.theme](container, opts)
- }
- var s = document.createElement('script')
- // TODO: whats the deal with this? Can't we do any better?
- s.src = staticurl + '/themes/' + opts.theme + '/chrome.js?ienocache=' + Math.floor(Math.random()*10000)
- if (s.addEventListener) {
- s.addEventListener('load', chromeCallback, false)
- }
- else if (s.attachEvent) {
- s.attachEvent('onreadystatechange', function() {
- if (s.readyState == "loaded") {
- chromeCallback()
- }
- })
- }
- if (true) {
- var k = 3 + 3
- }
-// var d = document.createElement('div')
-// d.innerHTML = 'go'
-// document.body.appendChild(d)
- document.getElementsByTagName('head')[0].appendChild(s)
- }
- document.getElementsByTagName('head')[0].appendChild(s)
-
-}
-
-$(document).ready(function(){
- if (!window.WillowChat) { WillowChat = {} }; WillowChat.hostHeader = "${host}";
- loaded();
-});
-
-})();
-if (!this.JSON) {
-
-// Create a JSON object only if one does not already exist. We create the
-// object in a closure to avoid creating global variables.
-
- JSON = function () {
-
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- Date.prototype.toJSON = function (key) {
-
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
-
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function (key) {
- return this.valueOf();
- };
-
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
-
-
- function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
- escapeable.lastIndex = 0;
- return escapeable.test(string) ?
- '"' + string.replace(escapeable, function (a) {
- var c = meta[a];
- if (typeof c === 'string') {
- return c;
- }
- return '\\u' + ('0000' +
- (+(a.charCodeAt(0))).toString(16)).slice(-4);
- }) + '"' :
- '"' + string + '"';
- }
-
-
- function str(key, holder) {
-
-// Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
-
-// If the value has a toJSON method, call it to obtain a replacement value.
-
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
-// What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return quote(value);
-
- case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
- return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
- case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
-// Make an array to hold the partial results of stringifying this object value.
-
- gap += indent;
- partial = [];
-
-// If the object has a dontEnum length property, we'll treat it as an array.
-
- if (typeof value.length === 'number' &&
- !(value.propertyIsEnumerable('length'))) {
-
-// The object is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
- v = partial.length === 0 ? '[]' :
- gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' +
- mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
- v = partial.length === 0 ? '{}' :
- gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
- mind + '}' : '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
-
-// Return the JSON object containing the stringify and parse methods.
-
- return {
- stringify: function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
- return str('', {'': value});
- },
-
-
- parse: function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
- var j;
-
- function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' + ('0000' +
- (+(a.charCodeAt(0))).toString(16)).slice(-4);
- });
- }
-
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
- if (/^[\],:{}\s]*$/.
-test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
-replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
-replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
- j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
- throw new SyntaxError('JSON.parse');
- }
- };
- }();
-}
diff --git a/moksha/api/widgets/chat/templates/chat.mak b/moksha/api/widgets/chat/templates/chat.mak
deleted file mode 100644
index a3ab679..0000000
--- a/moksha/api/widgets/chat/templates/chat.mak
+++ /dev/null
@@ -1,31 +0,0 @@
-<script>
- TCPSocket = Orbited.TCPSocket
- document.domain = document.domain;
-</script>
-
-<div id="popup">
-<div id="popupOuter">
- <div id="popupMiddle">
- <div id="popupContent">
- <p>Greeting</p>
- <label for="nickname">Nickname:</label>
- <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
- </div>
- </div>
-</div>
-</div>
-
- <div id="absorbClicks"></div>
- <div id="presenceToggle">
- →
- </div>
- <div id="presence">
- <div id="presenceTitle">Presence</div>
- <div id="presenceList">
- </div>
- </div>
- <div id="history">
- </div>
- <div id="inputBar">
- <textarea id="chatboxInput"></textarea>
- </div>
diff --git a/moksha/widgets/chat/__init__.py b/moksha/widgets/chat/__init__.py
new file mode 100644
index 0000000..5447654
--- /dev/null
+++ b/moksha/widgets/chat/__init__.py
@@ -0,0 +1,17 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from chat import LiveChatWidget, LiveChatFrameWidget
diff --git a/moksha/widgets/chat/chat.py b/moksha/widgets/chat/chat.py
new file mode 100644
index 0000000..98ef860
--- /dev/null
+++ b/moksha/widgets/chat/chat.py
@@ -0,0 +1,50 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors: Luke Macken <lmacken(a)redhat.com>
+
+from tw.api import Widget, JSLink, CSSLink
+from tw.jquery import jquery_js
+
+from moksha.api.widgets.orbited import orbited_js
+
+irc2_js = JSLink(filename='static/irc2.js',
+ javascript=[orbited_js],
+ modname=__name__)
+
+willowchat_js = JSLink(filename='static/willowchat.js',
+ javascript=[jquery_js, irc2_js],
+ modname=__name__)
+
+gui_js = JSLink(filename='static/gui.js',
+ javascript=[willowchat_js],
+ modname=__name__)
+
+willowchat_css = CSSLink(filename='static/style.css', modname=__name__)
+
+
+class LiveChatWidget(Widget):
+ name = 'Chat'
+ params = ['bootstrap']
+ bootstrap = JSLink(link='/apps/chat/bootstrap')
+ template = '<div id="willowchat" reposition="true">${bootstrap}</div>'
+ visible = False
+
+
+class LiveChatFrameWidget(Widget):
+ template = 'mako:moksha.api.widgets.chat.templates.chat'
+ javascript = [orbited_js, willowchat_js, irc2_js, gui_js, jquery_js]
+ css = [willowchat_css]
diff --git a/moksha/widgets/chat/controllers/__init__.py b/moksha/widgets/chat/controllers/__init__.py
new file mode 100644
index 0000000..10fd377
--- /dev/null
+++ b/moksha/widgets/chat/controllers/__init__.py
@@ -0,0 +1,17 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from chat import ChatController
diff --git a/moksha/widgets/chat/controllers/chat.py b/moksha/widgets/chat/controllers/chat.py
new file mode 100644
index 0000000..b413a00
--- /dev/null
+++ b/moksha/widgets/chat/controllers/chat.py
@@ -0,0 +1,114 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors: Luke Macken <lmacken(a)redhat.com>
+
+import logging
+log = logging.getLogger(__name__)
+
+import urlparse
+urlparse.uses_netloc.append('irc')
+
+from tg import expose, tmpl_context, config
+from pylons import request
+
+from moksha.lib.base import BaseController
+from moksha.api.widgets.chat import LiveChatFrameWidget
+
+chat_frame_widget = LiveChatFrameWidget('chat_frame')
+
+
+class ChatController(BaseController):
+
+ def __init__(self, *args, **kw):
+ super(ChatController, self).__init__(*args, **kw)
+ self.config = {}
+ backend = config.get('chat.backend')
+ if not backend:
+ log.info('No `chat.backend` defined; disabling chat functionality')
+ return
+ backend = urlparse.urlparse(backend)
+ if hasattr(backend, 'scheme'): # Python 2.5+
+ self.config['backendProtocol'] = backend.scheme
+ self.config['backendAddr'] = [backend.hostname, backend.port]
+ else: # Python 2.4
+ self.config['backendProtocol'] = backend[0]
+ host, port = backend[1].split(':')
+ self.config['backendAddr'] = [host, port]
+ self.config['startBuiltin'] = config.get('chat.builtin', False)
+ self.config['rooms'] = {}
+ display_opts = {
+ 'floating': True, 'floatingToggle': False, 'width': 400 ,
+ 'height': 300, 'theme': 'simple', 'resizable': True,
+ 'greeting': 'Moksha Chat',
+ }
+ for room in config['chat.rooms'].replace(',', ' ').split():
+ self.config['rooms'][room] = {'display': {}}
+ for display_opt, default in display_opts.items():
+ self.config['rooms'][room]['display'][display_opt] = \
+ config.get('chat.%s.display.%s' % (room, display_opt),
+ default)
+ self.config['rooms'][room]['roomAssignmentMode'] = \
+ config.get('chat.%s.roomAssignmentMode' % room, 'static')
+ self.config['rooms'][room]['staticRoomName'] = \
+ config.get('chat.%s.staticRoomName' % room, room)
+
+ log.debug('Chat config = %r' % self.config)
+
+ @expose('mako:moksha.templates.widget')
+ def index(self, *args, **kw):
+ tmpl_context.widget = chat_frame_widget
+ return dict(options={})
+
+ @expose('mako:moksha.api.widgets.chat.templates.bootstrap',
+ content_type='text/javascript')
+ def bootstrap(self, *args, **kw):
+ return dict(host=request.headers['host'])
+
+ @expose('json')
+ def rooms(self, roomClass='default', op=None, jsonp=None):
+ opts = None
+ if op:
+ opts = self.jsonp(getattr(self, 'op_%s' % op,
+ self.op_not_found)(roomClass), jsonp)
+ else:
+ opts = self.jsonp([False, ["op not specified"]], jsonp)
+ return opts
+
+ def jsonp(self, result, jsonp=None):
+ result = str(result).replace('True', 'true').replace('False', 'false')
+ if jsonp:
+ result = jsonp + '(' + result + ')'
+ return result
+
+ def op_info(self, roomClass):
+ if roomClass not in self.config['rooms']:
+ return [False, ['unknown room class: ' + roomClass]]
+ info = self.config['rooms'][roomClass]
+ displayInfo = info.get('display', {})
+ opts = {}
+ opts.update(displayInfo)
+ mode = info.get('roomAssignmentMode', 'static')
+ if mode == 'static':
+ opts['roomId'] = info.get('staticRoomName', 'default')
+ elif mode == 'referrer':
+ opts['roomId'] = request.headers.get('referer', 'default')
+ opts['protocol'] = self.config['backendProtocol']
+ opts['addr'] = self.config['backendAddr']
+ return [True, opts]
+
+ def op_not_found(self):
+ return [False, ['unrecognized op']]
diff --git a/moksha/widgets/chat/static/chat.css b/moksha/widgets/chat/static/chat.css
new file mode 100644
index 0000000..fe0d13f
--- /dev/null
+++ b/moksha/widgets/chat/static/chat.css
@@ -0,0 +1,119 @@
+#signin_popup {
+ width:220pt;
+ padding:2em;
+ padding-bottom:3em;
+ text-align:center;
+ background-color: #A4C9D6;
+ color:#0E3541;
+ border: 5pt solid #195263;
+ position:absolute;
+ top:80pt;
+ left:100pt;
+ z-index:2;
+}
+#nickname {
+ width:90pt;
+}
+#absorb_clicks {
+ position:absolute;
+ top:0;
+ left:0;
+ width:300pt;
+ height:200pt;
+}
+
+.chatbox {
+ width:490pt;
+ font: 100% Verdana, sans-serif;
+ background-color:#24758E;
+ padding:5pt;
+ position:relative;
+}
+.chatbox .left_column {
+ width: 360pt;
+}
+.chatbox .chathistory {
+ width:100%;
+ height:217pt;
+ overflow: auto;
+ background-color: white;
+}
+.chatbox .chathistory div {
+ background-color:#ffffee;
+ padding:.2em;
+ padding-left:1.5em;
+ text-indent: -1em;
+ border-bottom: 1px dotted #ccc;
+}
+.chatbox .chathistory .message .user {
+ width:5em;
+ font-weight: bold;
+ color:#DD7200;
+ padding-right:.2em;
+ text-align:right;
+}
+.chatbox .chathistory .message.self .user{
+ color: #B42600;
+}
+.chatbox .chathistory .message.mentioned{
+ background-color: #d5c5ff;
+}
+.chatbox .chathistory .message.private{
+ background-color: #ccc;
+}
+.chatbox .chathistory .message.ctcp {
+ background-color: #f0f;
+}
+.chatbox .chathistory .action,
+.chatbox .chathistory .action .user {
+ color: #D68850;
+ font-style:italic;
+}
+.chatbox .chathistory .action.self,
+.chatbox .chathistory .action.self .user {
+ color: #A94C3B;
+ font-style:italic;
+}
+.chatbox .chathistory .informative {
+ font-size: 85%;
+ font-style: italic;
+ color:#999;
+ text-align:center;
+ padding:.3em;
+}
+
+.chatbox .chatbox_input {
+ width:100%;
+ height:30pt;
+ margin:0;
+ margin-top:3pt;
+ padding:0;
+ border:0;
+ font-family: Verdana, sans-serif;
+}
+
+.chatbox .user_list {
+ float:right;
+ position: absolute;
+ padding:0;
+ margin:0;
+ right:5pt;
+ top:5pt;
+ background-color:white;
+ width:127pt;
+ height:250pt;
+ overflow:auto;
+}
+.chatbox .user_list .user_entry{
+ padding:.2em;
+ padding-left:8pt;
+ border-bottom: 1px dotted #ccc;
+}
+
+#events {
+ visibility:hidden;
+ border:0;
+ width:0;
+ height:0;
+/* display:none;*/
+}
diff --git a/moksha/widgets/chat/static/chrome.js b/moksha/widgets/chat/static/chrome.js
new file mode 100644
index 0000000..34caca5
--- /dev/null
+++ b/moksha/widgets/chat/static/chrome.js
@@ -0,0 +1,83 @@
+(function() {
+/* Boilerplate
+ */
+if (!window.WillowChat) {
+ Willowchat = {}
+}
+
+if (!WillowChat.chrome) {
+ WillowChat.chrome = {}
+}
+
+if (!WillowChat.chrome.map) {
+ WillowChat.chrome.map = {}
+}
+
+
+WillowChat.chrome.map.simple = WillowChat.chrome.SimpleChrome = function(container, opts) {
+ /* Set configured height
+ */
+ container.style.width = opts.width + 'px'
+ container.style.height = opts.height + 'px'
+ container.style.background = "white";
+ var toggles = document.createElement('div')
+ toggles.setAttribute('id', 'willowchatToggles')
+ var floatToggle = document.createElement('div')
+ floatToggle.setAttribute('id', 'willowchatFloat')
+ floatToggle.innerHTML = "↑"
+ var minToggle = document.createElement('div')
+ minToggle.setAttribute('id', 'willowchatMin')
+ minToggle.innerHTML = "-"
+ floatToggle.setAttribute('style', "float: left;")
+ minToggle.setAttribute('style', "float: left;")
+ var toggleElements = [ minToggle, floatToggle]
+ for (var i = 0; i < 2; ++i) {
+ var t = toggleElements[i]
+ t.style.width = "20px"
+ t.style.height = "20px"
+ t.style.textAlign = "center"
+ t.style.border = "1px solid black"
+ t.style.padding = "2px"
+ t.style.color = "white"
+ t.style.fontWeight = "bold"
+ t.style.background = "#005522"
+ t.style.cursor = "pointer"
+ t.style.cssFloat = "left"
+ t.style.styleFloat = "left"
+ t.style.display = "none"
+ }
+ container.appendChild(toggles)
+ toggles.appendChild(floatToggle)
+ toggles.appendChild(minToggle)
+
+ /* Should it be floating?
+ */
+ if (opts.floating) {
+ container.style.position = 'absolute';
+ container.style.bottom = '0';
+ container.style.right = '0';
+ minToggle.style.display = "block"
+ toggles.style.position = "absolute"
+ toggles.style.top = "1px"
+ toggles.style.left = "1px"
+ if (opts.reposition) {
+ container.parentNode.removeChild(container)
+ document.body.appendChild(container)
+
+ }
+ }
+ else {
+ var ifr = container.getElementsByTagName('iframe')[0]
+ toggles.style.marginBottom="-10px"
+ ifr.style.marginTop="10px"
+ container.removeChild(ifr)
+ container.appendChild(ifr)
+// toggles.style.marginBottom = "-5px";
+ }
+ if (opts.floatingToggle) {
+ floatToggle.style.display = "block"
+ }
+ toggles.style.border = "1ps solid yellow"
+}
+
+})();
\ No newline at end of file
diff --git a/moksha/widgets/chat/static/gui.js b/moksha/widgets/chat/static/gui.js
new file mode 100644
index 0000000..2972753
--- /dev/null
+++ b/moksha/widgets/chat/static/gui.js
@@ -0,0 +1,215 @@
+(function() {
+
+if (!window.WillowChat) {
+ Willowchat = {}
+}
+
+if (!WillowChat.guis) {
+ WillowChat.guis = {}
+}
+
+if (!WillowChat.guis.map) {
+ WillowChat.guis.map = {}
+}
+var ENTER_KEY = 13
+WillowChat.guis.map.simple = WillowChat.guis.SimpleGui = function(wc, opts) {
+ var self = this;
+ self.presenceShown = true;
+ var logger = Orbited.getLogger('WillowChatTest');
+// logger.enabled = true;
+ var username = null;
+ var presence = {}
+
+ $('#nickname').focus();
+ $('#nickname').keypress( function(e) {
+ var key = e.charCode || e.keyCode || 0
+ if (key == ENTER_KEY) {
+ self.connect();
+ };
+ });
+ $('#chatboxInput').keypress(function(e) {
+ var key = e.charCode || e.keyCode || 0;
+ if (key == ENTER_KEY) {
+ self.sendMessage();
+ return false;
+ };
+ });
+ $("#popupContent p").html(opts.greeting)
+ $("#presenceToggle").click(function() {
+ if (self.presenceShown) {
+ self.presenceShown = false;
+ $("#presence").hide()
+ $("#presenceToggle").html('←');
+ }
+ else {
+ self.presenceShown = true;
+ $("#presence").show();
+ $("#presenceToggle").html('→');
+ }
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ $('#chatboxInput').focus();
+ }
+ else {
+ $('#nickname').focus();
+ }
+ })
+ var scrollDown = function() {
+ var box = $('#history')[0]
+ box.scrollTop = box.scrollHeight;
+ }
+ var isSubstring = function (sub, str) {
+ // case insensitive substring test
+ return str.toLowerCase().indexOf(sub.toLowerCase()) >= 0;
+ };
+ var sanitize = (function(str) {
+ // See http://bigdingus.com/2007/12/29/html-escaping-in-javascript/
+ var MAP = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+ var repl = function(c) { return MAP[c]; };
+ return function(s) {
+ return s.replace(/[&<>'"]/g, repl);
+ };
+ })();
+
+ // TODO: test this out
+ var userRenamed = function(oldname, newname) {
+ $("<div class='informative rename'></div>")
+ .html("<span class='user'>" + oldname + "</span> is now known as " +
+ "<span class='user'>" + newname + "</span>")
+ .appendTo("#history");
+ scrollDown();
+ $("#user_" + oldname)
+ .attr("id", "user_" + newname)
+ .html(newname);
+ }
+
+ var addName = function (name) {
+ presence[name] = 1
+ $('<div class="user_entry" id="user_' + name + '">' + name + '</div>')
+ .appendTo("#presenceList");
+ };
+
+ var removeName = function (name) {
+ delete presence[name];
+ $(".user_list #user_" + name).remove()
+ };
+
+ var sortNames = function () {
+ $('#presenceList').empty();
+ var list = [];
+ for (var user in presence) {
+ list.push(user);
+ };
+ list.sort()
+ for (var i=0; i < list.length; i++) {
+ var user = list[i];
+ $('<div class="user_entry" id="user_' + user + '">' + user + '</div>')
+ .appendTo("#presenceList");
+ };
+ };
+ self.connect = function() {
+ username = $("#nickname").val();
+ if (!username) {
+ logger.debug('please enter a username');
+ return
+ }
+ $('#popup, #absorbClicks').hide();
+ $('#chatboxInput').focus();
+ $('#chatboxInput').val('')
+
+ connected = true;
+ wc.connect( {
+ username: username
+ })
+ wc.onConnect = function(data) {
+ /* This is somewhat important -- without this IE can run into some
+ * issues with reconnecting
+ */
+
+ window.onbeforeunload = function() {
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ return 'Are you sure you want to quit and lose the chat connection?';
+ }
+ };
+ window.onunload = function() {
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ wc.disconnect();
+ }
+ }
+
+
+ $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
+ for (var i = 0; i < wc.presence.length; ++i) {
+ addName(wc.presence[i]);
+ }
+ sortNames();
+ logger.debug('connected', data, wc.presence)
+ }
+ wc.onMessage = function(sender, message) {
+ logger.debug('msg', sender, message);
+ var messagediv = $('<div class="message"></div>');
+
+ if (sender == username) {
+ messagediv.addClass("self");
+ }
+ if (isSubstring(username, message)) {
+ messagediv.addClass("mentioned");
+ }
+ messagediv.html('<span class="user">' + sender + ':</span> ' +
+ sanitize(message))
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onAction = function(s, m) { logger.debug('action', s, m); }
+
+ wc.onJoin = function(joiner) {
+ logger.debug('join', joiner);
+ addName(joiner);
+ sortNames();
+ $("<div class='informative join'></div>")
+ .html("<span class='user'>" + joiner + '</span> has joined')
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onLeave = function(leaver) {
+ logger.debug('leave', leaver);
+ removeName(leaver);
+ $("<div class='informative part'></div>")
+ .html("<span class='user'>" + leaver + '</span> left')
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onDisconnect = function() { logger.debug('disconneted'); }
+ wc.onUsernameTaken = function() {
+ logger.debug('onUsernameTaken', username);
+ username += '_'
+ try {
+ wc.rename(username);
+ logger.debug('rename sent');
+ }
+ catch(e) {
+ logger.debug('rename failed:', e)
+ }
+ }
+ }
+ self.sendMessage = function() {
+ var msg = $('#chatboxInput').val();
+ wc.sendMessage(msg)
+ $('#chatboxInput').val('');
+ // the WillowChat server will not echo our message back, so simulate a send.
+ wc.onMessage(username, msg)
+ }
+ self.sendAction = function() {
+ var msg = getMessage()
+ wc.sendAction(msg);
+ logger.debug('action', username, msg)
+ }
+
+}
+})()
+
diff --git a/moksha/widgets/chat/static/index.html b/moksha/widgets/chat/static/index.html
new file mode 100644
index 0000000..d4277bf
--- /dev/null
+++ b/moksha/widgets/chat/static/index.html
@@ -0,0 +1,48 @@
+<!-- @@ HACK -->
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
+<script src="/toscawidgets/resources/tw.jquery.base/static/javascript/jquery-1.2.6.pack.js"></script>
+<link rel="stylesheet" type="text/css" href="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/style.css"></link>
+ <script>
+ TCPSocket = Orbited.TCPSocket
+ document.domain = document.domain;
+/* Orbited.system.enabled = true;
+ Orbited.loggers['Orbited.XSDR'].enabled = false
+ Orbited.loggers['Orbited.CometSession'].enabled = true
+ Orbited.loggers['Orbited.TCPSocket'].enabled = true
+ Orbited.loggers['XSDRBridge'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true.
+ Orbited.loggers['WC.c.IRCClient'].enabled = true
+*/
+ </script>
+
+<div id="popup">
+<div id="popupOuter">
+ <div id="popupMiddle">
+ <div id="popupContent">
+ <p>Greeting</p>
+ <label for="nickname">Nickname:</label>
+ <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
+ </div>
+ </div>
+</div>
+</div>
+
+ <div id="absorbClicks"></div>
+ <div id="presenceToggle">
+ →
+ </div>
+ <div id="presence">
+ <div id="presenceTitle">Presence</div>
+ <div id="presenceList">
+ </div>
+ </div>
+ <div id="history">
+ </div>
+ <div id="inputBar">
+ <textarea id="chatboxInput"></textarea>
+ </div>
diff --git a/moksha/widgets/chat/static/irc2.js b/moksha/widgets/chat/static/irc2.js
new file mode 100644
index 0000000..175be14
--- /dev/null
+++ b/moksha/widgets/chat/static/irc2.js
@@ -0,0 +1,224 @@
+/* irc.js
+ * This IRC client runs in a web browser using pure JavaScript
+ * Orbited 0.5+ required
+ *
+ * Methods:
+ * connect(hostname, port)
+ * ident(nickname, modes, real_name)
+ * join(channel)
+ * names(channel)
+ * part(channel)
+ * quit(reason)
+ * privmsg(destination, message)
+ *
+ * Callbacks:
+ * Built-in callbacks are onconnect(), onerror(), onresponse(), and onclose()
+ * onerror and onreply are passed numerical reponse codes, see:
+ * http://www.irchelp.org/irchelp/rfc/chapter6.html for a list of IRC response
+ * codes.
+ *
+ * To add callbacks for IRC actions, for instance PRIVMSG,
+ * set onPRIVMSG = function(command) {...you code here...}
+ * See the included IRC demo (/static/demos/irc) for example usage
+ *
+ * Frank Salim (frank.salim(a)gmail.com)
+ * ©2008 The Orbited Project
+ */
+
+// TODO DRY this by creating a common logging infrastructure (this is also on stomp.js)
+IRC_DEBUG = false;
+
+if (IRC_DEBUG && typeof(Orbited)) {
+ var getIrcLogger = function(name) {
+ var logger = Orbited.getLogger(name);
+ if (!("dir" in logger)) {
+ logger.dir = function() {};
+ }
+ return logger;
+ }
+}
+else if (IRC_DEBUG && typeof(console)) {
+ var getIrcLogger = function(name) {
+ return {
+ debug: function() {
+ var args = Array.prototype.slice.call(arguments);
+ args.unshift(name, ": ");
+ console.debug.apply(console, args);
+ },
+ dir: function() {
+ console.debug(name, ":");
+ console.dir.apply(console, arguments);
+ }
+ };
+ };
+}
+else {
+ var getIrcLogger = function(name) {
+ return {
+ debug: function() {},
+ dir: function() {}
+ };
+ };
+}
+
+IRCClient = function() {
+ var log = getIrcLogger("IRCClient");
+ var self = this
+ var conn = null
+ var buffer = ""
+ var ENDL = "\r\n"
+
+ self.onopen = function() {};
+ self.onconnect = function() {} // Do nothing in default callbacks
+ self.onclose = function() {}
+ self.onerror = function(command) {}
+ self.onresponse = function(command) {} // used for numerical replies
+
+ self.connect = function(hostname, port) {
+ log.debug("connect");
+ conn = self._createTransport();
+ conn.onopen = conn_opened
+ conn.onclose = conn_closed
+ conn.onread = conn_read
+ conn.open(hostname, port)
+ // TODO set onerror.
+ }
+ self._createTransport = function() {
+ return new TCPSocket();
+ };
+ self.close = function() {
+ log.debug("close");
+ conn.close()
+ conn.onopen = null;
+ conn.onclose = null;
+ conn.onread = null;
+ self.onclose()
+ }
+ self.ident = function(nickname, modes, real_name) {
+ send("USER", nickname + " " + modes + " :" + real_name)
+ }
+ self.nick = function(nickname) {
+ send("NICK", nickname)
+ }
+ self.join = function(channel) {
+ send("JOIN", channel)
+ }
+ self.names = function(channel) {
+ send("NAMES", channel)
+ }
+ self.part = function(channel, reason) {
+ send("PART", channel + " :" + reason)
+ }
+ self.quit = function(reason) {
+ var reason = reason || "leaving";
+ send("QUIT", ":" + reason)
+ conn.close()
+ }
+ self.reset = function() {
+ conn.reset();
+ }
+ self.action = function(destination, message) {
+ send('PRIVMSG', destination + ' :\01ACTION ' + message + '\01')
+ }
+
+ self.privmsg = function(destination, message) {
+ send('PRIVMSG', destination + ' :' + message)
+ }
+
+ // Socket Callbacks
+ var conn_opened = function() {
+ self.onopen()
+ }
+ var conn_closed = function() {
+ self.onclose()
+ }
+ var conn_read = function(data) {
+ log.debug("data:");
+ log.debug(data);
+ buffer += data
+ parse_buffer()
+ }
+
+ // Internal Functions
+ var send = function(type, payload) {
+ log.debug("send: " + payload);
+ conn.send(type + " " + payload + ENDL);
+ };
+ var parse_buffer= function() {
+ var commands = buffer.split(ENDL);
+ buffer = commands[commands.length-1];
+ for (var i = 0, l = commands.length - 1; i < l; ++i) {
+ var line = commands[i];
+ if (line.length > 0)
+ dispatch(line);
+ }
+ };
+ var parse_command = function(s) {
+ // See http://tools.ietf.org/html/rfc2812#section-2.3
+
+ // all the arguments are split by a single space character until
+ // the first ":" character. the ":" marks the start of the last
+ // trailing argument which can contain embeded space characters.
+ var i = s.indexOf(" :");
+ if (i >= 0) {
+ var args = s.slice(0, i).split(' ');
+ args.push(s.slice(i + 2));
+ } else {
+ var args = s.split(' ');
+ }
+
+ // extract the prefix (if there is one).
+ if (args[0].charAt(0) == ":") {
+ var prefix = args.shift().slice(1);
+ } else {
+ var prefix = null;
+ }
+
+ var command = {
+ prefix: prefix,
+ type: args.shift(),
+ args: args
+ };
+ log.debug("command:");
+ log.dir(command);
+ return command;
+ };
+ var dispatch = function(line) {
+ command = parse_command(line);
+ if (command.type == "PING") {
+ send("PONG", ":" + command.args)
+ }
+ if (!isNaN(parseInt(command.type))) {
+ var error_code = parseInt(command.type)
+ if (error_code > 400)
+ return self.onerror(command)
+ else
+ return self.onresponse(command)
+ }
+ if (command.type == "PRIVMSG") {
+ msg = command.args[1]
+ if (msg.charCodeAt(0) == 1 && msg.charCodeAt(msg.length-1) == 1) {
+ var args = [command.args[0]]
+ var newargs = msg.slice(1, msg.length - 1).split(' ')
+ if (newargs[0] == 'ACTION') {
+ command.type = newargs.shift()
+ }
+ else {
+ command.type = 'CTCP'
+ }
+
+ for (var i = 0; i < newargs.length; ++i) {
+ args.push(newargs[i])
+ }
+ command.args = args
+ }
+ }
+ if (typeof(self["on" + command.type]) == "function") {
+ // XXX the user is able to define unknown command handlers,
+ // but cannot send any arbitrary command
+ self["on" + command.type](command);
+ } else {
+ log.debug("unhandled command received: ", command.type);
+ }
+ };
+};
diff --git a/moksha/widgets/chat/static/style.css b/moksha/widgets/chat/static/style.css
new file mode 100644
index 0000000..c92d64e
--- /dev/null
+++ b/moksha/widgets/chat/static/style.css
@@ -0,0 +1,153 @@
+/*
+html, body {
+ padding: 0px;
+ margin: 0px;
+ border: none;
+ _overflow: hidden;
+ }
+ */
+#presenceToggle {
+ border: 1px solid black;
+ position: absolute;
+ right: 1px;
+ top: 1px;
+ padding: 2px;
+ background: #3f9824;
+ color: white;
+ font-weight: bold;
+ cursor: pointer;
+}
+#presenceToggle:hover {
+}
+#presence {
+ float: right;
+ border: 1px solid gray;
+ width: 130px;
+ height: 83%;
+ margin-left: 3px;
+ margin-bottom: 0px;
+ overflow: hidden;
+}
+#presenceTitle {
+ text-decoration: underline;
+}
+#presenceList {
+ overflow: auto;
+ height: 90%;
+}
+#history {
+ border: 1px solid gray;
+ height: 83%;
+ overflow: auto;
+ margin-bottom: 0px;
+}
+#historySpacer {
+ border: 1px solid red;
+}
+#inputBar {
+ margin-top: 0px;
+ height: 15%;
+}
+#inputBar textarea {
+ width: 100%;
+ height: 100%;
+ border: 1px solid gray;
+}
+
+
+
+#popup {
+ position: absolute;
+ height: 100%;
+ width: 70%;
+ left: 15%;
+ z-index: 2;
+}
+
+#popupOuter {
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ position: relative;
+}
+#popupOuter[id] {display: table; position: static;}
+
+#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
+#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
+
+#popupContent {position: relative; top: -50%} /* for explorer only */
+/* optional: #popupContent[id] {position: static;} */
+
+#popupContent {
+ font-size: 120%;
+ text-align:center;
+ background: #3f9824;
+ color: white;
+ border: 5pt solid #83cb22;
+ padding: 8px;
+ padding-bottom: 20px;
+ width: 100%;
+}
+#popupContent p {
+ font-size: 150%;
+}
+
+#absorbClicks {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+}
+
+
+#history div {
+ background-color:#eeffee;
+ padding:.2em;
+ padding-left:1.5em;
+ text-indent: -1em;
+ border-bottom: 1px dotted #ccc;
+}
+#history .message .user {
+ width:5em;
+ font-weight: bold;
+ color:#DD7200;
+ padding-right:.2em;
+ text-align:right;
+}
+#history .message.self .user{
+ color: #B42600;
+}
+#history .message.mentioned{
+ background-color: #d5c5ff;
+}
+#history .message.private{
+ background-color: #ccc;
+}
+#history .message.ctcp {
+ background-color: #f0f;
+}
+#history .action {
+ color: #D68850;
+ font-style:italic;
+}
+#history .action {
+ color: #A94C3B;
+ font-style:italic;
+}
+#history .informative {
+ font-size: 85%;
+ font-style: italic;
+ color:#999;
+ text-align:center;
+ padding:.3em;
+}
+#presenceList .user_entry {
+ font-size: 90%;
+ padding:.2em;
+ padding-left:8pt;
+ border-bottom: 1px dotted #ccc;
+}
+
+
+
diff --git a/moksha/widgets/chat/static/themes/dojo/chrome.js b/moksha/widgets/chat/static/themes/dojo/chrome.js
new file mode 100644
index 0000000..770701f
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/dojo/chrome.js
@@ -0,0 +1,83 @@
+(function() {
+/* Boilerplate
+ */
+if (!window.WillowChat) {
+ Willowchat = {}
+}
+
+if (!WillowChat.chrome) {
+ WillowChat.chrome = {}
+}
+
+if (!WillowChat.chrome.map) {
+ WillowChat.chrome.map = {}
+}
+
+
+WillowChat.chrome.map.dojo = WillowChat.chrome.DojoChrome = function(container, opts) {
+ /* Set configured height
+ */
+ container.style.width = opts.width + 'px'
+ container.style.height = opts.height + 'px'
+ container.style.background = "white";
+ var toggles = document.createElement('div')
+ toggles.setAttribute('id', 'willowchatToggles')
+ var floatToggle = document.createElement('div')
+ floatToggle.setAttribute('id', 'willowchatFloat')
+ floatToggle.innerHTML = "↑"
+ var minToggle = document.createElement('div')
+ minToggle.setAttribute('id', 'willowchatMin')
+ minToggle.innerHTML = "-"
+ floatToggle.setAttribute('style', "float: left;")
+ minToggle.setAttribute('style', "float: left;")
+ var toggleElements = [ minToggle, floatToggle]
+ for (var i = 0; i < 2; ++i) {
+ var t = toggleElements[i]
+ t.style.width = "20px"
+ t.style.height = "20px"
+ t.style.textAlign = "center"
+ t.style.border = "1px solid black"
+ t.style.padding = "2px"
+ t.style.color = "white"
+ t.style.fontWeight = "bold"
+ t.style.background = "#005522"
+ t.style.cursor = "pointer"
+ t.style.cssFloat = "left"
+ t.style.styleFloat = "left"
+ t.style.display = "none"
+ }
+ container.appendChild(toggles)
+ toggles.appendChild(floatToggle)
+ toggles.appendChild(minToggle)
+
+ /* Should it be floating?
+ */
+ if (opts.floating) {
+ container.style.position = 'absolute';
+ container.style.bottom = '0';
+ container.style.right = '0';
+ minToggle.style.display = "block"
+ toggles.style.position = "absolute"
+ toggles.style.top = "1px"
+ toggles.style.left = "1px"
+ if (opts.reposition) {
+ container.parentNode.removeChild(container)
+ document.body.appendChild(container)
+
+ }
+ }
+ else {
+ var ifr = container.getElementsByTagName('iframe')[0]
+ toggles.style.marginBottom="-10px"
+ ifr.style.marginTop="10px"
+ container.removeChild(ifr)
+ container.appendChild(ifr)
+// toggles.style.marginBottom = "-5px";
+ }
+ if (opts.floatingToggle) {
+ floatToggle.style.display = "block"
+ }
+ toggles.style.border = "1ps solid yellow"
+}
+
+})();
\ No newline at end of file
diff --git a/moksha/widgets/chat/static/themes/dojo/gui.js b/moksha/widgets/chat/static/themes/dojo/gui.js
new file mode 100644
index 0000000..b042620
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/dojo/gui.js
@@ -0,0 +1,19 @@
+
+
+if (!window.WillowChat) {
+ Willowchat = {}
+}
+
+if (!WillowChat.guis) {
+ WillowChat.guis = {}
+}
+
+if (!WillowChat.guis.map) {
+ WillowChat.guis.map = {}
+}
+
+var willowConnection = null;
+WillowChat.guis.map.dojo = WillowChat.guis.DojoGui = function(wc, opts) {
+ console.log("Neat? ", wc, opts);
+ willowConnection = wc;
+}
diff --git a/moksha/widgets/chat/static/themes/dojo/index.html b/moksha/widgets/chat/static/themes/dojo/index.html
new file mode 100644
index 0000000..fe50981
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/dojo/index.html
@@ -0,0 +1,226 @@
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="style.css">
+<script src="http://localhost:9000/static/Orbited.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
+<script src="gui.js"></script>
+ <script>
+ TCPSocket = Orbited.TCPSocket
+ document.domain = document.domain
+/* Orbited.system.enabled = true;
+ Orbited.loggers['Orbited.XSDR'].enabled = false
+ Orbited.loggers['Orbited.CometSession'].enabled = true
+ Orbited.loggers['Orbited.TCPSocket'].enabled = true
+ Orbited.loggers['XSDRBridge'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true
+ Orbited.loggers['WC.c.IRCClient'].enabled = true
+*/
+ </script>
+
+
+ <link rel="stylesheet"
+ href="http://o.aolcdn.com/dojo/1.2/dijit/themes/soria/soria.css">
+ <!-- load Dojo, and all the required modules -->
+
+ <script type="text/javascript">
+
+ djConfig = {
+ isDebug: true,
+ baseUrl: "./",
+ xdWaitSeconds: 10,
+ parseOnLoad: true
+ };
+ </script>
+
+ <script src="http://o.aolcdn.com/dojo/1.2/dojo/dojo.xd.js" ></script>
+
+ <script>
+
+ dojo.require("dijit.layout.BorderContainer");
+ dojo.require("dijit.layout.AccordionContainer");
+ dojo.require("dijit.layout.ContentPane");
+ dojo.require("dijit.layout.TabContainer");
+
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.Dialog");
+
+
+ var username = null;
+ var roomMembers = [];
+
+ dojo.addOnLoad(function() {
+ dijit.byId("logindialog").show();
+ console.log("hi?", willowConnection);
+
+
+ var mssageBox = dojo.byId("messageBox");
+ dojo.connect(mssageBox, "keyup", function(e) {
+ var key = e.charCode || e.keyCode || 0
+ if (key == dojo.keys.ENTER) {
+ var msg = mssageBox.value;
+ willowConnection.sendMessage(msg)
+ willowConnection.onMessage(username, msg);
+ mssageBox.value = "";
+ };
+ });
+
+
+ });
+
+ function login(nickname) {
+ username = nickname;
+ willowConnection.connect( {
+ username: nickname
+ });
+
+
+
+
+ willowConnection.onConnect = function(data) {
+ /* This is somewhat important -- without this IE can run into some
+ * issues with reconnecting
+ */
+
+ window.onbeforeunload = function() {
+ if (willowConnection.readyState == willowConnection.READY_STATE_CONNECTED) {
+ return 'Are you sure you want to quit and lose the chat connection?';
+ }
+ };
+ window.onunload = function() {
+ if (willowConnection.readyState == willowConnection.READY_STATE_CONNECTED) {
+ willowConnection.disconnect();
+ }
+ }
+
+
+ // $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
+ for (var i = 0; i < willowConnection.presence.length; ++i) {
+ addName(willowConnection.presence[i]);
+ console.log("who?", willowConnection.presence[i]);
+ }
+ updateMembers();
+ console.log('connected', data, willowConnection.presence)
+ }
+ willowConnection.onMessage = function(sender, message) {
+ console.log('msg', sender, message);
+ chatArea.domNode.innerHTML += "<div>" + sender + ": " + message + "</div>";
+ scrollDown();
+ /* var messagediv = $('<div class="message"></div>');
+
+ if (sender == username) {
+ messagediv.addClass("self");
+ }
+ if (isSubstring(username, message)) {
+ messagediv.addClass("mentioned");
+ }
+ messagediv.html('<span class="user">' + sender + ':</span> ' +
+ sanitize(message))
+ .appendTo("#history");
+ scrollDown();*/
+ }
+ willowConnection.onAction = function(s, m) { console.log('action', s, m); }
+
+ willowConnection.onJoin = function(joiner) {
+ console.log('join', joiner);
+ addName(joiner);
+ updateMembers();
+ chatArea.domNode.innerHTML += "<span class='user'>" + joiner + "</span> has joined<br/>";
+ scrollDown();
+ }
+
+ willowConnection.onLeave = function(leaver) {
+ console.log('leave', leaver);
+ var idx = -1;
+ for(var i = 0; idx > -1 && i < roomMembers.length; i++) {
+ if(leaver == roomMembers[i]) {
+ idx = i;
+ }
+ }
+ roomMembers.splice(i, 1);
+ _updateMemberDisplay();
+ }
+
+ willowConnection.onDisconnect = function() { console.log('disconneted'); roomMembers = []; _updateMemberDisplay(); dijit.byId("logindialog").show();}
+ willowConnection.onUsernameTaken = function() {
+ console.log('onUsernameTaken', username);
+ username += '_'
+ try {
+ willowConnection.rename(username);
+ console.log('rename sent');
+ }
+ catch(e) {
+ console.log('rename failed:', e)
+ }
+ }
+
+
+
+
+
+ }
+
+ function addName(name) {
+ roomMembers.push(name);
+ // presenceContainer.domNode.innerHTML += name + "<br/>";
+ }
+
+
+ function updateMembers() {
+ roomMembers.sort();
+ _updateMemberDisplay();
+ }
+
+ function _updateMemberDisplay() {
+ presenceContainer.domNode.innerHTML = "";
+ for(var i = 0; i < roomMembers.length; i++) {
+ var member = roomMembers[i];
+ presenceContainer.domNode.innerHTML += member + "<br/>";
+ }
+ }
+
+ function scrollDown() {
+ chatArea.domNode.scrollTop = chatArea.domNode.scrollHeight;
+ }
+
+ function logout() {
+ willowConnection.disconnect();
+ }
+
+
+
+
+ </script>
+
+
+ </head>
+ <body class="soria" >
+ <div dojoType="dijit.Dialog" id="logindialog" title="Chat"
+ execute="login(arguments[0]['name'] ? arguments[0]['name'] : 'guest');">
+ <label for="name">Nickname: </label>
+ <input dojoType=dijit.form.TextBox type="text" maxlength="16" name="name" id="name" value="">
+ <button dojoType=dijit.form.Button type="submit">OK</button>
+ </div>
+
+ <div>
+ <div dojoType="dijit.layout.BorderContainer" style="width:100%; height:100%">
+ <div dojoType="dijit.layout.ContentPane" region="top" style="border:1px solid gray; height: 20px; background: #eee;">
+ WillowChat now with Dojo <button dojoType=dijit.form.Button onClick="logout();" style="font-size:10px;" type="submit">Leave</button>
+ </div>
+ <div dojoType="dijit.layout.ContentPane" region="left" jsId="presenceContainer" style="width: 100px; border:1px solid gray; background: #eee;" splitter="true" minSize="0" maxSize="250">
+
+ </div>
+ <div dojoType="dijit.layout.ContentPane" region="center" jsId="chatArea" style="border:1px solid gray; background: #eee;" >
+
+ </div>
+ <div dojoType="dijit.layout.ContentPane" region="bottom" style="height: 50px; border:1px solid gray; background: #eee;" >
+ <textarea id="messageBox" style="width:90%"></textarea>
+ </div>
+ </div>
+ </div>
+</html>
diff --git a/moksha/widgets/chat/static/themes/dojo/style.css b/moksha/widgets/chat/static/themes/dojo/style.css
new file mode 100644
index 0000000..29f0a19
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/dojo/style.css
@@ -0,0 +1,151 @@
+html, body {
+ padding: 0px;
+ margin: 0px;
+ border: none;
+ _overflow: hidden;
+ }
+#presenceToggle {
+ border: 1px solid black;
+ position: absolute;
+ right: 1px;
+ top: 1px;
+ padding: 2px;
+ background: #005522;
+ color: white;
+ font-weight: bold;
+ cursor: pointer;
+}
+#presenceToggle:hover {
+}
+#presence {
+ float: right;
+ border: 1px solid gray;
+ width: 130px;
+ height: 83%;
+ margin-left: 3px;
+ margin-bottom: 0px;
+ overflow: hidden;
+}
+#presenceTitle {
+ text-decoration: underline;
+}
+#presenceList {
+ overflow: auto;
+ height: 90%;
+}
+#history {
+ border: 1px solid gray;
+ height: 83%;
+ overflow: auto;
+ margin-bottom: 0px;
+}
+#historySpacer {
+ border: 1px solid red;
+}
+#inputBar {
+ margin-top: 0px;
+ height: 15%;
+}
+#inputBar textarea {
+ width: 100%;
+ height: 100%;
+ border: 1px solid gray;
+}
+
+
+
+#popup {
+ position: absolute;
+ height: 100%;
+ width: 70%;
+ left: 15%;
+ z-index: 2;
+}
+
+#popupOuter {
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ position: relative;
+}
+#popupOuter[id] {display: table; position: static;}
+
+#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
+#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
+
+#popupContent {position: relative; top: -50%} /* for explorer only */
+/* optional: #popupContent[id] {position: static;} */
+
+#popupContent {
+ font-size: 120%;
+ text-align:center;
+ background: #005522;
+ color: white;
+ border: 5pt solid #50A572;
+ padding: 8px;
+ padding-bottom: 20px;
+ width: 100%;
+}
+#popupContent p {
+ font-size: 150%;
+}
+
+#absorbClicks {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+}
+
+
+#history div {
+ background-color:#eeffee;
+ padding:.2em;
+ padding-left:1.5em;
+ text-indent: -1em;
+ border-bottom: 1px dotted #ccc;
+}
+#history .message .user {
+ width:5em;
+ font-weight: bold;
+ color:#DD7200;
+ padding-right:.2em;
+ text-align:right;
+}
+#history .message.self .user{
+ color: #B42600;
+}
+#history .message.mentioned{
+ background-color: #d5c5ff;
+}
+#history .message.private{
+ background-color: #ccc;
+}
+#history .message.ctcp {
+ background-color: #f0f;
+}
+#history .action {
+ color: #D68850;
+ font-style:italic;
+}
+#history .action {
+ color: #A94C3B;
+ font-style:italic;
+}
+#history .informative {
+ font-size: 85%;
+ font-style: italic;
+ color:#999;
+ text-align:center;
+ padding:.3em;
+}
+#presenceList .user_entry {
+ font-size: 90%;
+ padding:.2em;
+ padding-left:8pt;
+ border-bottom: 1px dotted #ccc;
+}
+
+
+
diff --git a/moksha/widgets/chat/static/themes/simple/chrome.js b/moksha/widgets/chat/static/themes/simple/chrome.js
new file mode 100644
index 0000000..4379ce6
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/simple/chrome.js
@@ -0,0 +1,83 @@
+(function() {
+/* Boilerplate
+ */
+if (!window.WillowChat) {
+ Willowchat = {}
+}
+
+if (!WillowChat.chrome) {
+ WillowChat.chrome = {}
+}
+
+if (!WillowChat.chrome.map) {
+ WillowChat.chrome.map = {}
+}
+
+
+WillowChat.chrome.map.simple = WillowChat.chrome.SimpleChrome = function(container, opts) {
+ /* Set configured height
+ */
+ container.style.width = opts.width + 'px'
+ container.style.height = opts.height + 'px'
+ container.style.background = "white";
+ var toggles = document.createElement('div')
+ toggles.setAttribute('id', 'willowchatToggles')
+ var floatToggle = document.createElement('div')
+ floatToggle.setAttribute('id', 'willowchatFloat')
+ floatToggle.innerHTML = "↑"
+ var minToggle = document.createElement('div')
+ minToggle.setAttribute('id', 'willowchatMin')
+ minToggle.innerHTML = "-"
+ floatToggle.setAttribute('style', "float: left;")
+ minToggle.setAttribute('style', "float: left;")
+ var toggleElements = [ minToggle, floatToggle]
+ for (var i = 0; i < 2; ++i) {
+ var t = toggleElements[i]
+ t.style.width = "20px"
+ t.style.height = "20px"
+ t.style.textAlign = "center"
+ t.style.border = "1px solid black"
+ t.style.padding = "2px"
+ t.style.color = "white"
+ t.style.fontWeight = "bold"
+ t.style.background = "#005522"
+ t.style.cursor = "pointer"
+ t.style.cssFloat = "left"
+ t.style.styleFloat = "left"
+ t.style.display = "none"
+ }
+ container.appendChild(toggles)
+ toggles.appendChild(floatToggle)
+ toggles.appendChild(minToggle)
+
+ /* Should it be floating?
+ */
+ if (opts.floating) {
+ container.style.position = 'absolute';
+ container.style.bottom = '0';
+ container.style.right = '0';
+ minToggle.style.display = "block"
+ toggles.style.position = "absolute"
+ toggles.style.top = "1px"
+ toggles.style.left = "1px"
+ if (opts.reposition) {
+ container.parentNode.removeChild(container)
+ document.body.appendChild(container)
+
+ }
+ }
+ else {
+ var ifr = container.getElementsByTagName('iframe')[0]
+ toggles.style.marginBottom="-10px"
+ ifr.style.marginTop="10px"
+ container.removeChild(ifr)
+ container.appendChild(ifr)
+// toggles.style.marginBottom = "-5px";
+ }
+ if (opts.floatingToggle) {
+ floatToggle.style.display = "block"
+ }
+ toggles.style.border = "1ps solid yellow"
+}
+
+})();
diff --git a/moksha/widgets/chat/static/themes/simple/gui.js b/moksha/widgets/chat/static/themes/simple/gui.js
new file mode 100644
index 0000000..2b5083f
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/simple/gui.js
@@ -0,0 +1,216 @@
+(function() {
+
+if (!window.WillowChat) {
+ console.log('no willochat found in gui?');
+ Willowchat = {}
+}
+
+if (!WillowChat.guis) {
+ WillowChat.guis = {}
+}
+
+if (!WillowChat.guis.map) {
+ WillowChat.guis.map = {}
+}
+var ENTER_KEY = 13
+WillowChat.guis.map.simple = WillowChat.guis.SimpleGui = function(wc, opts) {
+ var self = this;
+ self.presenceShown = true;
+ var logger = Orbited.getLogger('WillowChatTest');
+// logger.enabled = true;
+ var username = null;
+ var presence = {}
+
+ $('#nickname').focus();
+ $('#nickname').keypress( function(e) {
+ var key = e.charCode || e.keyCode || 0
+ if (key == ENTER_KEY) {
+ self.connect();
+ };
+ });
+ $('#chatboxInput').keypress(function(e) {
+ var key = e.charCode || e.keyCode || 0;
+ if (key == ENTER_KEY) {
+ self.sendMessage();
+ return false;
+ };
+ });
+ $("#popupContent p").html(opts.greeting)
+ $("#presenceToggle").click(function() {
+ if (self.presenceShown) {
+ self.presenceShown = false;
+ $("#presence").hide()
+ $("#presenceToggle").html('←');
+ }
+ else {
+ self.presenceShown = true;
+ $("#presence").show();
+ $("#presenceToggle").html('→');
+ }
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ $('#chatboxInput').focus();
+ }
+ else {
+ $('#nickname').focus();
+ }
+ })
+ var scrollDown = function() {
+ var box = $('#history')[0]
+ box.scrollTop = box.scrollHeight;
+ }
+ var isSubstring = function (sub, str) {
+ // case insensitive substring test
+ return str.toLowerCase().indexOf(sub.toLowerCase()) >= 0;
+ };
+ var sanitize = (function(str) {
+ // See http://bigdingus.com/2007/12/29/html-escaping-in-javascript/
+ var MAP = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": '''
+ };
+ var repl = function(c) { return MAP[c]; };
+ return function(s) {
+ return s.replace(/[&<>'"]/g, repl);
+ };
+ })();
+
+ // TODO: test this out
+ var userRenamed = function(oldname, newname) {
+ $("<div class='informative rename'></div>")
+ .html("<span class='user'>" + oldname + "</span> is now known as " +
+ "<span class='user'>" + newname + "</span>")
+ .appendTo("#history");
+ scrollDown();
+ $("#user_" + oldname)
+ .attr("id", "user_" + newname)
+ .html(newname);
+ }
+
+ var addName = function (name) {
+ presence[name] = 1
+ $('<div class="user_entry" id="user_' + name + '">' + name + '</div>')
+ .appendTo("#presenceList");
+ };
+
+ var removeName = function (name) {
+ delete presence[name];
+ $(".user_list #user_" + name).remove()
+ };
+
+ var sortNames = function () {
+ $('#presenceList').empty();
+ var list = [];
+ for (var user in presence) {
+ list.push(user);
+ };
+ list.sort()
+ for (var i=0; i < list.length; i++) {
+ var user = list[i];
+ $('<div class="user_entry" id="user_' + user + '">' + user + '</div>')
+ .appendTo("#presenceList");
+ };
+ };
+ self.connect = function() {
+ username = $("#nickname").val();
+ if (!username) {
+ logger.debug('please enter a username');
+ return
+ }
+ $('#popup, #absorbClicks').hide();
+ $('#chatboxInput').focus();
+ $('#chatboxInput').val('')
+
+ connected = true;
+ wc.connect( {
+ username: username
+ })
+ wc.onConnect = function(data) {
+ /* This is somewhat important -- without this IE can run into some
+ * issues with reconnecting
+ */
+
+ window.onbeforeunload = function() {
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ return 'Are you sure you want to quit and lose the chat connection?';
+ }
+ };
+ window.onunload = function() {
+ if (wc.readyState == wc.READY_STATE_CONNECTED) {
+ wc.disconnect();
+ }
+ }
+
+
+ $("<div class='informative'>Entered ChatRoom</div>").appendTo("#history");
+ for (var i = 0; i < wc.presence.length; ++i) {
+ addName(wc.presence[i]);
+ }
+ sortNames();
+ logger.debug('connected', data, wc.presence)
+ }
+ wc.onMessage = function(sender, message) {
+ logger.debug('msg', sender, message);
+ var messagediv = $('<div class="message"></div>');
+
+ if (sender == username) {
+ messagediv.addClass("self");
+ }
+ if (isSubstring(username, message)) {
+ messagediv.addClass("mentioned");
+ }
+ messagediv.html('<span class="user">' + sender + ':</span> ' +
+ sanitize(message))
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onAction = function(s, m) { logger.debug('action', s, m); }
+
+ wc.onJoin = function(joiner) {
+ logger.debug('join', joiner);
+ addName(joiner);
+ sortNames();
+ $("<div class='informative join'></div>")
+ .html("<span class='user'>" + joiner + '</span> has joined')
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onLeave = function(leaver) {
+ logger.debug('leave', leaver);
+ removeName(leaver);
+ $("<div class='informative part'></div>")
+ .html("<span class='user'>" + leaver + '</span> left')
+ .appendTo("#history");
+ scrollDown();
+ }
+ wc.onDisconnect = function() { logger.debug('disconneted'); }
+ wc.onUsernameTaken = function() {
+ logger.debug('onUsernameTaken', username);
+ username += '_'
+ try {
+ wc.rename(username);
+ logger.debug('rename sent');
+ }
+ catch(e) {
+ logger.debug('rename failed:', e)
+ }
+ }
+ }
+ self.sendMessage = function() {
+ var msg = $('#chatboxInput').val();
+ wc.sendMessage(msg)
+ $('#chatboxInput').val('');
+ // the WillowChat server will not echo our message back, so simulate a send.
+ wc.onMessage(username, msg)
+ }
+ self.sendAction = function() {
+ var msg = getMessage()
+ wc.sendAction(msg);
+ logger.debug('action', username, msg)
+ }
+
+}
+})()
+
diff --git a/moksha/widgets/chat/static/themes/simple/index.html b/moksha/widgets/chat/static/themes/simple/index.html
new file mode 100644
index 0000000..ee659cf
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/simple/index.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="style.css">
+<!-- @@ HACK -->
+<script src="http://localhost:9000/static/Orbited.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/irc2.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/willowchat.js"></script>
+<script src="/toscawidgets/resources/moksha.api.widgets.chat.chat/static/gui.js"></script>
+<script src="/toscawidgets/resources/tw.jquery.base/static/javascript/jquery-1.2.6.pack.js"></script>
+ <script src="gui.js"></script>
+ <script>
+ TCPSocket = Orbited.TCPSocket
+ document.domain = document.domain
+
+/* Orbited.system.enabled = true;
+ Orbited.loggers['Orbited.XSDR'].enabled = false
+ Orbited.loggers['Orbited.CometSession'].enabled = true
+ Orbited.loggers['Orbited.TCPSocket'].enabled = true
+ Orbited.loggers['XSDRBridge'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.LongPoll'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.XHRStream'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.HTMLFile'].enabled = true
+ Orbited.loggers['Orbited.CometTransports.SSE'].enabled = true
+ Orbited.loggers['WC.c.IRCClient'].enabled = true
+*/
+ </script>
+
+ </head>
+ <body>
+<div id="popup">
+<div id="popupOuter">
+ <div id="popupMiddle">
+ <div id="popupContent">
+ <p>Greeting</p>
+ <label for="nickname">Nickname:</label>
+ <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
+ </div>
+ </div>
+</div>
+</div>
+
+
+ <div id="absorbClicks"></div>
+ <div id="presenceToggle">
+ →
+ </div>
+ <div id="presence">
+ <div id="presenceTitle">Presence</div>
+ <div id="presenceList">
+ </div>
+ </div>
+ <div id="history">
+ </div>
+ <div id="inputBar">
+ <textarea id="chatboxInput"></textarea>
+ </div>
+ </body>
+</html>
diff --git a/moksha/widgets/chat/static/themes/simple/style.css b/moksha/widgets/chat/static/themes/simple/style.css
new file mode 100644
index 0000000..29f0a19
--- /dev/null
+++ b/moksha/widgets/chat/static/themes/simple/style.css
@@ -0,0 +1,151 @@
+html, body {
+ padding: 0px;
+ margin: 0px;
+ border: none;
+ _overflow: hidden;
+ }
+#presenceToggle {
+ border: 1px solid black;
+ position: absolute;
+ right: 1px;
+ top: 1px;
+ padding: 2px;
+ background: #005522;
+ color: white;
+ font-weight: bold;
+ cursor: pointer;
+}
+#presenceToggle:hover {
+}
+#presence {
+ float: right;
+ border: 1px solid gray;
+ width: 130px;
+ height: 83%;
+ margin-left: 3px;
+ margin-bottom: 0px;
+ overflow: hidden;
+}
+#presenceTitle {
+ text-decoration: underline;
+}
+#presenceList {
+ overflow: auto;
+ height: 90%;
+}
+#history {
+ border: 1px solid gray;
+ height: 83%;
+ overflow: auto;
+ margin-bottom: 0px;
+}
+#historySpacer {
+ border: 1px solid red;
+}
+#inputBar {
+ margin-top: 0px;
+ height: 15%;
+}
+#inputBar textarea {
+ width: 100%;
+ height: 100%;
+ border: 1px solid gray;
+}
+
+
+
+#popup {
+ position: absolute;
+ height: 100%;
+ width: 70%;
+ left: 15%;
+ z-index: 2;
+}
+
+#popupOuter {
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ position: relative;
+}
+#popupOuter[id] {display: table; position: static;}
+
+#popupMiddle {position: absolute; top: 50%;} /* for explorer only*/
+#popupMiddle[id] {display: table-cell; vertical-align: middle; position: static;}
+
+#popupContent {position: relative; top: -50%} /* for explorer only */
+/* optional: #popupContent[id] {position: static;} */
+
+#popupContent {
+ font-size: 120%;
+ text-align:center;
+ background: #005522;
+ color: white;
+ border: 5pt solid #50A572;
+ padding: 8px;
+ padding-bottom: 20px;
+ width: 100%;
+}
+#popupContent p {
+ font-size: 150%;
+}
+
+#absorbClicks {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+}
+
+
+#history div {
+ background-color:#eeffee;
+ padding:.2em;
+ padding-left:1.5em;
+ text-indent: -1em;
+ border-bottom: 1px dotted #ccc;
+}
+#history .message .user {
+ width:5em;
+ font-weight: bold;
+ color:#DD7200;
+ padding-right:.2em;
+ text-align:right;
+}
+#history .message.self .user{
+ color: #B42600;
+}
+#history .message.mentioned{
+ background-color: #d5c5ff;
+}
+#history .message.private{
+ background-color: #ccc;
+}
+#history .message.ctcp {
+ background-color: #f0f;
+}
+#history .action {
+ color: #D68850;
+ font-style:italic;
+}
+#history .action {
+ color: #A94C3B;
+ font-style:italic;
+}
+#history .informative {
+ font-size: 85%;
+ font-style: italic;
+ color:#999;
+ text-align:center;
+ padding:.3em;
+}
+#presenceList .user_entry {
+ font-size: 90%;
+ padding:.2em;
+ padding-left:8pt;
+ border-bottom: 1px dotted #ccc;
+}
+
+
+
diff --git a/moksha/widgets/chat/static/willowchat.js b/moksha/widgets/chat/static/willowchat.js
new file mode 100644
index 0000000..0561630
--- /dev/null
+++ b/moksha/widgets/chat/static/willowchat.js
@@ -0,0 +1,337 @@
+(function() {
+
+Orbited.settings.streaming = true
+
+if (window.addEventListener) {
+ window.addEventListener('load', function() { WillowChat.util.setup(); }, false);
+}
+else if (window.attachEvent) {
+ window.attachEvent('onload', function() { WillowChat.util.setup(); });
+}
+
+
+if (!window.WillowChat) {
+ WillowChat = {}
+}
+WillowChat.settings = {}
+WillowChat.settings.hostname = document.domain
+WillowChat.settings.port = (location.port.length > 0) ? location.port : 80
+WillowChat.settings.defaultTheme = 'simple'
+WillowChat.settings.client = 'irc'
+WillowChat.clients = {}
+WillowChat.clients.map = {}
+WillowChat.util = {}
+
+
+if (!WillowChat.guis) {
+ WillowChat.guis = {}
+}
+if (!WillowChat.guis.map) {
+ WillowChat.guis.map = {}
+}
+
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(n) {
+ for (var i = 0; i < this.length; ++i) {
+ if (this[i] === n) {
+ return i
+ }
+ }
+ return -1
+ }
+}
+
+
+
+
+WillowChat.util.setup = function() {
+ // TODO: first setup from remote and url
+ // TODO: this is a *really* ugly way to do this... Fix it
+
+ try {
+ var i = location.href.indexOf('&opts=')
+ var opts = JSON.parse(unescape(location.href.slice(i+6)))
+ }
+ catch(e) {
+ // If the options aren't there, then someone must be trying to use this
+ // library manually, which we want to allow.
+ return
+ }
+ // TODO: we actually need to get the "backend" hostname value
+ WillowChat.settings.hostname = 'localhost'
+ var client = new WillowChat.clients.map[WillowChat.settings.client](opts)
+ var gui = new WillowChat.guis.map[opts.theme ? opts.theme : WillowChat.settings.defaultTheme](client, opts)
+
+ return gui
+}
+
+
+
+
+
+WillowChat.BaseClient = function() {
+ var self = this;
+ self.readyState = self.READY_STATE_INITIALIZED;
+ self.onUsernameTaken = function() { };
+ self.onConnect = function() { };
+ self.onPresence= function() { };
+ self.onDisconnect = function() { };
+ self.onMessage = function() { };
+ self.onJoin = function() { };
+ self.onLeave = function() { };
+ self.onAction = function() { };
+ self.onRename = function() { };
+}
+
+WillowChat.BaseClient.prototype.connect = function(options) {
+ var self = this;
+ if (!this.doConnect) {
+ throw new Error("NotImplemented");
+ }
+ var username = options.username
+ if (!username) {
+ throw new Error("Missing username")
+ }
+ var roomId = options.roomId ? options.roomId : self.opts.roomId
+ if (!roomId) {
+ throw new Error("Missing roomId")
+ }
+ var hostname = options.hostname
+ var port = options.port
+ if (!port) {
+ port = 6667
+ }
+ if (!hostname) {
+ if (!self.opts.addr) {
+ throw new Error("missing connection information");
+ }
+ hostname = self.opts.addr[0]
+ port = self.opts.addr[1]
+ }
+ return self.doConnect(username, roomId, hostname, port);
+};
+WillowChat.BaseClient.prototype.rename = function(newName) {
+ throw new Error("NotImplemented");
+};
+WillowChat.BaseClient.prototype.sendMessage = function(msg) {
+ throw new Error("NotImplemented");
+};
+WillowChat.BaseClient.prototype.sendAction = function(action) {
+ throw new Error("NotImplemented");
+};
+WillowChat.BaseClient.prototype.disconnect = function() {
+ throw new Error("NotImplemented");
+};
+WillowChat.BaseClient.prototype.READY_STATE_INITIALIZED = 0;
+WillowChat.BaseClient.prototype.READY_STATE_CONNECTING = 1;
+WillowChat.BaseClient.prototype.READY_STATE_CONNECTED = 2;
+WillowChat.BaseClient.prototype.READY_STATE_DISCONNECTED = 3;
+
+
+WillowChat.clients.IRCClient = function(opts) {
+ var self = this;
+ self._conn = null;
+ self.opts = opts
+};
+
+WillowChat.clients.IRCClient.prototype = new WillowChat.BaseClient();
+
+WillowChat.clients.IRCClient.prototype.logger = Orbited.getLogger('WC.c.IRCClient');
+WillowChat.clients.map.irc = WillowChat.clients.IRCClient
+
+WillowChat.clients.IRCClient.prototype.disconnect = function() {
+ var self = this;
+ if (self.readyState == self.READY_STATE_DISCONNECTED) {
+ return
+ }
+ self.readyState = self.READY_STATE_DISCONNECTED;
+ // TODO: would be nice to have a quit message or something
+ self._conn.reset()
+ self._conn = null;
+ self.onDisconnect()
+}
+
+
+WillowChat.clients.IRCClient.prototype.doConnect = function(username, roomId, hostname, port) {
+ var self = this;
+ self.username = username
+ self.roomId = roomId;
+ if (self.roomId[0] != '#') {
+ self.roomId = '#' + self.roomId
+ }
+ self._conn = new IRCClient()
+ self.presence = []
+ var irc = self._conn
+ // By default, assume the irc server is on the same host as the willowchat
+ // server
+
+ function parseName(identity) {
+ // TODO remove privileges from name head.
+ return identity.split("!", 1)[0];
+ }
+ irc.onclose = function() {
+ self.disconnect();
+ }
+ irc.onopen = function() {
+ irc.ident(self.username, '8 *', self.username);
+ irc.nick(self.username);
+ }
+;;; self.logger.debug('do irc.connect', hostname, port)
+ irc.connect(hostname, port)
+ self.readyState = self.READY_STATE_CONNECTING
+
+ irc.onJOIN = function(command) {
+;;; self.logger.debug('irc.onJOIN', command)
+ // Ignore initial onJoin (before names)
+ var joiner = parseName(command.prefix)
+;;; self.logger.debug('irc.onJoin.a')
+ self.logger.debug('self.presence', self.presence, Orbited.JSON.stringify(self.presence))
+ if (self.presence.indexOf(joiner) == -1) {
+;;; self.logger.debug('irc.onJoin.b')
+ self.presence.push(joiner)
+ }
+;;; self.logger.debug('irc.onJoin.c')
+ if (self.readyState == self.READY_STATE_CONNECTED) {
+;;; self.logger.debug('irc.onJoin.d')
+ self.onJoin(joiner);
+ }
+;;; self.logger.debug('irc.onJoin.e')
+ }
+ irc.onPART = irc.onQUIT = function(command) {
+ var leaver = parseName(command.prefix);
+ var message = command.args.join(" ");
+ var i = self.presence.indexOf(leaver)
+ if (i != -1) {
+ self.presence.splice(i,1)
+ }
+ self.onLeave(leaver);
+ }
+ irc.onNICK = function(command) {
+ // See http://tools.ietf.org/html/rfc2812#section-3.1.2
+ var previousNick = parseName(command.prefix);
+ var i = self.presence.indexOf(previousNick)
+ if (i != -1) {
+ self.presence.splice(i,1)
+ }
+ var newNick = command.args[0];
+ if (self.presence.indexOf(newNick) == -1) {
+ self.presence.push(newNick)
+ }
+ self.onPresence()
+ };
+
+ irc.onPRIVMSG = function(command) {
+ var sender = parseName(command.prefix);
+ var target = command.args[0];
+ var message = command.args[1];
+ self.onMessage(sender, message);
+ }
+ irc.onACTION = function(command) {
+;;; self.logger.debug('irc.onACTION', command)
+ var sender = parseName(command.prefix);
+ var message = command.args.slice(1).join(" ")
+ self.onAction(sender, message);
+ }
+
+ irc.onresponse = function(command) {
+ self.logger.debug('onresponse', command)
+ var responseCode = parseInt(command.type);
+ if (responseCode == 353) {
+ // 353 is the code for RPL_NAMEREPLY.
+
+ // The args are:
+ //
+ // """
+ // <target> ( "=" / "*" / "@" ) <channel>
+ // :[ "@" / "+" ] <nick> *( " " [ "@" / "+" ] <nick> )
+ //
+ // - "@" is used for secret channels, "*" for private
+ // channels, and "=" for others (public channels).
+ // """ -- rfc2812
+ var channel = command.args[2];
+ if (channel != self.roomId)
+ return;
+ var partialUserList = command.args[3].split(' ');
+ for (var i = 0, l = partialUserList.length; i < l; ++i) {
+ // trim the name
+ var name = partialUserList[i].replace(/^\s+|\s+$/g,"");
+ if (name[0] == '@' || name[0] == '+') {
+ name = name.slice(1);
+ }
+ if (name == "" || self.presence.indexOf(name) != -1) {
+ continue;
+ }
+ self.presence.push(name)
+ }
+ }
+ else if (responseCode == 366) {
+ // 366 is the code for RPL_ENDOFNAMES.
+ self.readyState = self.READY_STATE_CONNECTED
+ self.onConnect();
+ }
+ else if (responseCode == 376) {
+ // 376 RPL_ENDOFMOTD
+ // :End of /MOTD command"
+ irc.join(self.roomId);
+ }
+ }
+ irc.onerror = function(command) {
+ self.logger.debug('onerror', command)
+ var responseCode = parseInt(command.type);
+ if (responseCode == 431 || responseCode == 432 || responseCode == 433) {
+ // 431 ERR_NONICKNAMEGIVEN
+ // 432 ERR_ERRONEUSNICKNAME
+ // 433 ERR_NICKNAMEINUSE
+ self.onUsernameTaken();
+ }
+/* else if (responseCode == 451) {
+ // 451 is the code for ERR_NOTREGISTERED
+ // Probably means the nick we chose was taken
+ }
+*/
+ }
+}
+WillowChat.clients.IRCClient.prototype.rename = function(newUserName) {
+ var self = this;
+ var irc = self._conn;
+ switch(self.readyState) {
+ case self.READY_STATE_CONNECTING:
+ case self.READY_STATE_CONNECTED:
+ irc.nick(newUserName);
+ self.userName = newUserName;
+ break;
+ default:
+ throw new Error("invalid readyState")
+ }
+}
+
+WillowChat.clients.IRCClient.prototype.sendMessage = function(msg) {
+ var self = this;
+ if (self.readyState != self.READY_STATE_CONNECTED) {
+ throw new Error('invalid readyState: ' + self.readyState);
+ }
+ var irc = self._conn;
+ irc.privmsg(self.roomId, msg);
+}
+
+WillowChat.clients.IRCClient.prototype.sendAction = function(action) {
+ var self = this;
+ if (self.readyState != self.READY_STATE_CONNECTED) {
+ throw new Error('invalid readyState: ' + self.readyState);
+ }
+ var irc = self._conn;
+ irc.action(self.roomId, action);
+}
+
+
+var createXHR = function () {
+ try { return new XMLHttpRequest(); } catch(e) {}
+ try { return new ActiveXObject('MSXML3.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('MSXML2.XMLHTTP.3.0'); } catch(e) {}
+ try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {}
+ try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {}
+ throw new Error('Could not find XMLHttpRequest or an alternative.');
+}
+
+
+})()
diff --git a/moksha/widgets/chat/templates/__init__.py b/moksha/widgets/chat/templates/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/moksha/widgets/chat/templates/bootstrap.mak b/moksha/widgets/chat/templates/bootstrap.mak
new file mode 100644
index 0000000..65ab577
--- /dev/null
+++ b/moksha/widgets/chat/templates/bootstrap.mak
@@ -0,0 +1,419 @@
+(function() {
+var gatherOptions = function(roomOptions, container) {
+ var opts = {}
+ var containerOptions = [ 'width', 'height', 'roomClass', 'reposition', 'theme' ]
+ for (var key in roomOptions) {
+ opts[key] = roomOptions[key]
+ }
+ for (var i = 0; i < containerOptions.length; ++i) {
+ var key = containerOptions[i]
+ var option = container.getAttribute(key)
+ if (option) {
+ opts[key] = option
+ }
+ }
+ if (!opts.roomId) {
+ var roomId = container.getAttribute('roomId')
+ opts.roomId = roomId ? roomId : 'default'
+ }
+ if (!opts.width) {
+ opts.width = 350;
+ }
+ if (!opts.height) {
+ opts.height = 240;
+ }
+ if (!opts.theme) {
+ opts.theme = 'simple'
+ }
+ if (!opts.greeting) {
+ opts.greeting = "Willow Chat"
+ }
+ return opts
+}
+
+var loaded = function() {
+ if (!window.WillowChat) {
+ WillowChat = {}
+ }
+ if (!WillowChat.util) {
+ WillowChat.util = {}
+ }
+ var container = document.getElementById('willowchat');
+ if (!container) {
+ container = document.createElement('div');
+ container.setAttribute('id', 'willowchat');
+ }
+
+
+ var roomClass = container.getAttribute('roomClass');
+ var roomClass= roomClass ? roomClass : 'default'
+ s = document.createElement('script')
+ var baseurl = 'http://' + WillowChat.hostHeader
+ s.src = baseurl + '/apps/chat/rooms?jsonp=WillowChat.util.optionsCallback&op=info&roomClass=' + roomClass
+
+ WillowChat.util.optionsCallback = function(result) {
+ success = result[0]
+ if (!success) {
+ throw new Error("Failed: " + result[1])
+ }
+ room = result[1]
+ var opts = gatherOptions(room, container);
+ ifr = document.createElement('iframe')
+ var staticurl = baseurl + '/toscawidgets/resources/moksha.api.widgets.chat.chat/static'
+ ifr.src = '/apps/chat/index?json=1&opts=' + escape(JSON.stringify(opts))
+ ifr.style.border = "0px";
+ ifr.style.width = "100%";
+ ifr.style.height = "100%";
+ var chromeCallback = function() {
+ container.appendChild(ifr)
+ chrome = new WillowChat.chrome.map[opts.theme](container, opts)
+ }
+ var s = document.createElement('script')
+ // TODO: whats the deal with this? Can't we do any better?
+ s.src = staticurl + '/themes/' + opts.theme + '/chrome.js?ienocache=' + Math.floor(Math.random()*10000)
+ if (s.addEventListener) {
+ s.addEventListener('load', chromeCallback, false)
+ }
+ else if (s.attachEvent) {
+ s.attachEvent('onreadystatechange', function() {
+ if (s.readyState == "loaded") {
+ chromeCallback()
+ }
+ })
+ }
+ if (true) {
+ var k = 3 + 3
+ }
+// var d = document.createElement('div')
+// d.innerHTML = 'go'
+// document.body.appendChild(d)
+ document.getElementsByTagName('head')[0].appendChild(s)
+ }
+ document.getElementsByTagName('head')[0].appendChild(s)
+
+}
+
+$(document).ready(function(){
+ if (!window.WillowChat) { WillowChat = {} }; WillowChat.hostHeader = "${host}";
+ loaded();
+});
+
+})();
+if (!this.JSON) {
+
+// Create a JSON object only if one does not already exist. We create the
+// object in a closure to avoid creating global variables.
+
+ JSON = function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ Date.prototype.toJSON = function (key) {
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapeable.lastIndex = 0;
+ return escapeable.test(string) ?
+ '"' + string.replace(escapeable, function (a) {
+ var c = meta[a];
+ if (typeof c === 'string') {
+ return c;
+ }
+ return '\\u' + ('0000' +
+ (+(a.charCodeAt(0))).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// If the object has a dontEnum length property, we'll treat it as an array.
+
+ if (typeof value.length === 'number' &&
+ !(value.propertyIsEnumerable('length'))) {
+
+// The object is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// Return the JSON object containing the stringify and parse methods.
+
+ return {
+ stringify: function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ },
+
+
+ parse: function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' + ('0000' +
+ (+(a.charCodeAt(0))).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ }
+ };
+ }();
+}
diff --git a/moksha/widgets/chat/templates/chat.mak b/moksha/widgets/chat/templates/chat.mak
new file mode 100644
index 0000000..a3ab679
--- /dev/null
+++ b/moksha/widgets/chat/templates/chat.mak
@@ -0,0 +1,31 @@
+<script>
+ TCPSocket = Orbited.TCPSocket
+ document.domain = document.domain;
+</script>
+
+<div id="popup">
+<div id="popupOuter">
+ <div id="popupMiddle">
+ <div id="popupContent">
+ <p>Greeting</p>
+ <label for="nickname">Nickname:</label>
+ <input type="text" id="nickname" maxlength="16" style="width: 10em;" value="" />
+ </div>
+ </div>
+</div>
+</div>
+
+ <div id="absorbClicks"></div>
+ <div id="presenceToggle">
+ →
+ </div>
+ <div id="presence">
+ <div id="presenceTitle">Presence</div>
+ <div id="presenceList">
+ </div>
+ </div>
+ <div id="history">
+ </div>
+ <div id="inputBar">
+ <textarea id="chatboxInput"></textarea>
+ </div>
diff --git a/setup.py.demo b/setup.py.demo
index faadf9f..bf09429 100644
--- a/setup.py.demo
+++ b/setup.py.demo
@@ -89,11 +89,11 @@ setup(
[moksha.application]
menu = moksha.api.menus.controllers:MokshaMenuController
- chat = moksha.api.widgets.chat.controllers:ChatController
+ chat = moksha.widgets.chat.controllers:ChatController
feeds = moksha.widgets.feedtree.controllers.feed:FeedController
[moksha.widget]
- chat = moksha.api.widgets.chat:LiveChatWidget
+ chat = moksha.widgets.chat:LiveChatWidget
#livefeed_demo = moksha.widgets.demos:LiveFeedDemo
#liveflot = moksha.api.widgets.flot:LiveFlotWidget
#livegraph = moksha.examples.livegraph:LiveGraphWidget
commit 45d3461a22807a6210f1f3d7cb5ea008b41a9baa
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:32:20 2009 -0400
Deprecate moksha.api.widgets.iframe and move it to moksha.widgets.iframe
diff --git a/moksha/api/widgets/iframe.py b/moksha/api/widgets/iframe.py
index da14db9..afd3b03 100644
--- a/moksha/api/widgets/iframe.py
+++ b/moksha/api/widgets/iframe.py
@@ -1,26 +1,4 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from tw.api import Widget
-
-class IFrameWidget(Widget):
- params = ['id', 'url']
- template = """
- <iframe id="${id}" src="${url}" width="100%" height="100%">
- <p>Your browser does not support iframes.</p>
- </iframe>
- """
- engine_name = 'mako'
+from moksha.widgets.iframe import IFrameWidget
+from moksha.lib.helpers import deprecation
+deprecation("The `moksha.api.widgets.iframe` module has been deprecated. "
+ "Please use `moksha.widgets.iframe` instead")
diff --git a/moksha/widgets/iframe.py b/moksha/widgets/iframe.py
new file mode 100644
index 0000000..5f8b4ef
--- /dev/null
+++ b/moksha/widgets/iframe.py
@@ -0,0 +1,33 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+:mod:`moksha.widgets.iframe` - An IFrame Widget
+===============================================
+
+.. moduleauthor:: Luke Macken <lmacken(a)redhat.com>
+"""
+
+from tw.api import Widget
+
+class IFrameWidget(Widget):
+ params = ['id', 'url']
+ template = """
+ <iframe id="${id}" src="${url}" width="100%" height="100%">
+ <p>Your browser does not support iframes.</p>
+ </iframe>
+ """
+ engine_name = 'mako'
commit 0086428885fbd7a45183a671082692c377a2a64d
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:31:50 2009 -0400
Add a moksha.lib.helpers.deprecation helper method
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index 7c43985..58eee9f 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -24,6 +24,7 @@ import simplejson as json
import re
import os
import logging
+import warnings
from tw.api import js_callback
from pytz import timezone, utc
@@ -1028,3 +1029,7 @@ def get_num_cpus():
if line.startswith('processor'):
cpus = int(line.split()[-1]) + 1
return cpus
+
+
+def deprecation(message):
+ warnings.warn(message, DeprecationWarning, level=2)
commit 12860dcb0f890f3192644d7fcfc36ac5449fa8bd
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 20:31:43 2009 -0400
Deprecate the moksha.api.widgets.layout module
diff --git a/moksha/api/widgets/__init__.py b/moksha/api/widgets/__init__.py
index f8de7d3..4614fdb 100644
--- a/moksha/api/widgets/__init__.py
+++ b/moksha/api/widgets/__init__.py
@@ -19,4 +19,3 @@ from util import *
from grid import Grid
from placeholder import Placeholder
from selectable import Selectable
-
diff --git a/moksha/api/widgets/layout/layout.py b/moksha/api/widgets/layout/layout.py
index 6ed6b47..bfc375a 100644
--- a/moksha/api/widgets/layout/layout.py
+++ b/moksha/api/widgets/layout/layout.py
@@ -1,47 +1,4 @@
-# This file is part of Moksha.
-# Copyright (C) 2008-2009 Red Hat, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import moksha
-
-from tw.api import Widget, JSLink, CSSLink
-from tw.jquery import jquery_js
-
-layout_js = JSLink(filename='static/layout.js', modname=__name__)
-layout_css = CSSLink(filename='static/layout.css', modname=__name__)
-ui_core_js = JSLink(filename='static/ui/ui.core.js', modname=__name__)
-ui_draggable_js = JSLink(filename='static/ui/ui.draggable.js', modname=__name__)
-ui_droppable_js = JSLink(filename='static/ui/ui.droppable.js', modname=__name__)
-ui_sortable_js = JSLink(filename='static/ui/ui.sortable.js', modname=__name__)
-
-class LayoutWidget(Widget):
- template = 'mako:moksha.api.widgets.layout.templates.layout'
- params = ['header', 'content', 'sidebar', 'footer', 'invisible']
- css = [layout_css]
- javascript = [jquery_js, layout_js, ui_core_js, ui_draggable_js,
- ui_droppable_js, ui_sortable_js]
-
- header = content = sidebar = footer = invisible = []
-
- def update_params(self, d):
- super(LayoutWidget, self).update_params(d)
- for widget in moksha._widgets.itervalues():
- if hasattr(widget['widget'], 'visible') and \
- not getattr(widget['widget'], 'visible'):
- d['invisible'].append(widget)
- elif hasattr(widget['widget'], 'view'):
- d[getattr(widget['widget'], 'view')].append(widget)
- else:
- d['content'].append(widget)
+from moksha.widgets.deprecated.layout import *
+from moksha.lib.helpers import deprecation
+deprecation("The `moksha.api.widgets.layout` module has been deprecated "
+ "and will be vanishing soon.")
diff --git a/moksha/widgets/deprecated/layout.py b/moksha/widgets/deprecated/layout.py
new file mode 100644
index 0000000..6ed6b47
--- /dev/null
+++ b/moksha/widgets/deprecated/layout.py
@@ -0,0 +1,47 @@
+# This file is part of Moksha.
+# Copyright (C) 2008-2009 Red Hat, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import moksha
+
+from tw.api import Widget, JSLink, CSSLink
+from tw.jquery import jquery_js
+
+layout_js = JSLink(filename='static/layout.js', modname=__name__)
+layout_css = CSSLink(filename='static/layout.css', modname=__name__)
+ui_core_js = JSLink(filename='static/ui/ui.core.js', modname=__name__)
+ui_draggable_js = JSLink(filename='static/ui/ui.draggable.js', modname=__name__)
+ui_droppable_js = JSLink(filename='static/ui/ui.droppable.js', modname=__name__)
+ui_sortable_js = JSLink(filename='static/ui/ui.sortable.js', modname=__name__)
+
+class LayoutWidget(Widget):
+ template = 'mako:moksha.api.widgets.layout.templates.layout'
+ params = ['header', 'content', 'sidebar', 'footer', 'invisible']
+ css = [layout_css]
+ javascript = [jquery_js, layout_js, ui_core_js, ui_draggable_js,
+ ui_droppable_js, ui_sortable_js]
+
+ header = content = sidebar = footer = invisible = []
+
+ def update_params(self, d):
+ super(LayoutWidget, self).update_params(d)
+ for widget in moksha._widgets.itervalues():
+ if hasattr(widget['widget'], 'visible') and \
+ not getattr(widget['widget'], 'visible'):
+ d['invisible'].append(widget)
+ elif hasattr(widget['widget'], 'view'):
+ d[getattr(widget['widget'], 'view')].append(widget)
+ else:
+ d['content'].append(widget)
14 years, 11 months
moksha/api
by Luke Macken
moksha/api/streams/datastream.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 9ec0dc95bda8dc5c48becfe0077c7a21bbfe0036
Author: Luke Macken <lmacken(a)redhat.com>
Date: Sat Jun 27 19:51:55 2009 -0400
Have our PollingDataStream.now default to False.
When :prop:`PollingDataStream.now` is True, Twisted will run it the DataStream
immediately, before exiting __init__. This causes the rest of the hub to
block, waiting for this job to finish. Setting it to False will cause it to
run initially after :prop:`PollingDataStream.frequency` seconds, asynchronously.
diff --git a/moksha/api/streams/datastream.py b/moksha/api/streams/datastream.py
index 94bdcfe..d808b77 100644
--- a/moksha/api/streams/datastream.py
+++ b/moksha/api/streams/datastream.py
@@ -46,7 +46,7 @@ class PollingDataStream(DataStream):
and calls the :meth:`poll` method.
"""
frequency = None # Either a timedelta object, or the number of seconds
- now = True
+ now = False
def __init__(self):
super(PollingDataStream, self).__init__()
14 years, 11 months
moksha/controllers
by Luke Macken
moksha/controllers/root.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
New commits:
commit b98078b98cbb5fe0f09972920c4adf63fb862f13
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Jun 16 08:11:31 2009 -0400
Let moksha work without any menus loaded
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index 57857a4..f39b195 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -64,7 +64,10 @@ class RootController(BaseController):
#@after_render(cache_rendered_data)
@expose('mako:moksha.templates.index')
def index(self):
- tmpl_context.menu_widget = moksha.menus['default_menu']
+ if 'default_menu' in moksha.menus:
+ tmpl_context.menu_widget = moksha.menus['default_menu']
+ else:
+ tmpl_context.menu_widget = ''
#tmpl_context.contextual_menu_widget = moksha.menus['contextual_menu']
return dict(title='[ Moksha ]')
14 years, 11 months
2 commits - moksha/lib setup.py.demo
by Luke Macken
moksha/lib/helpers.py | 3 +++
setup.py.demo | 10 ----------
2 files changed, 3 insertions(+), 10 deletions(-)
New commits:
commit 154fe2a26fe3eedb3f010457d2ecaed56bd204b0
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Jun 12 01:42:15 2009 -0400
Remove duplicate package_data in the setup.py
diff --git a/setup.py.demo b/setup.py.demo
index f74b928..faadf9f 100644
--- a/setup.py.demo
+++ b/setup.py.demo
@@ -16,16 +16,6 @@
from setuptools import setup, find_packages
-package_data = {'moksha': ['i18n/*/LC_MESSAGES/*.mo',
- 'public/favicon',
- 'public/css/*.css',
- 'public/images/*.png',
- 'public/images/*.gif',
- 'public/images/*.jpg',
- 'public/javascript/*.js',
- 'public/javascript/ui/*.js']
- }
-
setup(
name='moksha',
version='0.2',
commit ccc0f6d7ff6698bbbeae4d7506a325960a49e2d1
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Jun 12 01:41:55 2009 -0400
Add a __repr__ to our DateTimeDisplay
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index d69292d..7c43985 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -1006,6 +1006,9 @@ class DateTimeDisplay(object):
def __str__(self):
return self.datetime.strftime('%Y-%m-%d %H:%M:%S %Z%z')
+ def __repr__(self):
+ return "<DateTimeDisplay %r>" % self.datetime
+
def when_ready(func):
"""
14 years, 11 months
moksha/public
by John (J5) Palmieri
moksha/public/javascript/moksha.js | 1 +
1 file changed, 1 insertion(+)
New commits:
commit 6f31ce88d75b03fb53f6f418dc76fd15a90f3c0d
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Jun 9 10:42:08 2009 -0400
added a moksha.url to the loading icon path
diff --git a/moksha/public/javascript/moksha.js b/moksha/public/javascript/moksha.js
index ff2fda6..fe4582c 100644
--- a/moksha/public/javascript/moksha.js
+++ b/moksha/public/javascript/moksha.js
@@ -605,6 +605,7 @@ moksha = {
if (typeof(loading_icon) == 'undefined')
loading_icon = '/images/spinner.gif';
+ loading_icon = moksha.url(loading_icon);
var $msg = $('.message', $overlay_div);
// FIXME: make this globally configurable
$msg.html('<img src="'+ loading_icon + '"></img>');
14 years, 11 months
moksha/connector
by Luke Macken
moksha/connector/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit a7cd8ec02d8333e07e7f6a4045cdfc55ee2de63f
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Jun 8 11:20:45 2009 -0400
Fix a typo:
diff --git a/moksha/connector/utils.py b/moksha/connector/utils.py
index 90009f5..36d7e6a 100644
--- a/moksha/connector/utils.py
+++ b/moksha/connector/utils.py
@@ -287,7 +287,7 @@ class WeightedSearch(object):
if not isinstance(col_value, basestring):
col_value = ''
else:
- if not isinstace(col_value, unicode):
+ if not isinstance(col_value, unicode):
col_value = unicode(item.get(col_value, ''), 'utf-8')
col_value = col_value.lower()
14 years, 11 months
2 commits - moksha.spec
by Luke Macken
moksha.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit b0d201c2527ea1ecb0014e40d8db751f96b50eaf
Merge: 2983d54... 140c3d9...
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Jun 8 10:51:07 2009 -0400
Merge branch 'master' of git+ssh://git.fedorahosted.org/git/moksha
commit 2983d54bba64c28ad488fc6e5a05214cec3bcfac
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Jun 8 10:50:55 2009 -0400
Fix a trivial issue in our spec
diff --git a/moksha.spec b/moksha.spec
index d8b305e..097438d 100644
--- a/moksha.spec
+++ b/moksha.spec
@@ -52,7 +52,7 @@ information can be found on the Moksha Project Page at
%package doc
Summary: Developer documentation for Moksha
Group: Documentation
-Requires: %name = %{version}-%{release}
+Requires: %{name} = %{version}-%{release}
%description doc
This package contains developer documentation for Moksha along with
14 years, 11 months