From 6649b1f0a5db6160d197a13ca79cfd67fbb02d77 Mon Sep 17 00:00:00 2001 From: svncommit <devs@roundcube.net> Date: Sat, 23 Sep 2006 19:37:29 -0400 Subject: [PATCH] added TinyMCE spellchecker plugin, configured to use GoogleSpell --- program/js/app.js | 312 ++++++++++++++++++++++++++++++++++----------------- 1 files changed, 207 insertions(+), 105 deletions(-) diff --git a/program/js/app.js b/program/js/app.js index 3c9efb8..eedcd13 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -18,7 +18,6 @@ var CONTROL_KEY = 1; var SHIFT_KEY = 2; var CONTROL_SHIFT_KEY = 3; -var DRAFT_AUTOSAVE = 5; // Minutes var rcube_webmail_client; @@ -40,10 +39,8 @@ // webmail client settings this.dblclick_time = 600; this.message_time = 5000; - this.request_timeout = 180000; - this._interval = 60000; + this.mbox_expression = new RegExp('[^0-9a-z\-_]', 'gi'); - this.env.blank_img = 'skins/default/images/blank.gif'; // mimetypes supported by the browser (default settings) this.mimetypes = new Array('text/plain', 'text/html', 'text/xml', @@ -51,12 +48,16 @@ 'application/x-javascript', 'application/pdf', 'application/x-shockwave-flash'); + // default environment vars + this.env.keep_alive = 60; // seconds + this.env.request_timeout = 180; // seconds + this.env.draft_autosave = 0; // seconds + // set environment variable this.set_env = function(name, value) { - //if (!this.busy) - this.env[name] = value; + this.env[name] = value; }; @@ -141,17 +142,20 @@ if (this.gui_objects.remoteobjectsmsg) this.gui_objects.remoteobjectsmsg.style.display = 'block'; this.enable_command('load-images', true); - } + } if (this.env.action=='compose') { this.enable_command('add-attachment', 'send-attachment', 'remove-attachment', 'send', true); if (this.env.spellcheck) - this.enable_command('spellcheck', true); + { + this.env.spellcheck.spelling_state_observer = function(s){ rcube_webmail_client.set_spellcheck_state(s); }; + this.set_spellcheck_state('ready'); + } if (this.env.drafts_mailbox) this.enable_command('savedraft', true); } - + if (this.env.messagecount) this.enable_command('select-all', 'select-none', 'sort', 'expunge', true); @@ -170,7 +174,7 @@ // show printing dialog if (this.env.action=='print') window.print(); - + // get unread count for each mailbox if (this.gui_objects.mailboxlist) this.http_request('getunread', ''); @@ -246,24 +250,28 @@ // load body click event document.onmousedown = function(){ return rcube_webmail_client.reset_click(); }; document.onkeydown = function(e){ return rcube_webmail_client.key_pressed(e, msg_list_frame); }; - - // set default keep alive interval - if (!this.keep_alive_interval) - this.keep_alive_interval = this._interval; // flag object as complete this.loaded = true; - + // show message if (this.pending_message) this.display_message(this.pending_message[0], this.pending_message[1]); - - // start interval for keep-alive/recent_check signal - if (this.keep_alive_interval && this.task=='mail' && this.gui_objects.messagelist) - this._int = setInterval(this.ref+'.check_for_recent()', this.keep_alive_interval); - else if (this.task!='login') - this._int = setInterval(this.ref+'.send_keep_alive()', this.keep_alive_interval); + + // start keep-alive interval + this.start_keepalive(); }; + + + // start interval for keep-alive/recent_check signal + this.start_keepalive = function() + { + if (this.env.keep_alive && this.task=='mail' && this.gui_objects.messagelist) + this._int = setInterval(this.ref+'.check_for_recent()', this.env.keep_alive * 1000); + else if (this.env.keep_alive && this.task!='login') + this._int = setInterval(this.ref+'.send_keep_alive()', this.env.keep_alive * 1000); + } + // reset last clicked if user clicks on anything other than the message table this.reset_click = function() @@ -429,7 +437,7 @@ var input_replyto = rcube_find_object('_replyto'); var input_subject = rcube_find_object('_subject'); var input_message = rcube_find_object('_message'); - + // init live search events if (input_to) this.init_address_input_events(input_to); @@ -448,7 +456,7 @@ input_subject.focus(); else if (input_message) this.set_caret2start(input_message); // input_message.focus(); - + // get summary of all field values this.cmp_hash = this.compose_field_hash(); @@ -706,7 +714,7 @@ if (this.env.mailbox==this.env.drafts_mailbox) { this.set_busy(true); - location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox); + location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); } else this.show_message(uid); @@ -873,8 +881,9 @@ if (this.task=='mail' && this.env.mailbox==this.env.drafts_mailbox) { - var uid = this.get_single_uid(); - url += '&_draft_uid='+uid+'&_mbox='+escape(this.env.mailbox); + var uid; + if (uid = this.get_single_uid()) + url += '&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); } // modify url if we're in addressbook else if (this.task=='addressbook') @@ -924,8 +933,11 @@ break; case 'spellcheck': - if (this.env.spellcheck && this.env.spellcheck.spellCheck) + if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) + { this.env.spellcheck.spellCheck(this.env.spellcheck.check_link); + this.set_spellcheck_state('checking'); + } break; case 'savedraft': @@ -936,7 +948,8 @@ break; // if saving Drafts is disabled in main.inc.php - if (!this.env.drafts_mailbox) + // or if compose form did not change + if (!this.env.drafts_mailbox || this.cmp_hash == this.compose_field_hash()) break; this.set_busy(true, 'savingmessage'); @@ -951,6 +964,9 @@ if (!this.check_compose_input()) break; + + // Reset the auto-save timer + self.clearTimeout(this.save_timer); // all checks passed, send message this.set_busy(true, 'sendingmessage'); @@ -958,6 +974,9 @@ form.target = "savetarget"; form._draft.value = ''; form.submit(); + + // clear timeout (sending could take longer) + clearTimeout(this.request_timer); break; case 'add-attachment': @@ -980,7 +999,7 @@ if (uid = this.get_single_uid()) { this.set_busy(true); - location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : ''); + location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : ''); } break; @@ -989,7 +1008,7 @@ if (uid = this.get_single_uid()) { this.set_busy(true); - location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+escape(this.env.mailbox); + location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); } break; @@ -997,7 +1016,7 @@ var uid; if (uid = this.get_single_uid()) { - this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : '')); + this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : '')); if (this.printwin) setTimeout(this.ref+'.printwin.focus()', 20); } @@ -1007,7 +1026,7 @@ var uid; if (uid = this.get_single_uid()) { - this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+escape(this.env.mailbox)); + this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox)); if (this.sourcewin) setTimeout(this.ref+'.sourcewin.focus()', 20); } @@ -1022,7 +1041,7 @@ if (!props && this.gui_objects.qsearchbox) props = this.gui_objects.qsearchbox.value; if (props) - this.qsearch(escape(props), this.env.mailbox); + this.qsearch(urlencode(props), this.env.mailbox); break; // reset quicksearch @@ -1130,8 +1149,8 @@ clearTimeout(this.request_timer); // set timer for requests - if (a && this.request_timeout) - this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.request_timeout); + if (a && this.env.request_timeout) + this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.env.request_timeout * 1000); }; @@ -1249,7 +1268,7 @@ if (this.env.mailbox==this.env.drafts_mailbox) { this.set_busy(true); - location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+escape(this.env.mailbox); + location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+urlencode(this.env.mailbox); } else { @@ -1509,7 +1528,7 @@ if (id) { this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+escape(this.env.mailbox)+add_url; + target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url; } }; @@ -1581,7 +1600,7 @@ if (mbox) { this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+'&_mbox='+escape(mbox)+(page ? '&_page='+page : '')+add_url; + target.location.href = this.env.comm_path+'&_mbox='+urlencode(mbox)+(page ? '&_page='+page : '')+add_url; } }; @@ -1593,7 +1612,7 @@ this.clear_message_list(); // send request to server - var url = '_mbox='+escape(mbox)+(page ? '&_page='+page : ''); + var url = '_mbox='+urlencode(mbox)+(page ? '&_page='+page : ''); this.set_busy(true, 'loading'); this.http_request('list', url+add_url, true); }; @@ -1645,7 +1664,7 @@ } // send request to server - var url = '_mbox='+escape(mbox); + var url = '_mbox='+urlencode(mbox); this.http_request('expunge', url+add_url, lock); }; @@ -1667,7 +1686,7 @@ } // send request to server - var url = '_mbox='+escape(mbox); + var url = '_mbox='+urlencode(mbox); this.http_request('purge', url+add_url, lock); return true; }; @@ -1724,7 +1743,7 @@ this.set_busy(true, 'movingmessage'); } // send request to server - this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_target_mbox='+escape(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock); + this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock); }; this.permanently_remove_messages = function() { @@ -1755,7 +1774,7 @@ if (new_row) this.select_row(new_row.uid,false,false); // send request to server - this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : '')); + this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : '')); } @@ -2000,7 +2019,7 @@ } // check for empty body - if (input_message.value=='') + if ((input_message.value=='')&&(tinyMCE.getContent()=='')) { if (!confirm(this.get_label('nobodywarning'))) { @@ -2013,9 +2032,17 @@ }; + this.set_spellcheck_state = function(s) + { + this.spellcheck_ready = (s=='check_spelling' || s=='ready'); + this.enable_command('spellcheck', this.spellcheck_ready); + }; + + this.auto_save_start = function() { - this.save_timer = self.setTimeout('rcmail.command("savedraft","",this)', DRAFT_AUTOSAVE * 60000); + if (this.env.draft_autosave) + this.save_timer = self.setTimeout(this.ref+'.command("savedraft")', this.env.draft_autosave * 1000); }; @@ -2052,35 +2079,67 @@ var id = obj.options[obj.selectedIndex].value; var input_message = rcube_find_object('_message'); var message = input_message ? input_message.value : ''; + var is_html = (rcube_find_object('_is_html').value == '1'); var sig, p; if (!this.env.identity) this.env.identity = id - - // remove the 'old' signature - if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity]) + + if (!is_html) { - sig = this.env.signatures[this.env.identity]; - if (sig.indexOf('--')!=0) - sig = '--\n'+sig; - - p = message.lastIndexOf(sig); - if (p>=0) - message = message.substring(0, p-1) + message.substring(p+sig.length, message.length); + // remove the 'old' signature + if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity]) + { + sig = this.env.signatures[this.env.identity]['text']; + if (sig.indexOf('--')!=0) + sig = '--\n'+sig; + + p = message.lastIndexOf(sig); + if (p>=0) + message = message.substring(0, p-1) + message.substring(p+sig.length, message.length); + } + + // add the new signature string + if (this.env.signatures && this.env.signatures[id]) + { + sig = this.env.signatures[id]['text']; + if (sig.indexOf('--')!=0) + sig = '--\n'+sig; + message += '\n'+sig; + } } - - // add the new signature string - if (this.env.signatures && this.env.signatures[id]) + else { - sig = this.env.signatures[id]; - if (sig.indexOf('--')!=0) - sig = '--\n'+sig; - message += '\n'+sig; + var eid = tinyMCE.getEditorId('_message'); + // editor is a TinyMCE_Control object + var editor = tinyMCE.getInstanceById(eid); + var msgDoc = editor.getDoc(); + var msgBody = msgDoc.body; + + if (this.env.signatures && this.env.signatures[id]) + { + // Append the signature as a span within the body + var sigElem = msgDoc.getElementById("_rc_sig"); + if (!sigElem) + { + sigElem = msgDoc.createElement("span"); + sigElem.setAttribute("id", "_rc_sig"); + msgBody.appendChild(sigElem); + } + if (this.env.signatures[id]['is_html']) + { + sigElem.innerHTML = this.env.signatures[id]['text']; + } + else + { + sigElem.innerHTML = '<pre>' + this.env.signatures[id]['text'] + '</pre>'; + } + } } if (input_message) input_message.value = message; - + this.env.identity = id; return true; }; @@ -2168,7 +2227,7 @@ // add file name to attachment list // called from upload page - this.add2attachment_list = function(name,content) + this.add2attachment_list = function(name, content) { if (!this.gui_objects.attachmentlist) return false; @@ -2188,13 +2247,13 @@ var list = this.gui_objects.attachmentlist.getElementsByTagName("li"); for (i=0;i<list.length;i++) if (list[i].id == name) - this.gui_objects.attachmentlist.removeChild(list[i]); + this.gui_objects.attachmentlist.removeChild(list[i]); }; this.remove_attachment = function(name) { if (name) - this.http_request('remove-attachment', '_filename='+escape(name)); + this.http_request('remove-attachment', '_file='+urlencode(name)); return true; }; @@ -2707,7 +2766,7 @@ name = form.elements['_folder_name'].value; if (name) - this.http_request('create-folder', '_name='+escape(name), true); + this.http_request('create-folder', '_name='+urlencode(name), true); else if (form.elements['_folder_name']) form.elements['_folder_name'].focus(); }; @@ -2730,7 +2789,7 @@ } if (oldname && newname) - this.http_request('rename-folder', '_folder_oldname='+escape(oldname)+'&_folder_newname='+escape(newname)); + this.http_request('rename-folder', '_folder_oldname='+urlencode(oldname)+'&_folder_newname='+urlencode(newname)); }; @@ -2752,7 +2811,7 @@ if (id && (row = document.getElementById(id))) { this.name_input = document.createElement('INPUT'); - this.name_input.value = this.env.subscriptionrows[id]; + this.name_input.value = this.env.subscriptionrows[id][1]; this.name_input.style.width = '100%'; this.name_input.onkeypress = function(e){ rcmail.name_input_keypress(e); }; @@ -2770,8 +2829,8 @@ this.reset_folder_rename = function() { var cell = this.name_input ? this.name_input.parentNode : null; - if (cell && this.edit_folder) - cell.innerHTML = this.env.subscriptionrows[this.edit_folder]; + if (cell && this.edit_folder && this.env.subscriptionrows[this.edit_folder]) + cell.innerHTML = this.env.subscriptionrows[this.edit_folder][1]; this.edit_folder = null; }; @@ -2787,7 +2846,7 @@ { var newname = this.name_input ? this.name_input.value : null; if (this.edit_folder && newname) - this.http_request('rename-folder', '_folder_oldname='+escape(this.env.subscriptionrows[this.edit_folder])+'&_folder_newname='+escape(newname)); + this.http_request('rename-folder', '_folder_oldname='+urlencode(this.env.subscriptionrows[this.edit_folder][0])+'&_folder_newname='+urlencode(newname)); } // escape else if (key==27) @@ -2802,12 +2861,12 @@ this.reset_folder_rename(); if (folder) - this.http_request('delete-folder', '_mboxes='+escape(folder)); + this.http_request('delete-folder', '_mboxes='+urlencode(folder)); }; // add a new folder to the subscription list by cloning a folder row - this.add_folder_row = function(name, replace) + this.add_folder_row = function(name, display_name, replace) { name = name.replace('\\',""); if (!this.gui_objects.subscriptionlist) @@ -2838,10 +2897,10 @@ } // add to folder/row-ID map - this.env.subscriptionrows[row.id] = name; + this.env.subscriptionrows[row.id] = [name, display_name]; // set folder name - row.cells[0].innerHTML = name; + row.cells[0].innerHTML = display_name; if (row.cells[1] && row.cells[1].firstChild.tagName=='INPUT') { row.cells[1].firstChild.value = name; @@ -2866,13 +2925,13 @@ // replace an existing table row with a new folder line - this.replace_folder_row = function(newfolder, oldfolder) + this.replace_folder_row = function(oldfolder, newfolder, display_name) { var id = this.get_folder_row_id(oldfolder); var row = document.getElementById(id); // replace an existing table row (if found) - this.add_folder_row(newfolder, row); + this.add_folder_row(newfolder, display_name, row); this.env.subscriptionrows[id] = null; // rename folder in rename-folder dropdown @@ -2883,7 +2942,7 @@ { if (elm.options[i].value == oldfolder) { - elm.options[i].text = newfolder; + elm.options[i].text = display_name; elm.options[i].value = newfolder; break; } @@ -2928,7 +2987,7 @@ if ((form = this.gui_objects.editform) && form.elements['_unsubscribed']) this.change_subscription('_unsubscribed', '_subscribed', 'subscribe'); else if (folder) - this.http_request('subscribe', '_mboxes='+escape(folder)); + this.http_request('subscribe', '_mboxes='+urlencode(folder)); }; @@ -2938,7 +2997,7 @@ if ((form = this.gui_objects.editform) && form.elements['_subscribed']) this.change_subscription('_subscribed', '_unsubscribed', 'unsubscribe'); else if (folder) - this.http_request('unsubscribe', '_mboxes='+escape(folder)); + this.http_request('unsubscribe', '_mboxes='+urlencode(folder)); }; @@ -2972,7 +3031,7 @@ list_to[index] = new Option(a_folders[n]); } - this.http_request(action, '_mboxes='+escape(a_folders.join(','))); + this.http_request(action, '_mboxes='+urlencode(a_folders.join(','))); } } @@ -2982,7 +3041,7 @@ this.get_folder_row_id = function(folder) { for (var id in this.env.subscriptionrows) - if (this.env.subscriptionrows[id]==folder) + if (this.env.subscriptionrows[id] && this.env.subscriptionrows[id][0] == folder) break; return id; @@ -3404,6 +3463,18 @@ }; + this.toggle_editor = function(checkbox, textElementName) + { + var ischecked = checkbox.checked; + if (ischecked) + { + tinyMCE.execCommand('mceAddControl', true, textElementName); + } + else + { + tinyMCE.execCommand('mceRemoveControl', true, textElementName); + } + } /********************************************************/ /********* drag & drop methods *********/ @@ -3507,8 +3578,8 @@ // send request if (request_obj) { - // prompt('request', this.env.comm_path+'&_action='+escape(action)+'&'+querystring); - console('HTTP request: '+this.env.comm_path+'&_action='+escape(action)+'&'+querystring); + // prompt('request', this.env.comm_path+'&_action='+urlencode(action)+'&'+querystring); + console('HTTP request: '+this.env.comm_path+'&_action='+action+'&'+querystring); if (lock) this.set_busy(true); @@ -3517,7 +3588,7 @@ request_obj.__action = action; request_obj.onerror = function(o){ rcube_webmail_client.http_error(o); }; request_obj.oncomplete = function(o){ rcube_webmail_client.http_response(o); }; - request_obj.GET(this.env.comm_path+'&_action='+escape(action)+'&'+querystring); + request_obj.GET(this.env.comm_path+'&_action='+action+'&'+querystring); } }; @@ -3555,7 +3626,7 @@ case 'expunge': this.enable_command('select-all', 'select-none', 'expunge', this.env.messagecount ? true : false); - break; + break; } request_obj.reset(); @@ -3565,7 +3636,7 @@ // handle HTTP request errors this.http_error = function(request_obj) { - alert('Error sending request: '+request_obj.url); + //alert('Error sending request: '+request_obj.url); if (request_obj.__lock) this.set_busy(false); @@ -3586,6 +3657,12 @@ // send periodic request to check for recent messages this.check_for_recent = function() { + if (this.busy) + { + this.send_keep_alive(); + return; + } + this.set_busy(true, 'checkingmail'); var d = new Date(); this.http_request('check-recent', '_t='+d.getTime()); @@ -3787,7 +3864,7 @@ } } - // sedn GET request + // send GET request this.GET = function(url) { this.build(); @@ -3808,9 +3885,28 @@ }; - this.POST = function(url, a_param) + this.POST = function(url, body, contentType) { - // not implemented yet + // default value for contentType if not provided + contentType = typeof(contentType) != 'undefined' ? + contentType : 'application/x-www-form-urlencoded'; + + this.build(); + + if (!this.xmlhttp) + { + this.onerror(this); + return false; + } + + var ref=this; + this.url = url; + this.busy = true; + + this.xmlhttp.onreadystatechange = function() { ref.xmlhttp_onreadystatechange(); }; + this.xmlhttp.open('POST', url, true); + this.xmlhttp.setRequestHeader('Content-Type', contentType); + this.xmlhttp.send(body); }; @@ -3828,14 +3924,21 @@ else if(this.xmlhttp.readyState == 4) { - if(this.xmlhttp.status == 0) - this.onabort(this); - else if(this.xmlhttp.status == 200) - this.oncomplete(this); - else + try { + if (this.xmlhttp.status == 0) + this.onabort(this); + else if(this.xmlhttp.status == 200) + this.oncomplete(this); + else + this.onerror(this); + + this.busy = false; + } + catch(err) + { this.onerror(this); - - this.busy = false; + this.busy = false; + } } } @@ -3860,6 +3963,12 @@ } // end class rcube_http_request +// helper function to call the init method with a delay +function call_init(o) + { + if (window[o] && window[o].init) + setTimeout(o+'.init()', 200); + } function console(str) { @@ -3867,10 +3976,3 @@ document.debugform.console.value += str+'\n--------------------------------------\n'; } - -// set onload handler -window.onload = function(e) - { - if (window.rcube_webmail_client) - rcube_webmail_client.init(); - }; -- Gitblit v1.9.1