1 /*********************************************************************************
2 * SugarCRM Community Edition is a customer relationship management program developed by
3 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Affero General Public License version 3 as published by the
7 * Free Software Foundation with the addition of the following permission added
8 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
9 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
10 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * You should have received a copy of the GNU Affero General Public License along with
18 * this program; if not, see http://www.gnu.org/licenses or write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
23 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU Affero General Public License version 3.
29 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
30 * these Appropriate Legal Notices must retain the display of the "Powered by
31 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
32 * technical reasons, the Appropriate Legal Notices must display the words
33 * "Powered by SugarCRM".
34 ********************************************************************************/
40 * browse document for quickSearch fields
41 * Compatible ExtJS 1.1.1 and ExtJS 2.0
42 * parameter : noReload - if set to true, enableQS will enable only
43 * the new sqsEnabled field on the page. If set to false
44 * it will reload all the sqsEnabled fields.
46 function enableQS(noReload){
47 YAHOO.util.Event.onDOMReady(function(){
48 //Safety check. If sqs_objects variable is null, we really can't do anything useful
49 if(typeof sqs_objects == 'undefined') {
53 var Dom = YAHOO.util.Dom;
55 //Get all the fields where sqsEnabled is an attribue, these should be the input text fields for quicksearch
56 var qsFields = Dom.getElementsByClassName('sqsEnabled');
58 //Now loop through all these fields and process them
59 for(var qsField in qsFields){
61 //Safety checks to skip processing of invalid entries
62 if(typeof qsFields[qsField] == 'function' || typeof qsFields[qsField].id == 'undefined') {
66 //Create the index we are using to search for the sqs_objects Array
67 var form_id = qsFields[qsField].form.getAttribute('id');
69 //This is a special case where there is an element with id attribute value of "id"
70 //In this case, we get the real_id attribute (occurs in modules/Import/tpls/step3.tpl only).
71 if(typeof form_id == 'object' && qsFields[qsField].form.getAttribute('real_id')) {
72 form_id = qsFields[qsField].form.getAttribute('real_id');
74 var qs_index_id = form_id + '_' + qsFields[qsField].name;
76 //Another safety check, if the sqs_objects entry is not defined, we can't do anything useful
77 if(typeof sqs_objects[qs_index_id] == 'undefined') {
78 qs_index_id = qsFields[qsField].name;
79 if(typeof sqs_objects[qs_index_id] == 'undefined') {
83 //Track if this field has already been processed. The way the enableQS function is called
84 //is a bit problematic in that it lends itself to a lot of duplicate processing
85 if(QSProcessedFieldsArray[qs_index_id]) {
86 skipSTR = 'collection_0';
87 //the 'collection_0' id is not loaded dynamically, so the first item in the collection will not have an incremental value added to the base id
88 //only skip the additional fields so that cases where a form is closed and reopened without refreshing the screen will still work
89 if (qs_index_id.lastIndexOf(skipSTR) != (qs_index_id.length - skipSTR.length)){
94 //Store sqs_objects entry as a reference for convenience
95 var qs_obj = sqs_objects[qs_index_id];
96 //The loaded variable will be used to check whether or not the quick search field should be created
99 if (!document.forms[qs_obj.form]) {
102 //Skip quicksearch fields that are readOnly or that are disabled since you can't search on them anyway
103 if (!document.forms[qs_obj.form].elements[qsFields[qsField].id].readOnly && qs_obj['disable'] != true) {
104 var combo_id = qs_obj.form + '_' + qsFields[qsField].id;
105 if (Dom.get(combo_id + "_results")) {
109 // if loaded == false, then we do the heavy lifting to re-create the quicksearch field
111 QSProcessedFieldsArray[qs_index_id] = true;
113 qsFields[qsField].form_id = form_id;
115 var sqs = sqs_objects[qs_index_id];
117 //Initialize the result div
118 var resultDiv = document.createElement('div');
119 resultDiv.id = combo_id + "_results";
120 Dom.insertAfter(resultDiv, qsFields[qsField]);
122 //Add the module to the fields so we can read it from the response
123 var fields = qs_obj.field_list.slice();
124 fields[fields.length] = "module";
126 //Create the DataSource for this QS
127 var ds = new YAHOO.util.DataSource("index.php?", {
128 responseType: YAHOO.util.XHRDataSource.TYPE_JSON,
130 resultsList: 'fields',
134 metaFields: {total: 'totalCount', fields:"fields"}
139 // Don't force selection for search fields
140 var forceSelect = !((qsFields[qsField].form && typeof(qsFields[qsField].form) == 'object' && qsFields[qsField].form.name == 'search_form')
141 || qsFields[qsField].className.match('sqsNoAutofill') != null);
143 //Finally Declare the Autocomplete
144 var search = new YAHOO.widget.AutoComplete(qsFields[qsField], resultDiv, ds, {
145 typeAhead: forceSelect,
146 forceSelection : forceSelect,
151 inputElement: qsFields[qsField],
152 //YUI requires the data, even POST, to be URL encoded
153 generateRequest : function(sQuery) {
155 var item_id = this.inputElement.form_id + '_' + this.inputElement.name;
156 if (QSCallbacksArray[item_id]) {
157 QSCallbacksArray[item_id](this.sqs);
159 var out = SUGAR.util.paramsToUrl({
162 action: 'quicksearchQuery',
163 data: YAHOO.lang.JSON.stringify(this.sqs),
168 //Method to fill in form fields with the returned results.
169 //Should be called on select, and must be called from the AC instance scope.
170 setFields : function (data, filter) {
171 this.updateFields(data, filter);
174 updateFields: function(data, filter) {
175 for(var i in this.fields) {
176 for (var key in this.qs_obj.field_list) {
177 //Check that the field exists and matches the filter
178 if (this.fields[i] == this.qs_obj.field_list[key] &&
179 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]] &&
180 this.qs_obj.populate_list[key].match(filter)) {
181 //bug: 30823 - remove the apostrophe
182 var displayValue = data[i].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');
183 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = displayValue;
184 SUGAR.util.callOnChangeListers(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]);
188 SUGAR.util.callOnChangeListers(this._elTextbox);
190 clearFields : function() {
191 for (var key in this.qs_obj.field_list) {
192 if (document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]){
193 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = "";
194 SUGAR.util.callOnChangeListers(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]);
201 //C.L. Bug 36575: In event of account_name quicksearch, check to see if we need to warn user
202 //that address fields may change. This code has similarities to code block in set_return method
203 //of sugar_3.js when building the alert message contents.
204 if(/^(billing_|shipping_)?account_name$/.exec(qsFields[qsField].name))
207 //C.L. Bug 36106 only clear the name and id fields
208 search.clearFields = function() {
209 for(var i in {name:0, id:1}) {
210 for (var key in this.qs_obj.field_list) {
211 //Check that the field exists
212 if (i == this.qs_obj.field_list[key] &&
213 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]])
215 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = "";
221 search.setFields = function(data, filter)
224 var label_data_str = '';
225 var current_label_data_str = '';
226 var label_data_hash = new Array();
228 for(var i in this.fields) {
229 for (var key in this.qs_obj.field_list) {
230 //Check that the field exists and matches the filter
231 if (this.fields[i] == this.qs_obj.field_list[key] &&
232 document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]] &&
233 document.getElementById(this.qs_obj.populate_list[key]+'_label') &&
234 this.qs_obj.populate_list[key].match(filter)) {
236 var displayValue = data[i].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');
237 var data_label = document.getElementById(this.qs_obj.populate_list[key]+'_label').innerHTML.replace(/\n/gi,'').replace(/<\/?[^>]+(>|$)/g, "");
239 label_and_data = data_label + ' ' + displayValue;
241 //Append to current_label_data_str only if the label and data are unique
242 if(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]] && !label_data_hash[data_label])
244 label_str += data_label + ' \n';
245 label_data_str += label_and_data + '\n';
246 label_data_hash[data_label] = true;
247 current_label_data_str += data_label + ' ' + document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value + '\n';
253 if(label_str != current_label_data_str && current_label_data_str != label_data_str) {
255 module_key = (typeof document.forms[form_id].elements['module'] != 'undefined') ? document.forms[form_id].elements['module'].value : 'app_strings';
256 warning_label = SUGAR.language.translate(module_key, 'NTC_OVERWRITE_ADDRESS_PHONE_CONFIRM') + '\n\n' + label_data_str;
258 if(!confirm(warning_label))
260 this.updateFields(data,/account_id/);
263 if(Dom.get('shipping_checkbox'))
265 if(this.inputElement.id == 'shipping_account_name')
267 //If the copy address checkbox is checked, update account and office_phone
268 filter = Dom.get('shipping_checkbox').checked ? /(account_id|office_phone)/ : filter;
269 } else if(this.inputElement.id == 'billing_account_name') {
270 //If the copy address is checked, update account, office phone and billing addresses
271 filter = Dom.get('shipping_checkbox').checked ? filter : /(account_id|office_phone|billing)/;
273 } else if(Dom.get('alt_checkbox')) {
274 filter = Dom.get('alt_checkbox').checked ? filter : /^(?!alt)/;
277 this.updateFields(data,filter);
280 this.updateFields(data,filter);
286 if ( typeof(SUGAR.config.quicksearch_querydelay) != 'undefined' ) {
287 search.queryDelay = Number(SUGAR.config.quicksearch_querydelay);
290 //fill in the data fields on selection
291 search.itemSelectEvent.subscribe(function(e, args){
293 var fields = this.fields;
294 this.setFields(data, /\S/);
296 //Handle special case where post_onblur_function is set
297 if (typeof(this.qs_obj['post_onblur_function']) != 'undefined') {
298 collection_extended = new Array();
299 for (var i in fields) {
300 for (var key in this.qs_obj.field_list) {
301 if (fields[i] == this.qs_obj.field_list[key]) {
302 collection_extended[this.qs_obj.field_list[key]] = data[i];
306 eval(this.qs_obj['post_onblur_function'] + '(collection_extended, this.qs_obj.id)');
310 // We will get the old value firstly when the field lose focus.
311 search.textboxFocusEvent.subscribe(function(){
312 this.oldValue = this.getInputEl().value;
315 //If there is no change for this qucik search field , the value of it will not be cleared.
316 search.selectionEnforceEvent.subscribe(function(e, args){
317 if (this.oldValue != args[1]) {
320 this.getInputEl().value = this.oldValue;
324 search.dataReturnEvent.subscribe(function(e, args){
325 //Selected the first returned value if a tab was done before results were returned
326 if (this.getInputEl().value.length == 0 && args[2].length > 0) {
328 for(var key in this.qs_obj.field_list) {
329 data[data.length] = args[2][0][this.qs_obj.field_list[key]];
331 this.getInputEl().value = data[this.key];
332 this.itemSelectEvent.fire(this, "", data);
336 search.typeAheadEvent.subscribe(function (e, args) {
337 this.getInputEl().value = this.getInputEl().value.replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');
341 if (typeof QSFieldsArray[combo_id] == 'undefined' && qsFields[qsField].id) {
342 QSFieldsArray[combo_id] = search;
350 function registerSingleSmartInputListener(input) {
351 if ((c = input.className) && (c.indexOf("sqsEnabled") != -1)) {
356 if(typeof QSFieldsArray == 'undefined') {
357 QSFieldsArray = new Array();
358 QSProcessedFieldsArray = new Array();
359 QSCallbacksArray = new Array();