Permalink
Browse files

Refactored editor/presenter handling to use inter-frame communication…

…, for easy embedding of any web app within GraphTerm
  • Loading branch information...
1 parent 8728a8f commit 97d9158f7e8aa6a1f31de9a443090ec6835f2898 @mitotic committed Sep 23, 2012
View
@@ -159,7 +159,7 @@ except Exception:
lines = 24
columns = 80
-max_width = max([5]+[len(fileinfo[1]) for fileinfo in File_list])
+max_width = max([7]+[len(fileinfo[1]) for fileinfo in File_list])
ncols = max(1, columns // (max_width+1))
Table_list = ['<table frame=none border=0>',
View
@@ -4,8 +4,13 @@
options=""
file=""
+editor=""
for arg in $*; do
- if [[ "$arg" == -* ]]; then
+ if [ "$arg" == "--ace" ]; then
+ editor="ace"
+ elif [ "$arg" == "--ckeditor" ]; then
+ editor="ckeditor"
+ elif [[ "$arg" == -* ]]; then
options="$options $arg"
else
file="$arg"
@@ -33,7 +38,7 @@ echocmd1="echo -n"
##echocmd1="/bin/echo -e"
echocmd2="echo"
-headers='{"content_type": "text/html", "x_gterm_response": "edit_file", "x_gterm_parameters": {"filepath": "'"${file}"'", "editor": "", "modify": "true", "command": "", "current_directory": "'"${PWD}"'"}}'
+headers='{"content_type": "text/html", "x_gterm_response": "edit_file", "x_gterm_parameters": {"filepath": "'"${file}"'", "editor": "'"${editor}"'", "modify": "true", "command": "", "current_directory": "'"${PWD}"'"}}'
esc=`printf "\033"`
nl=`printf "\012"`
View
@@ -43,6 +43,8 @@
RETRY_SEC = 15
+AJAX_EDITORS = set(["ace", "ckeditor", "textarea"])
+
OSHELL_NAME = "osh"
##SHELL_CMD = "bash -l"
@@ -60,8 +62,8 @@
DEFAULT_HTTP_PORT = 8900
DEFAULT_HOST_PORT = DEFAULT_HTTP_PORT - 1
-HOST_RE = re.compile(r"^[\w\-\.\*\?\[\]]+$") # Allowed host names
-SESSION_RE = re.compile(r"^[a-z\*\?\[\]][\w\*\?\[\]]*$") # Allowed session names
+HOST_RE = re.compile(r"^[\w\-\.\*\?\[\]]+$") # Allowed host names
+SESSION_RE = re.compile(r"^[a-z\*\?\[\]][\w\*\?\[\]]*$") # Allowed session names
Host_secret = None
IO_loop = None
@@ -469,7 +471,7 @@ def logmessage(self, log_level, msg, exc_info=None, logtype="", plaintext=""):
sys.stderr.write((plaintext or msg)+"\n")
def editback(self, content, filepath="", filetype="", editor="", modify=False):
- if editor and editor != "web":
+ if editor and editor not in AJAX_EDITORS:
return otrace.TraceCallback.editback(self, content, filepath=filepath, filetype=filetype,
editor=editor, modify=modify)
params = {"editor": editor, "modify": modify, "command": "edit -f "+filepath if modify else "",
View
@@ -60,6 +60,8 @@
except ImportError:
from ordereddict import OrderedDict
+APPS_URL = "/static"
+
App_dir = os.path.join(os.getenv("HOME"), ".graphterm")
File_dir = os.path.dirname(__file__)
if File_dir == ".":
@@ -422,7 +424,7 @@ def open(self):
"about_url": about.url, "about_description": about.description,
"controller": self.controller,
"wildcard": bool(self.wildcard), "display_splash": display_splash,
- "feedback": term_feedback,
+ "apps_url": APPS_URL, "feedback": term_feedback,
"state_id": self.authorized["state_id"]}]])
except Exception, excp:
logging.warning("GTSocket.open: ERROR %s", excp)
@@ -474,6 +476,7 @@ def on_message(self, message):
controller = self.wildcard or (self.remote_path in self._control_set and self.websocket_id in self._control_set[self.remote_path])
+ from_user = self.authorized["user"] if self.authorized else ""
conn = None
allow_feedback_only = False
if not self.wildcard:
@@ -527,27 +530,32 @@ def on_message(self, message):
if msg[1]:
self._webcast_paths[self.remote_path] = time.time()
- elif msg[0] == "broadcast":
+ elif msg[0] == "send_msg":
if self.wildcard:
continue
+ to_user = msg[1]
ws_list = GTSocket._watch_set.get(self.remote_path)
if not ws_list:
continue
for ws_id in ws_list:
- if ws_id != self.websocket_id:
- # Broadcast to all watchers (excluding originator)
- ws = GTSocket._all_websockets.get(ws_id)
- if ws:
+ if ws_id == self.websocket_id:
+ continue
+ # Broadcast to all watchers (excluding originator)
+ ws = GTSocket._all_websockets.get(ws_id)
+ if not ws:
+ continue
+ ws_user = ws.authorized["user"] if ws.authorized else ""
+ if (not to_user and controller) or to_user == "*" or to_user == ws_user:
+ try:
+ # Change command and add from_user
+ ws.write_message(json.dumps([["receive_msg", from_user] + msg[1:]]))
+ except Exception, excp:
+ logging.error("edit_broadcast: ERROR %s", excp)
try:
- # Strip broadcast prefix from message
- ws.write_message(json.dumps([msg[1:]]))
- except Exception, excp:
- logging.error("edit_broadcast: ERROR %s", excp)
- try:
- # Close websocket on write error
- ws.close()
- except Exception:
- pass
+ # Close websocket on write error
+ ws.close()
+ except Exception:
+ pass
else:
req_list.append(msg)
View
@@ -1295,6 +1295,9 @@ def gterm_append(self, s):
# Note: blob content should be Base64 encoded
self.screen_callback(self.term_name, "", "create_blob",
[blob_id, headers, content])
+ elif self.gterm_validated and response_type == "frame_msg":
+ self.screen_callback(self.term_name, "", "frame_msg",
+ [response_params.get("user",""), response_params.get("frame",""), content])
elif self.gterm_validated or plain_text:
headers["content_length"] = len(content)
params = {"validated": self.gterm_validated, "headers": headers}
View
@@ -0,0 +1,133 @@
+<!-- ace.html: graphterm editor page -->
+<html>
+ <head>
+ <title>GraphTerm Ajax.org Cloud9 Editor</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+ <script type="text/javascript" src="jquery/jquery.min.js"></script>
+ <script src="ace/ace.js" type="text/javascript" charset="utf-8"></script>
+ <script src="ace/mode-css.js" type="text/javascript" charset="utf-8"></script>
+ <script src="ace/mode-html.js" type="text/javascript" charset="utf-8"></script>
+ <script src="ace/mode-javascript.js" type="text/javascript" charset="utf-8"></script>
+ <script src="ace/mode-python.js" type="text/javascript" charset="utf-8"></script>
+ <script src="ace/mode-xml.js" type="text/javascript" charset="utf-8"></script>
+
+ <script>
+function GTermEditor(frameDispatcher) {
+ this.frameDispatcher = frameDispatcher;
+ this.frameName = "editor";
+ this.frameApp = "ace";
+}
+
+GTermEditor.prototype.resize = function() {
+}
+
+GTermEditor.prototype.clear = function() {
+}
+
+GTermEditor.prototype.open = function(props) {
+ this.props = props;
+ var params = props.params;
+ //console.log("GTermEditor.open", params);
+ this.editor = ace.edit("editarea_content");
+ //this.editor.setTheme("theme/twilight")
+ try {
+ // Overrride undo manager to broadcast edit deltas
+ function GTUndoManager() {
+ }
+
+ var AceUndoManager = ace.require("ace/undomanager").UndoManager;
+ GTUndoManager.prototype = new AceUndoManager();
+
+ GTUndoManager.prototype.execute = function(options) {
+ var deltas = options.args[0][0].deltas;
+ if (gEditor.props.controller) {
+ //console.log("GTUndoManager.execute: ", deltas);
+ gEditor.send(["deltas", deltas]);
+ }
+ return AceUndoManager.prototype.execute.call(this, options);
+ };
+
+ this.editor.getSession().setUndoManager(new GTUndoManager());
+ } catch (err) {}
+
+ try {
+ if (params.filetype)
+ this.editor.getSession().setMode("ace/mode/"+params.filetype);
+ } catch(err) {
+ console.log("ERROR in mode:", params.filetype, err);
+ }
+
+ this.editor.getSession().setValue(props.content);
+ setTimeout(this.resize, 500);
+}
+
+GTermEditor.prototype.getContent = function() {
+ return this.editor.getSession().getValue();
+}
+
+GTermEditor.prototype.receive = function(fromUser, toUser, msg) {
+ if (msg[0] == "deltas")
+ this.editor.getSession().doc.applyDeltas(msg[1]);
+ else
+ this.close()
+}
+
+GTermEditor.prototype.send = function(msg) {
+ if (!this.frameDispatcher)
+ return;
+ try {
+ this.frameDispatcher.send("", "editor", msg);
+ } catch(err) {
+ console.log("GTermEditor.prototype.send: "+err);
+ }
+}
+
+GTermEditor.prototype.close = function(save) {
+ if (!this.frameDispatcher)
+ return;
+ try {
+ this.frameDispatcher.close(this.frameName, save);
+ } catch(err) {
+ console.log("GTermEditor.prototype.close: "+err);
+ }
+}
+
+var gEditor = null;
+
+$(document).ready(function() {
+ if (window.parent && window.parent.gFrameDispatcher) {
+ gEditor = new GTermEditor(window.parent.gFrameDispatcher);
+ gEditor.frameDispatcher.open(gEditor, window.frameElement);
+ } else {
+ gEditor = new GTermEditor(null);
+ var props = {controller: true,
+ params: {filetype: "text"},
+ content: "The quick brown fox jumps over the lazy dog."}
+ gEditor.open(props);
+ }
+});
+ </script>
+ <style>
+ #editarea_content {
+ width:100%;
+ height: 100%;
+ background-color: white;
+ }
+ </style>
+ </head>
+
+<body>
+<!-- ACE editor -->
+<div id="editarea" class="editarea">
+ <span id="editarea_title">Ajax.org Cloud9 Editor</span>
+ <button id="editarea_button_apply" onclick="gEditor.close(true);">Save</button>
+ <button id="editarea_button_quit" onclick="gEditor.close(false);">Discard</button>
+ <div id="editarea_container" class="editarea_container">
+ <div id="editarea_content" name="editarea_content"></div>
+ </div>
+</div> <!-- editarea -->
+
+</body>
+</html>
View
@@ -0,0 +1,110 @@
+<!-- ckeditor.html: graphterm editor page -->
+<html>
+ <head>
+ <title>GraphTerm CKEditor</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+ <script type="text/javascript" src="jquery/jquery.min.js"></script>
+ <script type="text/javascript" src="ckeditor/ckeditor.js" charset="utf-8"></script>
+ <script type="text/javascript" src="ckeditor/adapters/jquery.js"></script>
+
+ <script>
+function GTermEditor(frameDispatcher) {
+ this.frameDispatcher = frameDispatcher;
+ this.frameName = "editor";
+ this.frameApp = "ckeditor";
+}
+
+GTermEditor.prototype.resize = function() {
+ var defaultHeight = 300;
+ var newHeight = window.innerHeight-150;
+ var height = defaultHeight > newHeight ? defaultHeight : newHeight;
+ for (var name in CKEDITOR.instances){
+ var instance = CKEDITOR.instances[name];
+ instance.resize('100%', height);
+ }
+}
+
+GTermEditor.prototype.clear = function() {
+ for (var name in CKEDITOR.instances){
+ var instance = CKEDITOR.instances[name];
+ instance.destroy();
+ }
+}
+
+GTermEditor.prototype.open = function(props) {
+ this.props = props;
+ CKEDITOR.config.startupMode = (props.params.filetype == "html") ? "wysiwyg" : "source";
+ this.editor = $("#editarea_content").ckeditor({toolbar: "Basic"});
+ $("#editarea_content").ckeditorGet().setData(props.content);
+ setTimeout(this.resize, 500);
+}
+
+GTermEditor.prototype.getContent = function() {
+ return $("#editarea_content").ckeditorGet().getData();
+}
+
+GTermEditor.prototype.receive = function(fromUser, toUser, msg) {
+ if (msg[0] != "deltas")
+ this.close()
+}
+
+GTermEditor.prototype.send = function(msg) {
+ if (!this.frameDispatcher)
+ return;
+ try {
+ this.frameDispatcher.send("", "editor", msg);
+ } catch(err) {
+ console.log("GTermEditor.prototype.send: "+err);
+ }
+}
+
+GTermEditor.prototype.close = function(save) {
+ if (!this.frameDispatcher)
+ return;
+ try {
+ this.frameDispatcher.close(this.frameName, save);
+ } catch(err) {
+ console.log("GTermEditor.prototype.close: "+err);
+ }
+}
+
+var gEditor = null;
+
+$(document).ready(function() {
+ if (window.parent && window.parent.gFrameDispatcher) {
+ gEditor = new GTermEditor(window.parent.gFrameDispatcher);
+ gEditor.frameDispatcher.open(gEditor, window.frameElement);
+ } else {
+ gEditor = new GTermEditor(null);
+ var props = {controller: true,
+ params: {filetype: "text"},
+ content: "The quick brown fox jumps over the lazy dog."}
+ gEditor.open(props);
+ }
+});
+
+ </script>
+ <style>
+ #editarea_content {
+ width:100%;
+ height: 100%;
+ background-color: white;
+ }
+ </style>
+ </head>
+
+<body>
+<!-- CK editor -->
+<div id="editarea" class="editarea">
+ <span id="editarea_title">CK Editor</span>
+ <button id="editarea_button_apply" onclick="gEditor.close(true);">Save</button>
+ <button id="editarea_button_quit" onclick="gEditor.close(false);">Discard</button>
+ <div id="editarea_container" class="editarea_container">
+ <div id="editarea_content" name="editarea_content"></div>
+ </div>
+</div> <!-- editarea -->
+
+</body>
+</html>
Oops, something went wrong.

0 comments on commit 97d9158

Please sign in to comment.