Initial commit
[atlantis.git] / interface.js
blob02aa71010ea6c6ffc53e86d2807c6ad619a158aa
1 /*
2  * interface.js - The Atlantis user interface
3  * (c) 2008  Sander Dijkhuis <sander.dijkhuis@gmail.com>
4  * Still need to decide about licensing.  Ask if interested.
5  */
7 var Atlantis = {
8     DEBUG: true,
10     CTRL_KEY_CODE: 17,
11     BACKSP_KEY_CODE: 8,
12     DOC_KEY_CODE: 19,
13     contentElement: null,
14     commanding: false,
15     commandElts: {              // very bad probably
16         block: null,
17         string: null,
18         alternatives: null
19     },
20     commandString: '',
21     commandMatches: null,
22     message: '',
23     messageElt: null,
24     messageShown: false,
25     commands: new Array(),
26     initFunctions: new Array(),
27     initialized: false,
29     init: function() {
30         this.contentElement = document.getElementById('content');
32         this.commandElts.block  = document.getElementById('command-block');
33         this.commandElts.string = document.getElementById('command-string');
34         this.commandElts.alternatives =
35             document.getElementById('command-alternatives');
37         this.messageElt = document.getElementById('message');
39         this.addDefaultCommands();
41         this.toggleCommandMode(false);
42         this.hideMessage();
44         this.contentElement.focus();
46         for (i in this.initFunctions)
47             this.initFunctions[i]();
49         this.initialized = true;
50     },
52     addInitFunction: function(f) {
53         if (this.initalized)
54             f();
55         else
56             this.initFunctions.push(f);
57     },
59     toggleCommandMode: function(on) {
60         this.commanding = on;
61         this.commandElts.block.style.visibility = on? 'visible' : 'hidden';
62         if (!on) {
63             this.setCommandAlternatives('');
64             this.setCommandString('');
65         }
66     },
68     addCommandChar: function(c) {
69         this.setCommandString(this.commandString + c);
70         this.updateCommandMatches();
71     },
73     updateCommandMatches: function() {
74         this.commandMatches = new Array();
75         var s = '';
76         var match;
77         for (i in this.commands) {
78             match = this.matchCommand(this.commands[i].name,
79                                       this.commandString);
80             if (match != null) {
81                 s += '<li>' + match;
82                 this.commandMatches.push(this.commands[i].name);
83             }
84         }
86         this.setCommandAlternatives(s);
87     },
89     matchCommand: function(command, input) {
90         var i = 0;
91         var html = '';
92         var j;
93         var c;
94         var foundIt = false;
95         for (j in command) {
96             c = command[j];
97             if (input[i] == c && !foundIt) {
98                 i++;
99                 if (i == input.length)
100                     foundIt = true;
101                 html += '<b>' + c + '</b>';
102             } else {
103                 html += c;
104             }
105         }
106         if (foundIt) {
107             return html;
108         }
109         else
110             return null;
111     },
113     deleteCommandChar: function() {
114         this.setCommandString(this.commandString.substring(0,
115                                                            this.commandString.
116                                                            length - 1));
117         this.updateCommandMatches();
118     },
120     setCommandString: function(s) {
121         this.commandString = this.commandElts.string.innerHTML = s;
122     },
124     setCommandAlternatives: function(s) {
125         this.commandElts.alternatives.style.visibility =
126             s? 'visible' : 'hidden';
127         this.commandElts.alternatives.innerHTML = s;
128     },
130     execute: function(command) {
131         var available;
132         for (i in this.commands)
133             if (command == this.commands[i].name)
134                 return this.commands[i].run();
135     },
137     showUnknownCommand: function(command) {
138         this.showMessage('Unknown command: <b>' + command + '</b>');
139     },
141     showMessage: function(s) {
142         this.messageShown = true;
143         this.messageElt.style.visibility = 'visible';
144         this.messageElt.childNodes[0].innerHTML = s;
145     },
147     hideMessage: function() {
148         this.messageShown = false;
149         this.messageElt.style.visibility = 'hidden';
150     },
152     insertHTML: function(s) {
153         document.execCommand('insertHTML', undefined, s);
154     },
156     addCommand: function(command) {
157         this.commands.push(command);
158         this.commands.sort();
159     },
161     getXMLHttpRequestObject: function() {
162         var obj = null;
164         if (window.XMLHttpRequest)
165             obj = new XMLHttpRequest();
166         else if (window.ActiveXObject)
167             obj = new ActiveXObject('Microsoft.XMLHTTP');
169         return obj;
170     },
172     loadService: function(serviceId) {
173         this.loadScript('/-/' + serviceId + '/main.js');
174     },
176     loadScript: function(url) {
177         var xhr = this.getXMLHttpRequestObject();
178         xhr.onreadystatechange = function() {
179             if (xhr.readyState != 4)
180                 return;
181             if (xhr.status == 200)
182                 (function() { eval(xhr.responseText); })();
183         };
184         xhr.open('GET', url, true);
185         xhr.send(null);
186     }
189 /* temporary function for adding temporary commands quickly and uglily */
190 Atlantis.addDefaultCommands = function() {
191     var i;
192     var cmd;
193     var cmds =
194     [
195      ['undo', '', function() {
196              document.execCommand('undo', undefined, undefined);
197          }, null],
198      ['redo', '', function() {
199              document.execCommand('redo', undefined, undefined);
200          }, null],
201      ['new document', '', function() {
202              // doesn't work if in <ul>
203              Atlantis.insertHTML('<hr class=doc-char>');
204          }, null],
205      ['commands', '', function() {
206              var i;
207              var command;
208              s = '<h3>Commands</h3><ul>';
209              for (i in Atlantis.commands) {
210                  command = Atlantis.commands[i];
211                  s += '<li><b>' + command.name.replace(/_/g, ' ') + '</b>';
212                  if (command.doc)
213                      s += ' - ' + command.doc;
214              }
215              s += '</ul>';
216              Atlantis.insertHTML(s);
217          }, null],
218      ['hello world', '', function() {
219              Atlantis.insertHTML('Hello, World!');
220          }, null]
221      ];
223     for (i in cmds) {
224         cmd = new Atlantis.Command();
225         cmd.name = cmds[i][0];
226         cmd.doc = cmds[i][1];
227         cmd.run = cmds[i][2];
228         cmd.data = cmds[i][3];
229         Atlantis.addCommand(cmd);
230     }
232     cmd = new Atlantis.Command();
233     cmd.name = 'data test';
234     cmd.doc = 'Testing data.';
235     cmd.data = { i: 0 };
236     cmd.run = function() {
237         Atlantis.insertHTML(cmd.data.i++);
238     };
239     Atlantis.addCommand(cmd);
242 Atlantis.Command = function() {
245 Atlantis.Command.prototype = {
246     name: '',
247     doc: '',
248     run: null,
249     data: null,
250     toString: function() {
251         return this.name;
252     },
255 function onkeydown(evt) {
256     if (Atlantis.messageShown)
257         Atlantis.hideMessage();
259     if (evt.keyCode == Atlantis.CTRL_KEY_CODE) {
260         Atlantis.toggleCommandMode(true);
261         return false;
262     }
265 function onkeyup(evt) {
266     if (evt.keyCode == Atlantis.CTRL_KEY_CODE) {
267         if (Atlantis.commandString) {
268             if (Atlantis.commandMatches.length > 0)
269                 Atlantis.execute(Atlantis.commandMatches[0]);
270             else
271                 Atlantis.showUnknownCommand(Atlantis.commandString);
272         }
273         Atlantis.toggleCommandMode(false);
274     }
277 function onkeypress(evt) {
278     if (Atlantis.commanding) {
279         if (evt.which == Atlantis.BACKSP_KEY_CODE)
280             Atlantis.deleteCommandChar();
281         else
282             Atlantis.addCommandChar(String.fromCharCode(evt.charCode));
283         return false;
284     } else if (evt.keyCode == Atlantis.DOC_KEY_CODE)
285         Atlantis.execute('new document');
288 function oncontextmenu(evt) {
289     return false;
292 function onload(evt) {
293     Atlantis.init();