Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | /* |
2 | +--------------------------------------------------------------------+ | |
3 | | CiviCRM version 4.3 | | |
4 | +--------------------------------------------------------------------+ | |
5 | | Copyright CiviCRM LLC (c) 2004-2013 | | |
6 | +--------------------------------------------------------------------+ | |
7 | | This file is a part of CiviCRM. | | |
8 | | | | |
9 | | CiviCRM is free software; you can copy, modify, and distribute it | | |
10 | | under the terms of the GNU Affero General Public License | | |
11 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | | |
12 | | | | |
13 | | CiviCRM is distributed in the hope that it will be useful, but | | |
14 | | WITHOUT ANY WARRANTY; without even the implied warranty of | | |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | |
16 | | See the GNU Affero General Public License for more details. | | |
17 | | | | |
18 | | You should have received a copy of the GNU Affero General Public | | |
19 | | License and the CiviCRM Licensing Exception along | | |
20 | | with this program; if not, contact CiviCRM LLC | | |
21 | | at info[AT]civicrm[DOT]org. If you have questions about the | | |
22 | | GNU Affero General Public License or the licensing of CiviCRM, | | |
23 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | | |
24 | +--------------------------------------------------------------------+ | |
25 | */ | |
26 | ||
27 | /** | |
28 | * @file: global functions for CiviCRM | |
29 | * FIXME: We are moving away from using global functions. DO NOT ADD MORE. | |
30 | * @see CRM object - the better alternative to adding global functions | |
31 | */ | |
32 | ||
33 | var CRM = CRM || {}; | |
34 | var cj = jQuery; | |
35 | ||
36 | /** | |
37 | * Short-named function for string translation, defined in global scope so it's available everywhere. | |
38 | * | |
39 | * @param $text string string for translating | |
40 | * @param $params object key:value of additional parameters | |
41 | * | |
42 | * @return string the translated string | |
43 | */ | |
44 | function ts(text, params) { | |
7553cf23 | 45 | "use strict"; |
6a488035 TO |
46 | text = CRM.strings[text] || text; |
47 | if (params && typeof(params) === 'object') { | |
48 | for (var i in params) { | |
49 | // sprintf emulation: escape % characters in the replacements to avoid conflicts | |
50 | text = text.replace(new RegExp('%'+i, 'g'), params[i].replace(/%/g, '%-crmescaped-')); | |
51 | } | |
52 | return text.replace(/%-crmescaped-/g, '%'); | |
53 | } | |
54 | return text; | |
55 | } | |
56 | ||
57 | /** | |
58 | * This function is called by default at the bottom of template files which have forms that have | |
59 | * conditionally displayed/hidden sections and elements. The PHP is responsible for generating | |
60 | * a list of 'blocks to show' and 'blocks to hide' and the template passes these parameters to | |
61 | * this function. | |
62 | * | |
63 | * @access public | |
64 | * @param showBlocks Array of element Id's to be displayed | |
65 | * @param hideBlocks Array of element Id's to be hidden | |
66 | * @param elementType Value to set display style to for showBlocks (e.g. 'block' or 'table-row' or ...) | |
67 | * @return none | |
68 | */ | |
69 | function on_load_init_blocks(showBlocks, hideBlocks, elementType) | |
70 | { | |
71 | if ( elementType == null ) { | |
72 | var elementType = 'block'; | |
73 | } | |
74 | ||
75 | /* This loop is used to display the blocks whose IDs are present within the showBlocks array */ | |
76 | for ( var i = 0; i < showBlocks.length; i++ ) { | |
77 | var myElement = document.getElementById(showBlocks[i]); | |
78 | /* getElementById returns null if element id doesn't exist in the document */ | |
79 | if (myElement != null) { | |
80 | myElement.style.display = elementType; | |
81 | } else { | |
82 | alert('showBlocks array item not in .tpl = ' + showBlocks[i]); | |
83 | } | |
84 | } | |
85 | ||
86 | /* This loop is used to hide the blocks whose IDs are present within the hideBlocks array */ | |
87 | for ( var i = 0; i < hideBlocks.length; i++ ) { | |
88 | var myElement = document.getElementById(hideBlocks[i]); | |
89 | /* getElementById returns null if element id doesn't exist in the document */ | |
90 | if (myElement != null) { | |
91 | myElement.style.display = 'none'; | |
92 | } else { | |
93 | alert('showBlocks array item not in .tpl = ' + hideBlocks[i]); | |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | /** | |
99 | * This function is called when we need to show or hide a related form element (target_element) | |
100 | * based on the value (trigger_value) of another form field (trigger_field). | |
101 | * | |
102 | * @access public | |
103 | * @param trigger_field_id HTML id of field whose onchange is the trigger | |
104 | * @param trigger_value List of integers - option value(s) which trigger show-element action for target_field | |
105 | * @param target_element_id HTML id of element to be shown or hidden | |
106 | * @param target_element_type Type of element to be shown or hidden ('block' or 'table-row') | |
107 | * @param field_type Type of element radio/select | |
108 | * @param invert Boolean - if true, we HIDE target on value match; if false, we SHOW target on value match | |
109 | * @return none | |
110 | */ | |
111 | function showHideByValue(trigger_field_id, trigger_value, target_element_id, target_element_type, field_type, invert ) { | |
112 | if ( target_element_type == null ) { | |
113 | var target_element_type = 'block'; | |
114 | } else if ( target_element_type == 'table-row' ) { | |
115 | var target_element_type = ''; | |
116 | } | |
117 | ||
118 | if (field_type == 'select') { | |
119 | var trigger = trigger_value.split("|"); | |
120 | var selectedOptionValue = document.getElementById(trigger_field_id).options[document.getElementById(trigger_field_id).selectedIndex].value; | |
121 | ||
122 | var target = target_element_id.split("|"); | |
123 | for(var j = 0; j < target.length; j++) { | |
124 | if ( invert ) { | |
125 | cj('#' + target[j]).show(); | |
126 | } else { | |
127 | cj('#' + target[j]).hide(); | |
128 | } | |
129 | for(var i = 0; i < trigger.length; i++) { | |
130 | if (selectedOptionValue == trigger[i]) { | |
131 | if ( invert ) { | |
132 | cj('#' + target[j]).hide(); | |
133 | } else { | |
134 | cj('#' + target[j]).show(); | |
135 | } | |
136 | } | |
137 | } | |
138 | } | |
139 | ||
140 | } else if (field_type == 'radio') { | |
141 | var target = target_element_id.split("|"); | |
142 | for(var j = 0; j < target.length; j++) { | |
143 | if (document.getElementsByName(trigger_field_id)[0].checked) { | |
144 | if ( invert ) { | |
145 | cj('#' + target[j]).hide(); | |
146 | } else { | |
147 | cj('#' + target[j]).show(); | |
148 | } | |
149 | } else { | |
150 | if ( invert ) { | |
151 | cj('#' + target[j]).show(); | |
152 | } else { | |
153 | cj('#' + target[j]).hide(); | |
154 | } | |
155 | } | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | /** | |
161 | * | |
162 | * Function for checking ALL or unchecking ALL check boxes in a resultset page. | |
163 | * | |
164 | * @access public | |
165 | * @param fldPrefix - common string which precedes unique checkbox ID and identifies field as | |
166 | * belonging to the resultset's checkbox collection | |
167 | * @param object - checkbox | |
168 | * Sample usage: onClick="javascript:changeCheckboxValues('chk_', cj(this) );" | |
169 | * | |
170 | * @return | |
171 | */ | |
172 | function toggleCheckboxVals(fldPrefix, object) { | |
173 | if ( object.id == 'toggleSelect' && cj(object).is(':checked') ) { | |
174 | cj( 'Input[id*="' + fldPrefix + '"],Input[id*="toggleSelect"]').attr('checked', true); | |
175 | } else { | |
176 | cj( 'Input[id*="' + fldPrefix + '"],Input[id*="toggleSelect"]').attr('checked', false); | |
177 | } | |
178 | // change the class of selected rows | |
179 | on_load_init_checkboxes(object.form.name); | |
180 | } | |
181 | ||
182 | function countSelectedCheckboxes(fldPrefix, form) { | |
183 | fieldCount = 0; | |
184 | for( i=0; i < form.elements.length; i++) { | |
185 | fpLen = fldPrefix.length; | |
186 | if (form.elements[i].type == 'checkbox' && form.elements[i].name.slice(0,fpLen) == fldPrefix && form.elements[i].checked == true) { | |
187 | fieldCount++; | |
188 | } | |
189 | } | |
190 | return fieldCount; | |
191 | } | |
192 | ||
193 | /** | |
194 | * Function to enable task action select | |
195 | */ | |
196 | function toggleTaskAction( status ) { | |
197 | var radio_ts = document.getElementsByName('radio_ts'); | |
198 | if (!radio_ts[1]) { | |
199 | radio_ts[0].checked = true; | |
200 | } | |
201 | if ( radio_ts[0].checked || radio_ts[1].checked ) { | |
202 | status = true; | |
203 | } | |
204 | ||
205 | var formElements = ['task', 'Go', 'Print']; | |
206 | for(var i=0; i<formElements.length; i++ ) { | |
207 | var element = document.getElementById( formElements[i] ); | |
208 | if ( element ) { | |
209 | if ( status ) { | |
210 | element.disabled = false; | |
211 | } else { | |
212 | element.disabled = true; | |
213 | } | |
214 | } | |
215 | } | |
216 | } | |
217 | ||
218 | /** | |
219 | * This function is used to check if any actio is selected and also to check if any contacts are checked. | |
220 | * | |
221 | * @access public | |
222 | * @param fldPrefix - common string which precedes unique checkbox ID and identifies field as | |
223 | * belonging to the resultset's checkbox collection | |
224 | * @param form - name of form that checkboxes are part of | |
225 | * Sample usage: onClick="javascript:checkPerformAction('chk_', myForm );" | |
226 | * | |
227 | */ | |
228 | function checkPerformAction (fldPrefix, form, taskButton, selection) { | |
229 | var cnt; | |
230 | var gotTask = 0; | |
231 | ||
232 | // taskButton TRUE means we don't need to check the 'task' field - it's a button-driven task | |
233 | if (taskButton == 1) { | |
234 | gotTask = 1; | |
235 | } else if (document.forms[form].task.selectedIndex) { | |
236 | //force user to select all search contacts, CRM-3711 | |
237 | if ( document.forms[form].task.value == 13 || document.forms[form].task.value == 14 ) { | |
238 | var toggleSelect = document.getElementsByName('toggleSelect'); | |
239 | if ( toggleSelect[0].checked || document.forms[form].radio_ts[0].checked ) { | |
240 | return true; | |
241 | } else { | |
242 | alert( "Please select all contacts for this action.\n\nTo use the entire set of search results, click the 'all records' radio button." ); | |
243 | return false; | |
244 | } | |
245 | } | |
246 | gotTask = 1; | |
247 | } | |
248 | ||
249 | if (gotTask == 1) { | |
250 | // If user wants to perform action on ALL records and we have a task, return (no need to check further) | |
251 | if (document.forms[form].radio_ts[0].checked) { | |
252 | return true; | |
253 | } | |
254 | ||
255 | cnt = (selection == 1) ? countSelections() : countSelectedCheckboxes(fldPrefix, document.forms[form]); | |
256 | if (!cnt) { | |
257 | alert ("Please select one or more contacts for this action.\n\nTo use the entire set of search results, click the 'all records' radio button."); | |
258 | return false; | |
259 | } | |
260 | } else { | |
261 | alert ("Please select an action from the drop-down menu."); | |
262 | return false; | |
263 | } | |
264 | } | |
265 | ||
266 | /** | |
267 | * This function changes the style for a checkbox block when it is selected. | |
268 | * | |
269 | * @access public | |
270 | * @param chkName - it is name of the checkbox | |
271 | * @return null | |
272 | */ | |
273 | function checkSelectedBox( chkName ) { | |
274 | var checkElement = cj('#' + chkName ); | |
275 | if ( checkElement.attr('checked') ) { | |
276 | cj('input[value=ts_sel]:radio').attr('checked',true ); | |
277 | checkElement.parents('tr').addClass('crm-row-selected'); | |
278 | } else { | |
279 | checkElement.parents('tr').removeClass('crm-row-selected'); | |
280 | } | |
281 | } | |
282 | ||
283 | /** | |
284 | * This function is to show the row with selected checkbox in different color | |
285 | * @param form - name of form that checkboxes are part of | |
286 | * | |
287 | * @access public | |
288 | * @return null | |
289 | */ | |
290 | function on_load_init_checkboxes(form) | |
291 | { | |
292 | var formName = form; | |
293 | var fldPrefix = 'mark_x'; | |
294 | for( i=0; i < document.forms[formName].elements.length; i++) { | |
295 | fpLen = fldPrefix.length; | |
296 | if (document.forms[formName].elements[i].type == 'checkbox' && document.forms[formName].elements[i].name.slice(0,fpLen) == fldPrefix ) { | |
297 | checkSelectedBox (document.forms[formName].elements[i].name, formName); | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | /** | |
303 | * Function to change the color of the class | |
304 | * | |
305 | * @param form - name of the form | |
306 | * @param rowid - id of the <tr>, <div> you want to change | |
307 | * | |
308 | * @access public | |
309 | * @return null | |
310 | */ | |
311 | function changeRowColor (rowid, form) { | |
312 | switch (document.getElementById(rowid).className) { | |
313 | case 'even-row' : document.getElementById(rowid).className = 'selected even-row'; | |
314 | break; | |
315 | case 'odd-row' : document.getElementById(rowid).className = 'selected odd-row'; | |
316 | break; | |
317 | case 'selected even-row' : document.getElementById(rowid).className = 'even-row'; | |
318 | break; | |
319 | case 'selected odd-row' : document.getElementById(rowid).className = 'odd-row'; | |
320 | break; | |
321 | case 'form-item' : document.getElementById(rowid).className = 'selected'; | |
322 | break; | |
323 | case 'selected' : document.getElementById(rowid).className = 'form-item'; | |
324 | } | |
325 | } | |
326 | ||
327 | /** | |
328 | * This function is to show the row with selected checkbox in different color | |
329 | * @param form - name of form that checkboxes are part of | |
330 | * | |
331 | * @access public | |
332 | * @return null | |
333 | */ | |
334 | function on_load_init_check(form) | |
335 | { | |
336 | for( i=0; i < document.forms[form].elements.length; i++) { | |
337 | if ( ( document.forms[form].elements[i].type == 'checkbox' | |
338 | && document.forms[form].elements[i].checked == true ) | |
339 | || ( document.forms[form].elements[i].type == 'hidden' | |
340 | && document.forms[form].elements[i].value == 1 ) ) { | |
341 | var ss = document.forms[form].elements[i].id; | |
342 | var row = 'rowid' + ss; | |
343 | changeRowColor(row, form); | |
344 | } | |
345 | } | |
346 | } | |
347 | ||
348 | /** | |
349 | * reset all the radio buttons with a given name | |
350 | * | |
351 | * @param string fieldName | |
352 | * @param object form | |
353 | * @return null | |
354 | */ | |
355 | function unselectRadio(fieldName, form) { | |
356 | for( i=0; i < document.forms[form].elements.length; i++) { | |
357 | if (document.forms[form].elements[i].name == fieldName) { | |
358 | document.forms[form].elements[i].checked = false; | |
359 | } | |
360 | } | |
361 | return; | |
362 | } | |
363 | ||
364 | /** | |
365 | * Function to change button text and disable one it is clicked | |
366 | * | |
367 | * @param obj object - the button clicked | |
368 | * @param formID string - the id of the form being submitted | |
369 | * @param string procText - button text after user clicks it | |
370 | * @return null | |
371 | */ | |
372 | var submitcount=0; | |
373 | /* Changes button label on submit, and disables button after submit for newer browsers. | |
374 | Puts up alert for older browsers. */ | |
375 | function submitOnce(obj,formId,procText) { | |
376 | // if named button clicked, change text | |
377 | if (obj.value != null) { | |
378 | obj.value = procText + " ..."; | |
379 | } | |
380 | if (document.getElementById) { // disable submit button for newer browsers | |
381 | obj.disabled = true; | |
382 | document.getElementById(formId).submit(); | |
383 | return true; | |
384 | } else { // for older browsers | |
385 | if (submitcount == 0) { | |
386 | submitcount++; | |
387 | return true; | |
388 | } else { | |
389 | alert("Your request is currently being processed ... Please wait."); | |
390 | return false; | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | function popUp(URL) { | |
396 | day = new Date(); | |
397 | id = day.getTime(); | |
398 | eval("page" + id + " = window.open(URL, '" + id + "', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=0,width=640,height=420,left = 202,top = 184');"); | |
399 | } | |
400 | ||
401 | function imagePopUp ( path ) { | |
402 | window.open(path,'popupWindow','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,screenX=150,screenY=150,top=150,left=150'); | |
403 | } | |
404 | ||
405 | /** | |
406 | * Function to show / hide the row in optionFields | |
407 | * | |
408 | * @param element name index, that whose innerHTML is to hide else will show the hidden row. | |
409 | */ | |
410 | function showHideRow( index ) { | |
411 | if ( index ) { | |
412 | cj( 'tr#optionField_' + index ).hide( ); | |
413 | if( cj( 'table#optionField tr:hidden:first' ).length ) cj( 'div#optionFieldLink' ).show( ); | |
414 | } else { | |
415 | cj( 'table#optionField tr:hidden:first' ).show( ); | |
416 | if( ! cj( 'table#optionField tr:hidden:last' ).length ) cj( 'div#optionFieldLink' ).hide( ); | |
417 | } | |
418 | return false; | |
419 | } | |
420 | ||
421 | /** | |
422 | * Function to check activity status in relavent to activity date | |
423 | * | |
424 | * @param element message JSON object. | |
425 | */ | |
426 | function activityStatus( message ) { | |
427 | var d = new Date(), time = [], i; | |
428 | var currentDateTime = d.getTime() | |
429 | var activityTime = cj("input#activity_date_time_time").val().replace(":", ""); | |
430 | ||
431 | //chunk the time in bunch of 2 (hours,minutes,ampm) | |
432 | for(i=0; i<activityTime.length; i+=2 ) { | |
433 | time.push( activityTime.slice( i, i+2 ) ); | |
434 | } | |
435 | var activityDate = new Date( cj("input#activity_date_time_hidden").val() ); | |
436 | ||
437 | d.setFullYear(activityDate.getFullYear()); | |
438 | d.setMonth(activityDate.getMonth()); | |
439 | d.setDate(activityDate.getDate()); | |
440 | var hours = time['0']; | |
441 | var ampm = time['2']; | |
442 | ||
443 | if (ampm == "PM" && hours != 0 && hours != 12) { | |
444 | // force arithmetic instead of string concatenation | |
445 | hours = hours*1 + 12; | |
446 | } else if (ampm == "AM" && hours == 12) { | |
447 | hours = 0; | |
448 | } | |
449 | d.setHours(hours); | |
450 | d.setMinutes(time['1']); | |
451 | ||
452 | var activity_date_time = d.getTime(); | |
453 | ||
454 | var activityStatusId = cj('#status_id').val(); | |
455 | ||
456 | if ( activityStatusId == 2 && currentDateTime < activity_date_time ) { | |
457 | if (! confirm( message.completed )) { | |
458 | return false; | |
459 | } | |
460 | } else if ( activity_date_time && activityStatusId == 1 && currentDateTime >= activity_date_time ) { | |
461 | if (! confirm( message.scheduled )) { | |
462 | return false; | |
463 | } | |
464 | } | |
465 | } | |
466 | ||
6a488035 TO |
467 | CRM.strings = CRM.strings || {}; |
468 | CRM.validate = CRM.validate || { | |
469 | params: {}, | |
470 | functions: [] | |
471 | }; | |
472 | ||
473 | (function($, undefined) { | |
7553cf23 | 474 | "use strict"; |
6a488035 | 475 | $(document).ready(function() { |
6a488035 TO |
476 | $().crmtooltip(); |
477 | $('.crm-container table.row-highlight').on('change', 'input.select-row, input.select-rows', function() { | |
e24b17b9 | 478 | var target, table = $(this).closest('table'); |
6a488035 | 479 | if ($(this).hasClass('select-rows')) { |
e24b17b9 | 480 | target = $('tbody tr', table); |
6a488035 TO |
481 | $('input.select-row', table).prop('checked', $(this).prop('checked')); |
482 | } | |
483 | else { | |
e24b17b9 | 484 | target = $(this).closest('tr'); |
6a488035 TO |
485 | $('input.select-rows', table).prop('checked', $(".select-row:not(':checked')", table).length < 1); |
486 | } | |
487 | target.toggleClass('crm-row-selected', $(this).is(':checked')); | |
488 | }); | |
e24b17b9 CW |
489 | $('#crm-container').live('click', function(event) { |
490 | if ($(event.target).is('.btn-slide')) { | |
491 | var currentActive = $('#crm-container .btn-slide-active'); | |
6a488035 TO |
492 | currentActive.children().hide(); |
493 | currentActive.removeClass('btn-slide-active'); | |
e24b17b9 CW |
494 | $(event.target).children().show(); |
495 | $(event.target).addClass('btn-slide-active'); | |
6a488035 | 496 | } else { |
e24b17b9 CW |
497 | $('.btn-slide .panel').hide(); |
498 | $('.btn-slide-active').removeClass('btn-slide-active'); | |
6a488035 TO |
499 | } |
500 | }); | |
501 | }); | |
148c4e8d CW |
502 | |
503 | /** | |
504 | * Function to make multiselect boxes behave as fields in small screens | |
505 | */ | |
506 | function advmultiselectResize() { | |
507 | var amswidth = $("#crm-container form:has(table.advmultiselect)").width(); | |
508 | if (amswidth < 700) { | |
509 | $("form table.advmultiselect td").css('display', 'block'); | |
510 | } else { | |
511 | $("form table.advmultiselect td").css('display', 'table-cell'); | |
512 | } | |
513 | var contactwidth = $('#crm-container #mainTabContainer').width(); | |
514 | if (contactwidth < 600) { | |
515 | $('#crm-container #mainTabContainer').addClass('narrowpage'); | |
516 | $('#crm-container #mainTabContainer.narrowpage #contactTopBar td').each( function(index) { | |
517 | if (index > 1) { | |
518 | if (index%2 == 0) { | |
519 | $(this).parent().after('<tr class="narrowadded"></tr>'); | |
520 | } | |
521 | var item = $(this); | |
522 | $(this).parent().next().append(item); | |
523 | } | |
524 | }); | |
525 | } else { | |
526 | $('#crm-container #mainTabContainer.narrowpage').removeClass('narrowpage'); | |
527 | $('#crm-container #mainTabContainer #contactTopBar tr.narrowadded td').each( function() { | |
528 | var nitem = $(this); | |
529 | var parent = $(this).parent(); | |
530 | $(this).parent().prev().append(nitem); | |
531 | if ( parent.children().size() == 0 ) { | |
532 | parent.remove(); | |
533 | } | |
534 | }); | |
535 | $('#crm-container #mainTabContainer.narrowpage #contactTopBar tr.added').detach(); | |
536 | } | |
537 | var cformwidth = $('#crm-container #Contact .contact_basic_information-section').width(); | |
538 | ||
539 | if (cformwidth < 720) { | |
540 | $('#crm-container .contact_basic_information-section').addClass('narrowform'); | |
541 | $('#crm-container .contact_basic_information-section table.form-layout-compressed td .helpicon').parent().addClass('hashelpicon'); | |
542 | if (cformwidth < 480) { | |
543 | $('#crm-container .contact_basic_information-section').addClass('xnarrowform'); | |
544 | } else { | |
545 | $('#crm-container .contact_basic_information-section.xnarrowform').removeClass('xnarrowform'); | |
546 | } | |
547 | } else { | |
548 | $('#crm-container .contact_basic_information-section.narrowform').removeClass('narrowform'); | |
549 | $('#crm-container .contact_basic_information-section.xnarrowform').removeClass('xnarrowform'); | |
550 | } | |
551 | } | |
552 | advmultiselectResize(); | |
6a488035 TO |
553 | $(window).resize(function() { |
554 | advmultiselectResize(); | |
555 | }); | |
556 | ||
e24b17b9 CW |
557 | $.fn.crmtooltip = function() { |
558 | $('a.crm-summary-link:not(.crm-processed)') | |
559 | .addClass('crm-processed') | |
560 | .on('mouseover', function(e) { | |
561 | $(this).addClass('crm-tooltip-active'); | |
562 | var topDistance = e.pageY - $(window).scrollTop(); | |
563 | if (topDistance < 300 | topDistance < $(this).children('.crm-tooltip-wrapper').height()) { | |
564 | $(this).addClass('crm-tooltip-down'); | |
565 | } | |
566 | if (!$(this).children('.crm-tooltip-wrapper').length) { | |
6a488035 TO |
567 | $(this).append('<div class="crm-tooltip-wrapper"><div class="crm-tooltip"></div></div>'); |
568 | $(this).children().children('.crm-tooltip') | |
569 | .html('<div class="crm-loading-element"></div>') | |
570 | .load(this.href); | |
571 | } | |
572 | }) | |
e24b17b9 CW |
573 | .on('mouseout', function() { |
574 | $(this).removeClass('crm-tooltip-active crm-tooltip-down'); | |
575 | }) | |
576 | .on('click', false); | |
6a488035 TO |
577 | }; |
578 | ||
579 | var h; | |
580 | CRM.help = function(title, params) { | |
581 | h && h.close && h.close(); | |
582 | var options = { | |
583 | expires: 0 | |
584 | }; | |
585 | h = CRM.alert('...', title, 'crm-help crm-msg-loading', options); | |
586 | params.class_name = 'CRM_Core_Page_Inline_Help'; | |
587 | params.type = 'page'; | |
588 | $.ajax(CRM.url('civicrm/ajax/inline'), | |
589 | { | |
590 | data: params, | |
591 | dataType: 'html', | |
e24b17b9 | 592 | success: function (data) { |
6a488035 TO |
593 | $('#crm-notification-container .crm-help .notify-content:last').html(data); |
594 | $('#crm-notification-container .crm-help').removeClass('crm-msg-loading').addClass('info'); | |
595 | }, | |
e24b17b9 | 596 | error: function () { |
6a488035 TO |
597 | $('#crm-notification-container .crm-help .notify-content:last').html('Unable to load help file.'); |
598 | $('#crm-notification-container .crm-help').removeClass('crm-msg-loading').addClass('error'); | |
599 | } | |
600 | } | |
601 | ); | |
602 | }; | |
603 | ||
604 | /** | |
605 | * @param string text Displayable message | |
606 | * @param string title Displayable title | |
607 | * @param string type 'alert'|'info'|'success'|'error' (default: 'alert') | |
608 | * @param {object} options | |
609 | * @return {*} | |
610 | * @see http://wiki.civicrm.org/confluence/display/CRM/Notifications+in+CiviCRM | |
611 | */ | |
612 | CRM.alert = function(text, title, type, options) { | |
613 | type = type || 'alert'; | |
614 | title = title || ''; | |
615 | options = options || {}; | |
616 | if ($('#crm-notification-container').length) { | |
617 | var params = { | |
618 | text: text, | |
619 | title: title, | |
620 | type: type | |
621 | }; | |
622 | // By default, don't expire errors and messages containing links | |
623 | var extra = { | |
624 | expires: (type == 'error' || text.indexOf('<a ') > -1) ? 0 : (text ? 10000 : 5000), | |
625 | unique: true | |
626 | }; | |
627 | options = $.extend(extra, options); | |
e24b17b9 | 628 | options.expires = options.expires === false ? 0 : parseInt(options.expires, 10); |
6a488035 TO |
629 | if (options.unique && options.unique !== '0') { |
630 | $('#crm-notification-container .ui-notify-message').each(function() { | |
631 | if (title === $('h1', this).html() && text === $('.notify-content', this).html()) { | |
632 | $('.icon.ui-notify-close', this).click(); | |
633 | } | |
634 | }); | |
635 | } | |
636 | return $('#crm-notification-container').notify('create', params, options); | |
637 | } | |
638 | else { | |
639 | if (title.length) { | |
640 | text = title + "\n" + text; | |
641 | } | |
642 | alert(text); | |
643 | return null; | |
644 | } | |
e24b17b9 | 645 | }; |
6a488035 TO |
646 | |
647 | /** | |
648 | * Close whichever alert contains the given node | |
649 | * | |
650 | * @param node | |
651 | */ | |
652 | CRM.closeAlertByChild = function(node) { | |
653 | $(node).closest('.ui-notify-message').find('.icon.ui-notify-close').click(); | |
e24b17b9 | 654 | }; |
6a488035 TO |
655 | |
656 | /** | |
657 | * Prompt the user for confirmation. | |
658 | * | |
7553cf23 CW |
659 | * @param buttons {object|function} key|value pairs where key == button label and value == callback function |
660 | * passing in a function instead of an object is a shortcut for a sinlgle button labeled "Continue" | |
661 | * @param options {object|void} Override defaults, keys include 'title', 'message', | |
662 | * see jQuery.dialog for full list of available params | |
6a488035 | 663 | */ |
7553cf23 CW |
664 | CRM.confirm = function(buttons, options) { |
665 | var dialog, callbacks = {}; | |
666 | var settings = { | |
667 | title: ts('Confirm Action'), | |
668 | message: ts('Are you sure you want to continue?'), | |
6a488035 TO |
669 | resizable: false, |
670 | modal: true, | |
7553cf23 CW |
671 | close: function() {$(dialog).remove();}, |
672 | buttons: {} | |
673 | }; | |
674 | settings.buttons[ts('Cancel')] = function() {dialog.dialog('close');}; | |
675 | options = options || {}; | |
676 | $.extend(settings, options); | |
677 | if (typeof(buttons) === 'function') { | |
678 | callbacks[ts('Continue')] = buttons; | |
679 | } else { | |
680 | callbacks = buttons; | |
681 | } | |
682 | $.each(callbacks, function(label, callback) { | |
683 | settings.buttons[label] = function() { | |
684 | callback.call(dialog); | |
685 | dialog.dialog('close'); | |
e24b17b9 | 686 | }; |
6a488035 | 687 | }); |
7553cf23 CW |
688 | dialog = $('<div class="crm-container crm-confirm-dialog"></div>') |
689 | .html(options.message) | |
690 | .appendTo('body') | |
691 | .dialog(settings); | |
692 | return dialog; | |
e24b17b9 | 693 | }; |
6a488035 TO |
694 | |
695 | /** | |
696 | * Sets an error message | |
697 | * If called for a form item, title and removal condition will be handled automatically | |
698 | */ | |
699 | $.fn.crmError = function(text, title, options) { | |
700 | title = title || ''; | |
701 | text = text || ''; | |
702 | options = options || {}; | |
703 | ||
704 | var extra = { | |
705 | expires: 0 | |
706 | }; | |
707 | if ($(this).length) { | |
708 | if (title == '') { | |
709 | var label = $('label[for="' + $(this).attr('name') + '"], label[for="' + $(this).attr('id') + '"]').not('[generated=true]'); | |
710 | if (label.length) { | |
711 | label.addClass('crm-error'); | |
712 | var $label = label.clone(); | |
713 | if (text == '' && $('.crm-marker', $label).length > 0) { | |
714 | text = $('.crm-marker', $label).attr('title'); | |
715 | } | |
716 | $('.crm-marker', $label).remove(); | |
717 | title = $label.text(); | |
718 | } | |
719 | } | |
720 | $(this).addClass('error'); | |
721 | } | |
722 | var msg = CRM.alert(text, title, 'error', $.extend(extra, options)); | |
723 | if ($(this).length) { | |
724 | var ele = $(this); | |
725 | setTimeout(function() {ele.one('change', function() { | |
726 | msg && msg.close && msg.close(); | |
727 | ele.removeClass('error'); | |
728 | label.removeClass('crm-error'); | |
729 | });}, 1000); | |
730 | } | |
731 | return msg; | |
e24b17b9 | 732 | }; |
6a488035 TO |
733 | |
734 | // Display system alerts through js notifications | |
735 | function messagesFromMarkup() { | |
736 | $('div.messages:visible', this).not('.help').not('.no-popup').each(function() { | |
e24b17b9 | 737 | var text, title = ''; |
6a488035 TO |
738 | $(this).removeClass('status messages'); |
739 | var type = $(this).attr('class').split(' ')[0] || 'alert'; | |
740 | type = type.replace('crm-', ''); | |
741 | $('.icon', this).remove(); | |
6a488035 | 742 | if ($('.msg-text', this).length > 0) { |
e24b17b9 | 743 | text = $('.msg-text', this).html(); |
6a488035 TO |
744 | title = $('.msg-title', this).html(); |
745 | } | |
746 | else { | |
e24b17b9 | 747 | text = $(this).html(); |
6a488035 TO |
748 | } |
749 | var options = $(this).data('options') || {}; | |
750 | $(this).remove(); | |
751 | // Duplicates were already removed server-side | |
752 | options.unique = false; | |
753 | CRM.alert(text, title, type, options); | |
754 | }); | |
755 | // Handle qf form errors | |
756 | $('form :input.error', this).one('blur', function() { | |
757 | $('.ui-notify-message.error a.ui-notify-close').click(); | |
758 | $(this).removeClass('error'); | |
759 | $(this).next('span.crm-error').remove(); | |
760 | $('label[for="' + $(this).attr('name') + '"], label[for="' + $(this).attr('id') + '"]') | |
761 | .removeClass('crm-error') | |
762 | .find('.crm-error').removeClass('crm-error'); | |
763 | }); | |
764 | } | |
765 | ||
766 | $(document).ready(function() { | |
767 | if (CRM && CRM.config && CRM.config.urlIsPublic === false) { | |
768 | // Initialize notifications | |
769 | $('#crm-notification-container').notify(); | |
770 | messagesFromMarkup.call($('#crm-container')); | |
771 | $('#crm-container').on('crmFormLoad', '*', messagesFromMarkup); | |
772 | } | |
773 | }); | |
774 | ||
775 | $.fn.crmAccordions = function(speed) { | |
e24b17b9 | 776 | var container = $('#crm-container'); |
6a488035 TO |
777 | if (speed === undefined) { |
778 | speed = 200; | |
779 | } | |
780 | if ($(this).length > 0) { | |
e24b17b9 | 781 | container = $(this); |
6a488035 TO |
782 | } |
783 | if (container.length > 0 && !container.hasClass('crm-accordion-processed')) { | |
784 | // Allow normal clicking of links | |
785 | container.on('click', 'div.crm-accordion-header a', function (e) { | |
786 | e.stopPropagation && e.stopPropagation(); | |
787 | }); | |
788 | container.on('click', '.crm-accordion-header, .crm-collapsible .collapsible-title', function () { | |
789 | if ($(this).parent().hasClass('collapsed')) { | |
790 | $(this).next().css('display', 'none').slideDown(speed); | |
791 | } | |
792 | else { | |
793 | $(this).next().css('display', 'block').slideUp(speed); | |
794 | } | |
795 | $(this).parent().toggleClass('collapsed'); | |
796 | return false; | |
797 | }); | |
798 | container.addClass('crm-accordion-processed'); | |
e24b17b9 | 799 | } |
6a488035 TO |
800 | }; |
801 | $.fn.crmAccordionToggle = function(speed) { | |
802 | $(this).each(function() { | |
803 | if ($(this).hasClass('collapsed')) { | |
804 | $('.crm-accordion-body', this).first().css('display', 'none').slideDown(speed); | |
805 | } | |
806 | else { | |
807 | $('.crm-accordion-body', this).first().css('display', 'block').slideUp(speed); | |
808 | } | |
809 | $(this).toggleClass('collapsed'); | |
810 | }); | |
811 | }; | |
812 | })(jQuery); |