5a920362 |
1 | /** |
2 | * This code is mostly from the old Etherpad. Please help us to comment this code. |
3 | * This helps other people to understand this code better and helps them to improve it. |
4 | * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED |
5 | */ |
6 | |
7 | /** |
8 | * Copyright 2009 Google Inc., 2011 Peter 'Pita' Martischka (Primary Technology Ltd) |
9 | * |
10 | * Licensed under the Apache License, Version 2.0 (the "License"); |
11 | * you may not use this file except in compliance with the License. |
12 | * You may obtain a copy of the License at |
13 | * |
14 | * http://www.apache.org/licenses/LICENSE-2.0 |
15 | * |
16 | * Unless required by applicable law or agreed to in writing, software |
17 | * distributed under the License is distributed on an "AS-IS" BASIS, |
18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
19 | * See the License for the specific language governing permissions and |
20 | * limitations under the License. |
21 | */ |
22 | |
23 | /* global $, window */ |
24 | |
25 | var socket; |
26 | |
27 | // These jQuery things should create local references, but for now `require()` |
28 | // assigns to the global `$` and augments it with plugins. |
29 | require('/jquery'); |
30 | require('/farbtastic'); |
31 | require('/excanvas'); |
32 | JSON = require('/json2'); |
33 | require('/undo-xpopup'); |
34 | require('/prefixfree'); |
35 | |
36 | var chat = require('/chat').chat; |
37 | var getCollabClient = require('/collab_client').getCollabClient; |
38 | var padconnectionstatus = require('/pad_connectionstatus').padconnectionstatus; |
39 | var padcookie = require('/pad_cookie').padcookie; |
40 | var paddocbar = require('/pad_docbar').paddocbar; |
41 | var padeditbar = require('/pad_editbar').padeditbar; |
42 | var padeditor = require('/pad_editor').padeditor; |
43 | var padimpexp = require('/pad_impexp').padimpexp; |
44 | var padmodals = require('/pad_modals').padmodals; |
45 | var padsavedrevs = require('/pad_savedrevs').padsavedrevs; |
46 | var paduserlist = require('/pad_userlist').paduserlist; |
47 | var padutils = require('/pad_utils').padutils; |
48 | |
49 | var createCookie = require('/pad_utils').createCookie; |
50 | var readCookie = require('/pad_utils').readCookie; |
51 | var randomString = require('/pad_utils').randomString; |
52 | |
53 | function getParams() |
54 | { |
55 | var params = getUrlVars() |
56 | var showControls = params["showControls"]; |
57 | var showChat = params["showChat"]; |
58 | var userName = params["userName"]; |
59 | var showLineNumbers = params["showLineNumbers"]; |
60 | var useMonospaceFont = params["useMonospaceFont"]; |
61 | var IsnoColors = params["noColors"]; |
62 | var hideQRCode = params["hideQRCode"]; |
63 | var rtl = params["rtl"]; |
64 | var alwaysShowChat = params["alwaysShowChat"]; |
65 | |
66 | if(IsnoColors) |
67 | { |
68 | if(IsnoColors == "true") |
69 | { |
70 | settings.noColors = true; |
71 | $('#clearAuthorship').hide(); |
72 | } |
73 | } |
74 | if(showControls) |
75 | { |
76 | if(showControls == "false") |
77 | { |
78 | $('#editbar').hide(); |
79 | $('#editorcontainer').css({"top":"0px"}); |
80 | } |
81 | } |
82 | if(showChat) |
83 | { |
84 | if(showChat == "false") |
85 | { |
86 | $('#chaticon').hide(); |
87 | } |
88 | } |
89 | if(showLineNumbers) |
90 | { |
91 | if(showLineNumbers == "false") |
92 | { |
93 | settings.LineNumbersDisabled = true; |
94 | } |
95 | } |
96 | if(useMonospaceFont) |
97 | { |
98 | if(useMonospaceFont == "true") |
99 | { |
100 | settings.useMonospaceFontGlobal = true; |
101 | } |
102 | } |
103 | if(userName) |
104 | { |
105 | // If the username is set as a parameter we should set a global value that we can call once we have initiated the pad. |
106 | settings.globalUserName = decodeURIComponent(userName); |
107 | } |
108 | if(hideQRCode) |
109 | { |
110 | $('#qrcode').hide(); |
111 | } |
112 | if(rtl) |
113 | { |
114 | if(rtl == "true") |
115 | { |
116 | settings.rtlIsTrue = true |
117 | } |
118 | } |
119 | if(alwaysShowChat) |
120 | { |
121 | if(alwaysShowChat == "true") |
122 | { |
123 | chat.stickToScreen(); |
124 | } |
125 | } |
126 | } |
127 | |
128 | function getUrlVars() |
129 | { |
130 | var vars = [], hash; |
131 | var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); |
132 | for(var i = 0; i < hashes.length; i++) |
133 | { |
134 | hash = hashes[i].split('='); |
135 | vars.push(hash[0]); |
136 | vars[hash[0]] = hash[1]; |
137 | } |
138 | return vars; |
139 | } |
140 | |
141 | function savePassword() |
142 | { |
143 | //set the password cookie |
144 | createCookie("password",$("#passwordinput").val(),null,document.location.pathname); |
145 | //reload |
146 | document.location=document.location; |
147 | } |
148 | |
149 | function ieTestXMLHTTP(){ |
150 | // Test for IE known XML HTTP issue |
151 | if ($.browser.msie && !window.XMLHttpRequest){ |
152 | $("#editorloadingbox").html("You do not have XML HTTP enabled in your browser. <a target='_blank' href='https://github.com/Pita/etherpad-lite/wiki/How-to-enable-native-XMLHTTP-support-in-IE'>Fix this issue</a>"); |
153 | } |
154 | } |
155 | function handshake() |
156 | { |
157 | var loc = document.location; |
158 | //get the correct port |
159 | var port = loc.port == "" ? (loc.protocol == "https:" ? 443 : 80) : loc.port; |
160 | //create the url |
161 | var url = loc.protocol + "//" + loc.hostname + ":" + port + "/"; |
162 | //find out in which subfolder we are |
163 | var resource = loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "socket.io"; |
164 | //connect |
165 | socket = pad.socket = io.connect(url, { |
166 | resource: resource, |
167 | 'max reconnection attempts': 3, |
168 | 'sync disconnect on unload' : false |
169 | }); |
170 | |
171 | function sendClientReady(isReconnect) |
172 | { |
173 | var padId = document.location.pathname.substring(document.location.pathname.lastIndexOf("/") + 1); |
174 | padId = decodeURIComponent(padId); // unescape neccesary due to Safari and Opera interpretation of spaces |
175 | |
176 | if(!isReconnect) |
177 | document.title = padId.replace(/_+/g, ' ') + " | " + document.title; |
178 | |
179 | var token = readCookie("token"); |
180 | if (token == null) |
181 | { |
182 | token = "t." + randomString(); |
183 | createCookie("token", token, 60); |
184 | } |
185 | |
186 | var sessionID = readCookie("sessionID"); |
187 | var password = readCookie("password"); |
188 | |
189 | var msg = { |
190 | "component": "pad", |
191 | "type": "CLIENT_READY", |
192 | "padId": padId, |
193 | "sessionID": sessionID, |
194 | "password": password, |
195 | "token": token, |
196 | "protocolVersion": 2 |
197 | }; |
198 | |
199 | //this is a reconnect, lets tell the server our revisionnumber |
200 | if(isReconnect == true) |
201 | { |
202 | msg.client_rev=pad.collabClient.getCurrentRevisionNumber(); |
203 | msg.reconnect=true; |
204 | } |
205 | |
206 | socket.json.send(msg); |
207 | }; |
208 | |
209 | var disconnectTimeout; |
210 | |
211 | socket.once('connect', function () { |
212 | sendClientReady(false); |
213 | }); |
214 | |
215 | socket.on('reconnect', function () { |
216 | //reconnect is before the timeout, lets stop the timeout |
217 | if(disconnectTimeout) |
218 | { |
219 | clearTimeout(disconnectTimeout); |
220 | } |
221 | |
222 | pad.collabClient.setChannelState("CONNECTED"); |
223 | sendClientReady(true); |
224 | }); |
225 | |
226 | socket.on('disconnect', function (reason) { |
227 | if(reason == "booted"){ |
228 | pad.collabClient.setChannelState("DISCONNECTED"); |
229 | } else { |
230 | function disconnectEvent() |
231 | { |
232 | pad.collabClient.setChannelState("DISCONNECTED", "reconnect_timeout"); |
233 | } |
234 | |
235 | pad.collabClient.setChannelState("RECONNECTING"); |
236 | |
237 | disconnectTimeout = setTimeout(disconnectEvent, 10000); |
238 | } |
239 | }); |
240 | |
241 | var receivedClientVars = false; |
242 | var initalized = false; |
243 | |
244 | socket.on('message', function(obj) |
245 | { |
246 | //the access was not granted, give the user a message |
247 | if(!receivedClientVars && obj.accessStatus) |
248 | { |
249 | if(obj.accessStatus == "deny") |
250 | { |
251 | $("#editorloadingbox").html("<b>You do not have permission to access this pad</b>"); |
252 | } |
253 | else if(obj.accessStatus == "needPassword") |
254 | { |
255 | $("#editorloadingbox").html("<b>You need a password to access this pad</b><br>" + |
256 | "<input id='passwordinput' type='password' name='password'>"+ |
257 | "<button type='button' onclick=\"" + padutils.escapeHtml('require('+JSON.stringify(module.id)+").savePassword()") + "\">ok</button>"); |
258 | } |
259 | else if(obj.accessStatus == "wrongPassword") |
260 | { |
261 | $("#editorloadingbox").html("<b>You're password was wrong</b><br>" + |
262 | "<input id='passwordinput' type='password' name='password'>"+ |
263 | "<button type='button' onclick=\"" + padutils.escapeHtml('require('+JSON.stringify(module.id)+").savePassword()") + "\">ok</button>"); |
264 | } |
265 | } |
266 | |
267 | //if we haven't recieved the clientVars yet, then this message should it be |
268 | else if (!receivedClientVars) |
269 | { |
270 | //log the message |
271 | if (window.console) console.log(obj); |
272 | |
273 | receivedClientVars = true; |
274 | |
275 | //set some client vars |
276 | clientVars = obj; |
277 | clientVars.userAgent = "Anonymous"; |
278 | clientVars.collab_client_vars.clientAgent = "Anonymous"; |
279 | |
280 | //initalize the pad |
281 | pad._afterHandshake(); |
282 | initalized = true; |
283 | |
284 | // If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers |
285 | if (settings.LineNumbersDisabled == true) |
286 | { |
287 | pad.changeViewOption('showLineNumbers', false); |
288 | } |
289 | |
290 | // If the noColors value is set to true then we need to hide the background colors on the ace spans |
291 | if (settings.noColors == true) |
292 | { |
293 | pad.changeViewOption('noColors', true); |
294 | } |
295 | |
296 | if (settings.rtlIsTrue == true) |
297 | { |
298 | pad.changeViewOption('rtl', true); |
299 | } |
300 | |
301 | // If the Monospacefont value is set to true then change it to monospace. |
302 | if (settings.useMonospaceFontGlobal == true) |
303 | { |
304 | pad.changeViewOption('useMonospaceFont', true); |
305 | } |
306 | // if the globalUserName value is set we need to tell the server and the client about the new authorname |
307 | if (settings.globalUserName !== false) |
308 | { |
309 | pad.notifyChangeName(settings.globalUserName); // Notifies the server |
310 | pad.myUserInfo.name = settings.globalUserName; |
311 | $('#myusernameedit').attr({"value":settings.globalUserName}); // Updates the current users UI |
312 | } |
313 | } |
314 | //This handles every Message after the clientVars |
315 | else |
316 | { |
317 | //this message advices the client to disconnect |
318 | if (obj.disconnect) |
319 | { |
320 | padconnectionstatus.disconnected(obj.disconnect); |
321 | socket.disconnect(); |
322 | return; |
323 | } |
324 | else |
325 | { |
326 | pad.collabClient.handleMessageFromServer(obj); |
327 | } |
328 | } |
329 | }); |
330 | // Bind the colorpicker |
331 | var fb = $('#colorpicker').farbtastic({ callback: '#mycolorpickerpreview', width: 220}); |
332 | } |
333 | |
334 | var pad = { |
335 | // don't access these directly from outside this file, except |
336 | // for debugging |
337 | collabClient: null, |
338 | myUserInfo: null, |
339 | diagnosticInfo: {}, |
340 | initTime: 0, |
341 | clientTimeOffset: null, |
342 | preloadedImages: false, |
343 | padOptions: {}, |
344 | |
345 | // these don't require init; clientVars should all go through here |
346 | getPadId: function() |
347 | { |
348 | return clientVars.padId; |
349 | }, |
350 | getClientIp: function() |
351 | { |
352 | return clientVars.clientIp; |
353 | }, |
354 | getIsProPad: function() |
355 | { |
356 | return clientVars.isProPad; |
357 | }, |
358 | getColorPalette: function() |
359 | { |
360 | return clientVars.colorPalette; |
361 | }, |
362 | getDisplayUserAgent: function() |
363 | { |
364 | return padutils.uaDisplay(clientVars.userAgent); |
365 | }, |
366 | getIsDebugEnabled: function() |
367 | { |
368 | return clientVars.debugEnabled; |
369 | }, |
370 | getPrivilege: function(name) |
371 | { |
372 | return clientVars.accountPrivs[name]; |
373 | }, |
374 | getUserIsGuest: function() |
375 | { |
376 | return clientVars.userIsGuest; |
377 | }, |
378 | getUserId: function() |
379 | { |
380 | return pad.myUserInfo.userId; |
381 | }, |
382 | getUserName: function() |
383 | { |
384 | return pad.myUserInfo.name; |
385 | }, |
386 | sendClientMessage: function(msg) |
387 | { |
388 | pad.collabClient.sendClientMessage(msg); |
389 | }, |
390 | |
391 | init: function() |
392 | { |
393 | padutils.setupGlobalExceptionHandler(); |
394 | |
395 | $(document).ready(function() |
396 | { |
397 | // test for XML HTTP capabiites |
398 | ieTestXMLHTTP(); |
399 | // start the custom js |
400 | if (typeof customStart == "function") customStart(); |
401 | getParams(); |
402 | handshake(); |
403 | }); |
404 | }, |
405 | _afterHandshake: function() |
406 | { |
407 | pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp; |
408 | |
409 | //initialize the chat |
410 | chat.init(this); |
411 | pad.initTime = +(new Date()); |
412 | pad.padOptions = clientVars.initialOptions; |
413 | |
414 | if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) |
415 | { |
416 | document.domain = document.domain; // for comet |
417 | } |
418 | |
419 | // for IE |
420 | if ($.browser.msie) |
421 | { |
422 | try |
423 | { |
424 | doc.execCommand("BackgroundImageCache", false, true); |
425 | } |
426 | catch (e) |
427 | {} |
428 | } |
429 | |
430 | // order of inits is important here: |
431 | padcookie.init(clientVars.cookiePrefsToSet, this); |
432 | |
433 | $("#widthprefcheck").click(pad.toggleWidthPref); |
434 | // $("#sidebarcheck").click(pad.togglewSidebar); |
435 | |
436 | pad.myUserInfo = { |
437 | userId: clientVars.userId, |
438 | name: clientVars.userName, |
439 | ip: pad.getClientIp(), |
440 | colorId: clientVars.userColor, |
441 | userAgent: pad.getDisplayUserAgent() |
442 | }; |
443 | |
444 | if (clientVars.specialKey) |
445 | { |
446 | pad.myUserInfo.specialKey = clientVars.specialKey; |
447 | if (clientVars.specialKeyTranslation) |
448 | { |
449 | $("#specialkeyarea").html("mode: " + String(clientVars.specialKeyTranslation).toUpperCase()); |
450 | } |
451 | } |
452 | paddocbar.init( |
453 | { |
454 | isTitleEditable: pad.getIsProPad(), |
455 | initialTitle: clientVars.initialTitle, |
456 | initialPassword: clientVars.initialPassword, |
457 | guestPolicy: pad.padOptions.guestPolicy |
458 | }, this); |
459 | padimpexp.init(this); |
460 | padsavedrevs.init(clientVars.initialRevisionList, this); |
461 | |
462 | padeditor.init(postAceInit, pad.padOptions.view || {}, this); |
463 | |
464 | paduserlist.init(pad.myUserInfo, this); |
465 | // padchat.init(clientVars.chatHistory, pad.myUserInfo); |
466 | padconnectionstatus.init(); |
467 | padmodals.init(this); |
468 | |
469 | pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, { |
470 | colorPalette: pad.getColorPalette() |
471 | }, pad); |
472 | pad.collabClient.setOnUserJoin(pad.handleUserJoin); |
473 | pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate); |
474 | pad.collabClient.setOnUserLeave(pad.handleUserLeave); |
475 | pad.collabClient.setOnClientMessage(pad.handleClientMessage); |
476 | pad.collabClient.setOnServerMessage(pad.handleServerMessage); |
477 | pad.collabClient.setOnChannelStateChange(pad.handleChannelStateChange); |
478 | pad.collabClient.setOnInternalAction(pad.handleCollabAction); |
479 | |
480 | function postAceInit() |
481 | { |
482 | padeditbar.init(); |
483 | setTimeout(function() |
484 | { |
485 | padeditor.ace.focus(); |
486 | }, 0); |
487 | if(padcookie.getPref("chatAlwaysVisible")){ // if we have a cookie for always showing chat then show it |
488 | chat.stickToScreen(true); // stick it to the screen |
489 | $('#options-stickychat').prop("checked", true); // set the checkbox to on |
490 | } |
491 | if(padcookie.getPref("showAuthorshipColors") == false){ |
492 | pad.changeViewOption('showAuthorColors', false); |
493 | } |
494 | } |
495 | }, |
496 | dispose: function() |
497 | { |
498 | padeditor.dispose(); |
499 | }, |
500 | notifyChangeName: function(newName) |
501 | { |
502 | pad.myUserInfo.name = newName; |
503 | pad.collabClient.updateUserInfo(pad.myUserInfo); |
504 | //padchat.handleUserJoinOrUpdate(pad.myUserInfo); |
505 | }, |
506 | notifyChangeColor: function(newColorId) |
507 | { |
508 | pad.myUserInfo.colorId = newColorId; |
509 | pad.collabClient.updateUserInfo(pad.myUserInfo); |
510 | //padchat.handleUserJoinOrUpdate(pad.myUserInfo); |
511 | }, |
512 | notifyChangeTitle: function(newTitle) |
513 | { |
514 | pad.collabClient.sendClientMessage( |
515 | { |
516 | type: 'padtitle', |
517 | title: newTitle, |
518 | changedBy: pad.myUserInfo.name || "unnamed" |
519 | }); |
520 | }, |
521 | notifyChangePassword: function(newPass) |
522 | { |
523 | pad.collabClient.sendClientMessage( |
524 | { |
525 | type: 'padpassword', |
526 | password: newPass, |
527 | changedBy: pad.myUserInfo.name || "unnamed" |
528 | }); |
529 | }, |
530 | changePadOption: function(key, value) |
531 | { |
532 | var options = {}; |
533 | options[key] = value; |
534 | pad.handleOptionsChange(options); |
535 | pad.collabClient.sendClientMessage( |
536 | { |
537 | type: 'padoptions', |
538 | options: options, |
539 | changedBy: pad.myUserInfo.name || "unnamed" |
540 | }); |
541 | }, |
542 | changeViewOption: function(key, value) |
543 | { |
544 | var options = { |
545 | view: {} |
546 | }; |
547 | options.view[key] = value; |
548 | pad.handleOptionsChange(options); |
549 | }, |
550 | handleOptionsChange: function(opts) |
551 | { |
552 | // opts object is a full set of options or just |
553 | // some options to change |
554 | if (opts.view) |
555 | { |
556 | if (!pad.padOptions.view) |
557 | { |
558 | pad.padOptions.view = {}; |
559 | } |
560 | for (var k in opts.view) |
561 | { |
562 | pad.padOptions.view[k] = opts.view[k]; |
563 | } |
564 | padeditor.setViewOptions(pad.padOptions.view); |
565 | } |
566 | if (opts.guestPolicy) |
567 | { |
568 | // order important here |
569 | pad.padOptions.guestPolicy = opts.guestPolicy; |
570 | paddocbar.setGuestPolicy(opts.guestPolicy); |
571 | } |
572 | }, |
573 | getPadOptions: function() |
574 | { |
575 | // caller shouldn't mutate the object |
576 | return pad.padOptions; |
577 | }, |
578 | isPadPublic: function() |
579 | { |
580 | return (!pad.getIsProPad()) || (pad.getPadOptions().guestPolicy == 'allow'); |
581 | }, |
582 | suggestUserName: function(userId, name) |
583 | { |
584 | pad.collabClient.sendClientMessage( |
585 | { |
586 | type: 'suggestUserName', |
587 | unnamedId: userId, |
588 | newName: name |
589 | }); |
590 | }, |
591 | handleUserJoin: function(userInfo) |
592 | { |
593 | paduserlist.userJoinOrUpdate(userInfo); |
594 | //padchat.handleUserJoinOrUpdate(userInfo); |
595 | }, |
596 | handleUserUpdate: function(userInfo) |
597 | { |
598 | paduserlist.userJoinOrUpdate(userInfo); |
599 | //padchat.handleUserJoinOrUpdate(userInfo); |
600 | }, |
601 | handleUserLeave: function(userInfo) |
602 | { |
603 | paduserlist.userLeave(userInfo); |
604 | //padchat.handleUserLeave(userInfo); |
605 | }, |
606 | handleClientMessage: function(msg) |
607 | { |
608 | if (msg.type == 'suggestUserName') |
609 | { |
610 | if (msg.unnamedId == pad.myUserInfo.userId && msg.newName && !pad.myUserInfo.name) |
611 | { |
612 | pad.notifyChangeName(msg.newName); |
613 | paduserlist.setMyUserInfo(pad.myUserInfo); |
614 | } |
615 | } |
616 | else if (msg.type == 'chat') |
617 | { |
618 | //padchat.receiveChat(msg); |
619 | } |
620 | else if (msg.type == 'padtitle') |
621 | { |
622 | paddocbar.changeTitle(msg.title); |
623 | } |
624 | else if (msg.type == 'padpassword') |
625 | { |
626 | paddocbar.changePassword(msg.password); |
627 | } |
628 | else if (msg.type == 'newRevisionList') |
629 | { |
630 | padsavedrevs.newRevisionList(msg.revisionList); |
631 | } |
632 | else if (msg.type == 'revisionLabel') |
633 | { |
634 | padsavedrevs.newRevisionList(msg.revisionList); |
635 | } |
636 | else if (msg.type == 'padoptions') |
637 | { |
638 | var opts = msg.options; |
639 | pad.handleOptionsChange(opts); |
640 | } |
641 | else if (msg.type == 'guestanswer') |
642 | { |
643 | // someone answered a prompt, remove it |
644 | paduserlist.removeGuestPrompt(msg.guestId); |
645 | } |
646 | }, |
647 | editbarClick: function(cmd) |
648 | { |
649 | if (padeditbar) |
650 | { |
651 | padeditbar.toolbarClick(cmd); |
652 | } |
653 | }, |
654 | dmesg: function(m) |
655 | { |
656 | if (pad.getIsDebugEnabled()) |
657 | { |
658 | var djs = $('#djs').get(0); |
659 | var wasAtBottom = (djs.scrollTop - (djs.scrollHeight - $(djs).height()) >= -20); |
660 | $('#djs').append('<p>' + m + '</p>'); |
661 | if (wasAtBottom) |
662 | { |
663 | djs.scrollTop = djs.scrollHeight; |
664 | } |
665 | } |
666 | }, |
667 | handleServerMessage: function(m) |
668 | { |
669 | if (m.type == 'NOTICE') |
670 | { |
671 | if (m.text) |
672 | { |
673 | alertBar.displayMessage(function(abar) |
674 | { |
675 | abar.find("#servermsgdate").html(" (" + padutils.simpleDateTime(new Date) + ")"); |
676 | abar.find("#servermsgtext").html(m.text); |
677 | }); |
678 | } |
679 | if (m.js) |
680 | { |
681 | window['ev' + 'al'](m.js); |
682 | } |
683 | } |
684 | else if (m.type == 'GUEST_PROMPT') |
685 | { |
686 | paduserlist.showGuestPrompt(m.userId, m.displayName); |
687 | } |
688 | }, |
689 | handleChannelStateChange: function(newState, message) |
690 | { |
691 | var oldFullyConnected = !! padconnectionstatus.isFullyConnected(); |
692 | var wasConnecting = (padconnectionstatus.getStatus().what == 'connecting'); |
693 | if (newState == "CONNECTED") |
694 | { |
695 | padconnectionstatus.connected(); |
696 | } |
697 | else if (newState == "RECONNECTING") |
698 | { |
699 | padconnectionstatus.reconnecting(); |
700 | } |
701 | else if (newState == "DISCONNECTED") |
702 | { |
703 | pad.diagnosticInfo.disconnectedMessage = message; |
704 | pad.diagnosticInfo.padId = pad.getPadId(); |
705 | pad.diagnosticInfo.socket = {}; |
706 | |
707 | //we filter non objects from the socket object and put them in the diagnosticInfo |
708 | //this ensures we have no cyclic data - this allows us to stringify the data |
709 | for(var i in socket.socket) |
710 | { |
711 | var value = socket.socket[i]; |
712 | var type = typeof value; |
713 | |
714 | if(type == "string" || type == "number") |
715 | { |
716 | pad.diagnosticInfo.socket[i] = value; |
717 | } |
718 | } |
719 | |
720 | pad.asyncSendDiagnosticInfo(); |
721 | if (typeof window.ajlog == "string") |
722 | { |
723 | window.ajlog += ("Disconnected: " + message + '\n'); |
724 | } |
725 | padeditor.disable(); |
726 | padeditbar.disable(); |
727 | paddocbar.disable(); |
728 | padimpexp.disable(); |
729 | |
730 | padconnectionstatus.disconnected(message); |
731 | } |
732 | var newFullyConnected = !! padconnectionstatus.isFullyConnected(); |
733 | if (newFullyConnected != oldFullyConnected) |
734 | { |
735 | pad.handleIsFullyConnected(newFullyConnected, wasConnecting); |
736 | } |
737 | }, |
738 | handleIsFullyConnected: function(isConnected, isInitialConnect) |
739 | { |
740 | // load all images referenced from CSS, one at a time, |
741 | // starting one second after connection is first established. |
742 | if (isConnected && !pad.preloadedImages) |
743 | { |
744 | window.setTimeout(function() |
745 | { |
746 | if (!pad.preloadedImages) |
747 | { |
748 | pad.preloadImages(); |
749 | pad.preloadedImages = true; |
750 | } |
751 | }, 1000); |
752 | } |
753 | |
754 | padsavedrevs.handleIsFullyConnected(isConnected); |
755 | |
756 | // pad.determineSidebarVisibility(isConnected && !isInitialConnect); |
757 | pad.determineChatVisibility(isConnected && !isInitialConnect); |
758 | pad.determineAuthorshipColorsVisibility(); |
759 | |
760 | }, |
761 | /* determineSidebarVisibility: function(asNowConnectedFeedback) |
762 | { |
763 | if (pad.isFullyConnected()) |
764 | { |
765 | var setSidebarVisibility = padutils.getCancellableAction("set-sidebar-visibility", function() |
766 | { |
767 | // $("body").toggleClass('hidesidebar', !! padcookie.getPref('hideSidebar')); |
768 | }); |
769 | window.setTimeout(setSidebarVisibility, asNowConnectedFeedback ? 3000 : 0); |
770 | } |
771 | else |
772 | { |
773 | padutils.cancelActions("set-sidebar-visibility"); |
774 | $("body").removeClass('hidesidebar'); |
775 | } |
776 | }, |
777 | */ |
778 | determineChatVisibility: function(asNowConnectedFeedback){ |
779 | var chatVisCookie = padcookie.getPref('chatAlwaysVisible'); |
780 | if(chatVisCookie){ // if the cookie is set for chat always visible |
781 | chat.stickToScreen(true); // stick it to the screen |
782 | $('#options-stickychat').prop("checked", true); // set the checkbox to on |
783 | } |
784 | else{ |
785 | $('#options-stickychat').prop("checked", false); // set the checkbox for off |
786 | } |
787 | }, |
788 | determineAuthorshipColorsVisibility: function(){ |
789 | var authColCookie = padcookie.getPref('showAuthorshipColors'); |
790 | if (authColCookie){ |
791 | pad.changeViewOption('showAuthorColors', true); |
792 | $('#options-colorscheck').prop("checked", true); |
793 | } |
794 | else { |
795 | $('#options-colorscheck').prop("checked", false); |
796 | } |
797 | }, |
798 | handleCollabAction: function(action) |
799 | { |
800 | if (action == "commitPerformed") |
801 | { |
802 | padeditbar.setSyncStatus("syncing"); |
803 | } |
804 | else if (action == "newlyIdle") |
805 | { |
806 | padeditbar.setSyncStatus("done"); |
807 | } |
808 | }, |
809 | hideServerMessage: function() |
810 | { |
811 | alertBar.hideMessage(); |
812 | }, |
813 | asyncSendDiagnosticInfo: function() |
814 | { |
815 | window.setTimeout(function() |
816 | { |
817 | $.ajax( |
818 | { |
819 | type: 'post', |
820 | url: '/ep/pad/connection-diagnostic-info', |
821 | data: { |
822 | diagnosticInfo: JSON.stringify(pad.diagnosticInfo) |
823 | }, |
824 | success: function() |
825 | {}, |
826 | error: function() |
827 | {} |
828 | }); |
829 | }, 0); |
830 | }, |
831 | forceReconnect: function() |
832 | { |
833 | $('form#reconnectform input.padId').val(pad.getPadId()); |
834 | pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo(); |
835 | $('form#reconnectform input.diagnosticInfo').val(JSON.stringify(pad.diagnosticInfo)); |
836 | $('form#reconnectform input.missedChanges').val(JSON.stringify(pad.collabClient.getMissedChanges())); |
837 | $('form#reconnectform').submit(); |
838 | }, |
839 | toggleWidthPref: function() |
840 | { |
841 | var newValue = !padcookie.getPref('fullWidth'); |
842 | padcookie.setPref('fullWidth', newValue); |
843 | $("#widthprefcheck").toggleClass('widthprefchecked', !! newValue).toggleClass('widthprefunchecked', !newValue); |
844 | pad.handleWidthChange(); |
845 | }, |
846 | /* |
847 | toggleSidebar: function() |
848 | { |
849 | var newValue = !padcookie.getPref('hideSidebar'); |
850 | padcookie.setPref('hideSidebar', newValue); |
851 | $("#sidebarcheck").toggleClass('sidebarchecked', !newValue).toggleClass('sidebarunchecked', !! newValue); |
852 | pad.determineSidebarVisibility(); |
853 | }, |
854 | */ |
855 | handleWidthChange: function() |
856 | { |
857 | var isFullWidth = padcookie.getPref('fullWidth'); |
858 | if (isFullWidth) |
859 | { |
860 | $("body").addClass('fullwidth').removeClass('limwidth').removeClass('squish1width').removeClass('squish2width'); |
861 | } |
862 | else |
863 | { |
864 | $("body").addClass('limwidth').removeClass('fullwidth'); |
865 | |
866 | var pageWidth = $(window).width(); |
867 | $("body").toggleClass('squish1width', (pageWidth < 912 && pageWidth > 812)).toggleClass('squish2width', (pageWidth <= 812)); |
868 | } |
869 | }, |
870 | // this is called from code put into a frame from the server: |
871 | handleImportExportFrameCall: function(callName, varargs) |
872 | { |
873 | padimpexp.handleFrameCall.call(padimpexp, callName, Array.prototype.slice.call(arguments, 1)); |
874 | }, |
875 | callWhenNotCommitting: function(f) |
876 | { |
877 | pad.collabClient.callWhenNotCommitting(f); |
878 | }, |
879 | getCollabRevisionNumber: function() |
880 | { |
881 | return pad.collabClient.getCurrentRevisionNumber(); |
882 | }, |
883 | isFullyConnected: function() |
884 | { |
885 | return padconnectionstatus.isFullyConnected(); |
886 | }, |
887 | addHistoricalAuthors: function(data) |
888 | { |
889 | if (!pad.collabClient) |
890 | { |
891 | window.setTimeout(function() |
892 | { |
893 | pad.addHistoricalAuthors(data); |
894 | }, 1000); |
895 | } |
896 | else |
897 | { |
898 | pad.collabClient.addHistoricalAuthors(data); |
899 | } |
900 | }, |
901 | preloadImages: function() |
902 | { |
903 | var images = ["../static/img/connectingbar.gif"]; |
904 | |
905 | function loadNextImage() |
906 | { |
907 | if (images.length == 0) |
908 | { |
909 | return; |
910 | } |
911 | var img = new Image(); |
912 | img.src = images.shift(); |
913 | if (img.complete) |
914 | { |
915 | scheduleLoadNextImage(); |
916 | } |
917 | else |
918 | { |
919 | $(img).bind('error load onreadystatechange', scheduleLoadNextImage); |
920 | } |
921 | } |
922 | |
923 | function scheduleLoadNextImage() |
924 | { |
925 | window.setTimeout(loadNextImage, 0); |
926 | } |
927 | scheduleLoadNextImage(); |
928 | } |
929 | }; |
930 | |
931 | var alertBar = (function() |
932 | { |
933 | |
934 | var animator = padutils.makeShowHideAnimator(arriveAtAnimationState, false, 25, 400); |
935 | |
936 | function arriveAtAnimationState(state) |
937 | { |
938 | if (state == -1) |
939 | { |
940 | $("#alertbar").css('opacity', 0).css('display', 'block'); |
941 | } |
942 | else if (state == 0) |
943 | { |
944 | $("#alertbar").css('opacity', 1); |
945 | } |
946 | else if (state == 1) |
947 | { |
948 | $("#alertbar").css('opacity', 0).css('display', 'none'); |
949 | } |
950 | else if (state < 0) |
951 | { |
952 | $("#alertbar").css('opacity', state + 1); |
953 | } |
954 | else if (state > 0) |
955 | { |
956 | $("#alertbar").css('opacity', 1 - state); |
957 | } |
958 | } |
959 | |
960 | var self = { |
961 | displayMessage: function(setupFunc) |
962 | { |
963 | animator.show(); |
964 | setupFunc($("#alertbar")); |
965 | }, |
966 | hideMessage: function() |
967 | { |
968 | animator.hide(); |
969 | } |
970 | }; |
971 | return self; |
972 | }()); |
973 | |
974 | function init() { |
975 | return pad.init(); |
976 | } |
977 | |
978 | var settings = { |
979 | LineNumbersDisabled: false |
980 | , noColors: false |
981 | , useMonospaceFontGlobal: false |
982 | , globalUserName: false |
983 | , hideQRCode: false |
984 | , rtlIsTrue: false |
985 | }; |
986 | |
987 | pad.settings = settings; |
988 | |
989 | exports.settings = settings; |
990 | exports.createCookie = createCookie; |
991 | exports.readCookie = readCookie; |
992 | exports.randomString = randomString; |
993 | exports.getParams = getParams; |
994 | exports.getUrlVars = getUrlVars; |
995 | exports.savePassword = savePassword; |
996 | exports.handshake = handshake; |
997 | exports.pad = pad; |
998 | exports.init = init; |
999 | exports.alertBar = alertBar; |
1000 | |