Changeset 0213f8d in github
- Timestamp:
- Jul 25, 2011 6:49:39 AM (22 months ago)
- Branches:
- master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
- Children:
- 71e8cc3
- Parents:
- 18371736
- Files:
-
- 6 edited
-
CHANGELOG (modified) (1 diff)
-
config/main.inc.php.dist (modified) (1 diff)
-
program/include/main.inc (modified) (1 diff)
-
program/js/app.js (modified) (15 diffs)
-
program/steps/mail/autocomplete.inc (modified) (3 diffs)
-
program/steps/mail/compose.inc (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG
r18371736 r0213f8d 2 2 =========================== 3 3 4 - Added optional "multithreading" autocomplete feature 4 5 - Plugin API: Added 'config_get' hook 5 6 - Fixed new_user_identity plugin to work with updated rcube_ldap class (#1487994) -
config/main.inc.php.dist
rca8a178 r0213f8d 572 572 $rcmail_config['autocomplete_min_length'] = 1; 573 573 574 // Number of parallel autocomplete requests. 575 // If there's more than one address book, n parallel (async) requests will be created, 576 // where each request will search in one address book. By default (0), all address 577 // books are searched in one request. 578 $rcmail_config['autocomplete_threads'] = 0; 579 580 // Max. numer of entries in autocomplete popup. Default: 15. 581 $rcmail_config['autocomplete_max'] = 15; 582 574 583 // show address fields in this order 575 584 // available placeholders: {street}, {locality}, {zipcode}, {country}, {region} -
program/include/main.inc
rd8aff9a r0213f8d 2123 2123 } 2124 2124 } 2125 2126 /** 2127 * Initializes client-side autocompletion 2128 */ 2129 function rcube_autocomplete_init() 2130 { 2131 global $RCMAIL; 2132 static $init; 2133 2134 if ($init) 2135 return; 2136 2137 $init = 1; 2138 2139 if (($threads = (int)$RCMAIL->config->get('autocomplete_threads')) > 0) { 2140 $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); 2141 if (count($book_types) > 1) { 2142 $RCMAIL->output->set_env('autocomplete_threads', $threads); 2143 $RCMAIL->output->set_env('autocomplete_sources', $book_types); 2144 } 2145 } 2146 2147 $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15)); 2148 $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length')); 2149 $RCMAIL->output->add_label('autocompletechars'); 2150 } -
program/js/app.js
r1b3ce75 r0213f8d 2872 2872 input_message = $("[name='_message']").get(0), 2873 2873 html_mode = $("input[name='_is_html']").val() == '1', 2874 ac_fields = ['cc', 'bcc', 'replyto', 'followupto']; 2874 ac_fields = ['cc', 'bcc', 'replyto', 'followupto'], 2875 ac_props; 2876 2877 // configure parallel autocompletion 2878 if (this.env.autocomplete_threads > 0) { 2879 ac_props = { 2880 threads: this.env.autocomplete_threads, 2881 sources: this.env.autocomplete_sources, 2882 }; 2883 } 2875 2884 2876 2885 // init live search events 2877 this.init_address_input_events(input_to );2886 this.init_address_input_events(input_to, ac_props); 2878 2887 for (var i in ac_fields) { 2879 this.init_address_input_events($("[name='_"+ac_fields[i]+"']") );2888 this.init_address_input_events($("[name='_"+ac_fields[i]+"']"), ac_props); 2880 2889 } 2881 2890 … … 2905 2914 }; 2906 2915 2907 this.init_address_input_events = function(obj, action)2908 { 2909 obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, action); })2916 this.init_address_input_events = function(obj, props) 2917 { 2918 obj[bw.ie || bw.safari || bw.chrome ? 'keydown' : 'keypress'](function(e) { return ref.ksearch_keydown(e, this, props); }) 2910 2919 .attr('autocomplete', 'off'); 2911 2920 }; … … 3442 3451 3443 3452 // handler for keyboard events on address-fields 3444 this.ksearch_keydown = function(e, obj, action)3453 this.ksearch_keydown = function(e, obj, props) 3445 3454 { 3446 3455 if (this.ksearch_timer) … … 3472 3481 break; 3473 3482 3474 case 13: // enter3475 if (this.ksearch_selected === null || !this.ksearch_ input || !this.ksearch_value)3483 case 13: // enter 3484 if (this.ksearch_selected === null || !this.ksearch_value) 3476 3485 break; 3477 3486 … … 3493 3502 3494 3503 // start timer 3495 this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results( action); }, 200);3504 this.ksearch_timer = window.setTimeout(function(){ ref.ksearch_get_results(props); }, 200); 3496 3505 this.ksearch_input = obj; 3497 3506 … … 3523 3532 trigger = false, 3524 3533 insert = '', 3525 3526 3534 // replace search string with full address 3527 3535 pre = inp_value.substring(0, p), 3528 3536 end = inp_value.substring(p+this.ksearch_value.length, inp_value.length); 3537 3538 this.ksearch_destroy(); 3529 3539 3530 3540 // insert all members of a group … … 3561 3571 3562 3572 // address search processor 3563 this.ksearch_get_results = function( action)3573 this.ksearch_get_results = function(props) 3564 3574 { 3565 3575 var inp_value = this.ksearch_input ? this.ksearch_input.value : null; … … 3606 3616 return; 3607 3617 3608 var lock = this.display_message(this.get_label('searching'), 'loading'); 3609 this.http_post(action ? action : 'mail/autocomplete', '_search='+urlencode(q), lock); 3610 }; 3611 3612 this.ksearch_query_results = function(results, search) 3618 this.ksearch_destroy(); 3619 3620 var i, lock, source, xhr, reqid = new Date().getTime(), 3621 threads = props && props.threads ? props.threads : 1, 3622 sources = props && props.sources ? props.sources : [], 3623 action = props && props.action ? props.action : 'mail/autocomplete'; 3624 3625 this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, locks: [], requests: []}; 3626 3627 for (i=0; i<threads; i++) { 3628 source = this.ksearch_data.sources.shift(); 3629 if (threads > 1 && source === null) 3630 break; 3631 3632 lock = this.display_message(this.get_label('searching'), 'loading'); 3633 xhr = this.http_post(action, '_search='+urlencode(q)+'&_id='+reqid 3634 + (source ? '&_source='+urlencode(source) : ''), lock); 3635 3636 this.ksearch_data.locks.push(lock); 3637 this.ksearch_data.requests.push(xhr); 3638 } 3639 }; 3640 3641 this.ksearch_query_results = function(results, search, reqid) 3613 3642 { 3614 3643 // ignore this outdated search response 3615 if (this.ksearch_ value && search != this.ksearch_value)3644 if (this.ksearch_input && this.ksearch_value && search != this.ksearch_value) 3616 3645 return; 3617 3646 3618 this.env.contacts = results ? results : [];3619 this.ksearch_display_results(this.env.contacts);3620 };3621 3622 this.ksearch_display_results = function (a_results)3623 {3624 3647 // display search results 3625 if (a_results.length && this.ksearch_input && this.ksearch_value) { 3626 var p, ul, li, text, s_val = this.ksearch_value; 3627 3628 // create results pane if not present 3629 if (!this.ksearch_pane) { 3630 ul = $('<ul>'); 3631 this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane').css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); 3632 this.ksearch_pane.__ul = ul[0]; 3633 } 3634 3635 // remove all search results 3636 ul = this.ksearch_pane.__ul; 3648 var p, ul, li, text, init, s_val = this.ksearch_value, 3649 maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15; 3650 3651 // create results pane if not present 3652 if (!this.ksearch_pane) { 3653 ul = $('<ul>'); 3654 this.ksearch_pane = $('<div>').attr('id', 'rcmKSearchpane') 3655 .css({ position:'absolute', 'z-index':30000 }).append(ul).appendTo(document.body); 3656 this.ksearch_pane.__ul = ul[0]; 3657 } 3658 3659 ul = this.ksearch_pane.__ul; 3660 3661 // remove all search results or add to existing list if parallel search 3662 if (reqid && this.ksearch_pane.data('reqid') == reqid) { 3663 maxlen -= ul.childNodes.length; 3664 } 3665 else { 3666 this.ksearch_pane.data('reqid', reqid); 3667 init = 1; 3668 // reset content 3637 3669 ul.innerHTML = ''; 3638 3639 // add each result line to list 3640 for (i=0; i < a_results.length; i++) { 3641 text = typeof a_results[i] === 'object' ? a_results[i].name : a_results[i]; 3670 this.env.contacts = []; 3671 // move the results pane right under the input box 3672 var pos = $(this.ksearch_input).offset(); 3673 this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px', display: 'none'}); 3674 } 3675 3676 // add each result line to list 3677 if (results && results.length) { 3678 for (i=0; i < results.length && maxlen > 0; i++) { 3679 text = typeof results[i] === 'object' ? results[i].name : results[i]; 3642 3680 li = document.createElement('LI'); 3643 3681 li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '<').replace(/>/g, '>').replace(/##([^%]+)%%/g, '<b>$1</b>'); … … 3646 3684 li._rcm_id = i; 3647 3685 ul.appendChild(li); 3648 } 3649 3686 maxlen -= 1; 3687 } 3688 } 3689 3690 if (ul.childNodes.length) { 3691 this.ksearch_pane.show(); 3650 3692 // select the first 3651 $(ul.firstChild).attr('id', 'rcmksearchSelected').addClass('selected'); 3652 this.ksearch_selected = 0; 3653 3654 // move the results pane right under the input box and make it visible 3655 var pos = $(this.ksearch_input).offset(); 3656 this.ksearch_pane.css({ left:pos.left+'px', top:(pos.top + this.ksearch_input.offsetHeight)+'px' }).show(); 3657 } 3658 // hide results pane 3659 else 3660 this.ksearch_hide(); 3693 if (!this.env.contacts.length) { 3694 $('li:first', ul).attr('id', 'rcmksearchSelected').addClass('selected'); 3695 this.ksearch_selected = 0; 3696 } 3697 } 3698 3699 if (results && results.length) 3700 this.env.contacts = this.env.contacts.concat(results); 3701 3702 // run next parallel search 3703 if (maxlen > 0 && this.ksearch_data.id == reqid && this.ksearch_data.sources.length) { 3704 var lock, xhr, props = this.ksearch_data, source = props.sources.shift(); 3705 if (source) { 3706 lock = this.display_message(this.get_label('searching'), 'loading'); 3707 xhr = this.http_post(props.action, '_search='+urlencode(s_val)+'&_id='+reqid 3708 +'&_source='+urlencode(source), lock); 3709 3710 this.ksearch_data.locks.push(lock); 3711 this.ksearch_data.requests.push(xhr); 3712 } 3713 } 3661 3714 }; 3662 3715 … … 3675 3728 clearTimeout(this.ksearch_timer); 3676 3729 3677 this.ksearch_value = '';3678 3730 this.ksearch_input = null; 3679 3731 this.ksearch_hide(); 3680 3732 }; 3681 3733 3682 3683 3734 this.ksearch_hide = function() 3684 3735 { 3685 3736 this.ksearch_selected = null; 3737 this.ksearch_value = ''; 3686 3738 3687 3739 if (this.ksearch_pane) … … 3689 3741 }; 3690 3742 3743 // Aborts pending autocomplete requests 3744 this.ksearch_destroy = function() 3745 { 3746 var i, len, ac = this.ksearch_data; 3747 3748 if (!ac) 3749 return; 3750 3751 for (i=0, len=ac.locks.length; i<len; i++) { 3752 this.hide_message(ac.locks[i]); // hide loading message 3753 ac.requests[i].abort(); // abort ajax request 3754 } 3755 3756 this.ksearch_data = null; 3757 } 3691 3758 3692 3759 /*********************************************************/ … … 4534 4601 var basename = this.env.mailbox.replace(reg, ''), 4535 4602 newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename; 4536 4603 4537 4604 if (newname != this.env.mailbox) { 4538 4605 this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), this.set_busy(true, 'foldermoving')); … … 5456 5523 /********* remote request methods *********/ 5457 5524 /********************************************************/ 5458 5525 5459 5526 // compose a valid url with the given parameters 5460 5527 this.url = function(action, query) … … 5535 5602 // send request 5536 5603 console.log('HTTP GET: ' + url); 5537 $.ajax({ 5604 5605 return $.ajax({ 5538 5606 type: 'GET', url: url, data: { _unlock:(lock?lock:0) }, dataType: 'json', 5539 5607 success: function(data){ ref.http_response(data); }, … … 5566 5634 // send request 5567 5635 console.log('HTTP POST: ' + url); 5568 $.ajax({ 5636 5637 return $.ajax({ 5569 5638 type: 'POST', url: url, data: postdata, dataType: 'json', 5570 5639 success: function(data){ ref.http_response(data); }, -
program/steps/mail/autocomplete.inc
r03eb13f r0213f8d 20 20 */ 21 21 22 $MAXNUM = 15;23 $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');24 25 22 if ($RCMAIL->action == 'group-expand') { 26 23 $abook = $RCMAIL->get_address_book(get_input_value('_source', RCUBE_INPUT_GPC)); … … 37 34 $OUTPUT->command('replace_group_recipients', $gid, join(', ', $members)); 38 35 } 36 37 $OUTPUT->send(); 39 38 } 40 else if ($book_types && ($search = get_input_value('_search', RCUBE_INPUT_GPC, true))) { 39 40 41 $MAXNUM = (int)$RCMAIL->config->get('autocomplete_max', 15); 42 $search = get_input_value('_search', RCUBE_INPUT_GPC, true); 43 $source = get_input_value('_source', RCUBE_INPUT_GPC); 44 $sid = get_input_value('_id', RCUBE_INPUT_GPC); 45 46 if (strlen($source)) 47 $book_types = array($source); 48 else 49 $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql'); 50 51 if (!empty($book_types) && strlen($search)) { 41 52 $contacts = array(); 42 53 $books_num = count($book_types); … … 88 99 } 89 100 90 $OUTPUT->command('ksearch_query_results', $contacts, $search );101 $OUTPUT->command('ksearch_query_results', $contacts, $search, $sid); 91 102 $OUTPUT->send(); 92 103 -
program/steps/mail/compose.inc
rf52c4f44 r0213f8d 112 112 'nobodywarning', 'notsentwarning', 'notuploadedwarning', 'savingmessage', 'sendingmessage', 113 113 'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany', 114 'fileuploaderror' , 'autocompletechars');114 'fileuploaderror'); 115 115 116 116 $OUTPUT->set_env('compose_id', $COMPOSE_ID); … … 125 125 $OUTPUT->set_env('sig_above', $CONFIG['sig_above']); 126 126 $OUTPUT->set_env('top_posting', $CONFIG['top_posting']); 127 $OUTPUT->set_env('autocomplete_min_length', $CONFIG['autocomplete_min_length']);128 127 129 128 // get reference message and set compose mode … … 467 466 $out = $input->show($MESSAGE->compose[$param]); 468 467 } 469 468 470 469 if ($form_start) 471 470 $out = $form_start.$out; 471 472 // configure autocompletion 473 rcube_autocomplete_init(); 472 474 473 475 return $out;
Note: See TracChangeset
for help on using the changeset viewer.
