Update documetnation so it makes sense when setting is disabled
[civicrm-core.git] / templates / CRM / Contact / Form / Merge.tpl
1 {*
2 +--------------------------------------------------------------------+
3 | CiviCRM version 4.7 |
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC (c) 2004-2018 |
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 <div class="crm-block crm-form-block crm-contact-merge-form-block">
27 <div class="help">
28 {ts}Click <strong>Merge</strong> to move data from the Duplicate Contact on the left into the Main Contact. In addition to the contact data (address, phone, email...), you may choose to move all or some of the related activity records (groups, contributions, memberships, etc.).{/ts} {help id="intro"}
29 </div>
30
31 <div class="message status">
32 <div class="icon inform-icon"></div>
33 <strong>{ts}WARNING: The duplicate contact record WILL BE DELETED after the merge is complete.{/ts}</strong>
34 </div>
35
36 {if $user}
37 <div class="message status">
38 <div class="icon inform-icon"></div>
39 <strong>{ts 1=$config->userFramework}WARNING: There are %1 user accounts associated with both the original and duplicate contacts. Ensure that the %1 user you want to retain is on the right - if necessary use the 'Flip between original and duplicate contacts.' option at top to swap the positions of the two records before doing the merge.
40 The user record associated with the duplicate contact will not be deleted, but will be unlinked from the associated contact record (which will be deleted).
41 You will need to manually delete that user (click on the link to open the %1 user account in new screen). You may need to give thought to how you handle any content or contents associated with that user.{/ts}</strong>
42 </div>
43 {/if}
44
45 <div class="crm-submit-buttons">
46 {include file="CRM/common/formButtons.tpl" location="top"}
47 </div>
48
49 <div class="action-link">
50 {if $prev}<a href="{$prev}" class="crm-hover-button action-item"><i class="crm-i fa-chevron-left"></i> {ts}Previous{/ts}</a>{/if}
51 {if $next}<a href="{$next}" class="crm-hover-button action-item">{ts}Next{/ts} <i class="crm-i fa-chevron-right"></i></a>{/if}
52 <a href="{$flip}" class="action-item crm-hover-button">
53 <i class="crm-i fa-random"></i>
54 {ts}Flip between original and duplicate contacts.{/ts}
55 </a>
56 </div>
57
58 <div class="action-link">
59 <a href="#" class="action-item crm-hover-button crm-notDuplicate" title={ts}Mark this pair as not a duplicate.{/ts} onClick="processDupes( {$main_cid}, {$other_cid}, 'dupe-nondupe', 'merge-contact', '{$browseUrl}' );return false;">
60 <i class="crm-i fa-times-circle"></i>
61 {ts}Mark this pair as not a duplicate.{/ts}
62 </a>
63 </div>
64
65 <div class="action-link">
66 <a href="javascript:void(0);" class="action-item crm-hover-button toggle_equal_rows">
67 <i class="crm-i fa-eye-slash"></i>
68 {ts}Show/hide rows with the same data on each contact record.{/ts}
69 </a>
70 </div>
71
72 <table class="row-highlight">
73 <tr class="columnheader">
74 <th>&nbsp;</th>
75 <th><a href="{crmURL p='civicrm/contact/view' q="reset=1&cid=$other_cid"}">{$other_name}</a> ({ts}duplicate{/ts})</th>
76 <th>{ts}Mark All{/ts}<br />=={$form.toggleSelect.html} ==&gt;</th>
77 <th><a href="{crmURL p='civicrm/contact/view' q="reset=1&cid=$main_cid"}">{$main_name}</a></th>
78 <th width="300">Add/overwrite?</th>
79 </tr>
80
81 {crmAPI var='other_result' entity='Contact' action='get' return="modified_date" id=$other_cid}
82
83 {crmAPI var='main_result' entity='Contact' action='get' return="modified_date" id=$main_cid}
84
85 <tr>
86 <td>Last modified</td>
87 <td>{$other_result.values.0.modified_date|crmDate} {if $other_result.values.0.modified_date gt $main_result.values.0.modified_date} (Most recent) {/if}</td>
88 <td></td>
89 <td>{$main_result.values.0.modified_date|crmDate} {if $main_result.values.0.modified_date gt $other_result.values.0.modified_date} (Most recent) {/if}</td>
90 <td></td>
91 </tr>
92
93 {foreach from=$rows item=row key=field}
94
95 {if !isset($row.main) && !isset($row.other)}
96 <tr style="background-color: #fff !important; border-bottom:1px solid #ccc !important;" class="no-data">
97 <td>
98 <strong>{$row.title}</strong>
99 </td>
100 {else}
101 {if $row.main eq $row.other}
102 <tr class="merge-row-equal crm-row-ok {cycle values="odd-row,even-row"}">
103 {else}
104 <tr class="crm-row-error {cycle values="odd-row,even-row"}">
105 {/if}
106 <td>
107 {$row.title}
108 </td>
109 {/if}
110
111 {assign var=position value=$field|strrpos:'_'}
112 {assign var=blockId value=$field|substr:$position+1}
113 {assign var=blockName value=$field|substr:14:$position-14}
114
115 <td>
116 {* @TODO check if this is ever an array or a fileName? *}
117 {* This is on one long line for address formatting *}
118 {if $row.title|substr:0:7 == "Address"}<span style="white-space: pre">{else}<span>{/if}{if !is_array($row.other)}{$row.other}{elseif $row.other.fileName}{$row.other.fileName}{else}{', '|implode:$row.other}{/if}</span>
119 </td>
120
121 <td style='white-space: nowrap'>
122 {if $form.$field}=={$form.$field.html|crmAddClass:"select-row"}==&gt;{/if}
123 </td>
124
125 {* For location blocks *}
126 {if $row.title|substr:0:5 == "Email" OR
127 $row.title|substr:0:7 == "Address" OR
128 $row.title|substr:0:2 == "IM" OR
129 $row.title|substr:0:7 == "Website" OR
130 $row.title|substr:0:5 == "Phone"}
131
132 <td>
133 {strip}
134 {if $row.title|substr:0:7 == "Address"}
135 <span style="white-space: pre" id="main_{$blockName}_{$blockId}">
136 {else}
137 <span id="main_{$blockName}_{$blockId}">
138 {/if}
139 {* @TODO check if this is ever an array or a fileName? *}
140 {if !is_array($row.main)}
141 {$row.main}
142 {elseif $row.main.fileName}
143 {$row.main.fileName}
144 {else}
145 {', '|implode:$row.main}
146 {/if}
147 </span>
148 {/strip}
149 </td>
150
151 <td>
152 {* Display location for fields with locations *}
153 {if $blockName eq 'email' || $blockName eq 'phone' || $blockName eq 'address' || $blockName eq 'im' }
154 {$form.location_blocks.$blockName.$blockId.locTypeId.html}&nbsp;
155 {/if}
156
157 {* Display other_type_id for websites, ims and phones *}
158 {if $blockName eq 'website' || $blockName eq 'im' || $blockName eq 'phone' }
159 {$form.location_blocks.$blockName.$blockId.typeTypeId.html}&nbsp;
160 {/if}
161
162 {* Display the overwrite/add/add new label *}
163 <span id="main_{$blockName}_{$blockId}_overwrite" class="location_block_controls">
164
165 <span class="location_primary">
166 {if $row.main && $row.main_is_primary == "1"}Primary{/if}
167 </span>
168
169 <span class="location_block_controls_options">
170 <span class="location_operation_description">
171 {if $row.main}({ts}overwrite{/ts}){else}({ts}add{/ts}){/if}
172 </span>
173 <span style="display: block" class="location_operation_checkbox">
174 {if $row.main && ($blockName eq 'email' || $blockName eq 'phone')}
175 {$form.location_blocks.$blockName.$blockId.operation.html}
176 {/if}
177 </span>
178 <span style="display: block" class="location_set_other_primary">
179 {if $blockName neq 'website' && (($row.main && $row.main_is_primary != "1") || !$row.main)}
180 {$form.location_blocks.$blockName.$blockId.set_other_primary.html}
181 {/if}
182 </span>
183 </span>
184 </span>
185
186 </td>
187
188 {* For non-location blocks *}
189 {else}
190
191 <td>
192 <span>
193 {if !is_array($row.main)}
194 {$row.main}
195 {elseif $row.main.fileName}
196 {$row.main.fileName}
197 {else}
198 {', '|implode:$row.main}
199 {/if}
200 </span>
201 </td>
202
203 <td>
204 {if isset($row.main) || isset($row.other)}
205 <span>
206 {if $row.main == $row.other}
207 <span class="action_label">({ts}match{/ts})</span><br />
208 {elseif $row.main}
209 <span class="action_label">({ts}overwrite{/ts})</span><br />
210 {else}
211 <span class="action_label">({ts}add{/ts})</span>
212 {/if}
213 </span>
214 {/if}
215 </td>
216
217 {/if}
218
219 </tr>
220 {/foreach}
221
222 {foreach from=$rel_tables item=params key=paramName}
223 {if $paramName eq 'move_rel_table_users'}
224 <tr class="{cycle values="even-row,odd-row"}">
225 <td><strong>{ts}Move related...{/ts}</strong></td><td>{if $otherUfId}<a target="_blank" href="{$params.other_url}">{$otherUfName}</a></td><td style='white-space: nowrap'>=={$form.$paramName.html|crmAddClass:"select-row"}==&gt;{else}<td style='white-space: nowrap'></td>{/if}</td><td>{if $mainUfId}<a target="_blank" href="{$params.main_url}">{$mainUfName}</a>{/if}</td>
226 <td>({ts}migrate{/ts})</td>
227 </tr>
228 {else}
229 <tr class="{cycle values="even-row,odd-row"}">
230 <td><strong>{ts}Move related...{/ts}</strong></td><td><a href="{$params.other_url}">{$params.title}</a></td><td style='white-space: nowrap'>=={$form.$paramName.html|crmAddClass:"select-row"}==&gt;</td><td><a href="{$params.main_url}">{$params.title}</a>{if $form.operation.$paramName.add.html}&nbsp;{$form.operation.$paramName.add.html}{/if}</td>
231 <td>({ts}migrate{/ts})</td>
232 </tr>
233 {/if}
234 {/foreach}
235 </table>
236
237 <div class="crm-submit-buttons">
238 {include file="CRM/common/formButtons.tpl" location="bottom"}
239 </div>
240 </div>
241
242 {literal}
243 <script type="text/javascript">
244
245 var locationBlockInfo = {/literal}{$locationBlockInfo}{literal};
246 var allBlock = {/literal}{$mainLocBlock}{literal};
247
248 /**
249 * Triggered when a 'location' or 'type' destination is changed, and when
250 * the operation or 'set primary' checkboxes are changed.
251 *
252 * Check to see if the 'main' contact record has a corresponding location
253 * block when the destination of a field is changed. Allow existing location
254 * fields to be overwritten with data from the 'other' contact.
255 *
256 * @param blockName string
257 * The name of the entity.
258 * @param blockId int
259 * The block ID being affected.
260 * @param event object
261 * The event that triggered the update.
262 */
263 function updateMainLocationBlock(blockName, blockId, event) {
264
265 // Get type of select list that's been changed (location or type)
266 var locTypeId = CRM.$('select#location_blocks_' + blockName + '_' + blockId + '_locTypeId').val();
267 var typeTypeId = CRM.$('select#location_blocks_' + blockName + '_' + blockId + '_typeTypeId').val();
268
269 // @todo Fix this 'special handling' for websites (no location id)
270 if (!locTypeId) {
271 locTypeId = 0;
272 }
273
274 // Look for a matching block on the main contact
275 var mainBlockId = 0;
276 var mainBlockDisplay = '';
277 var mainBlock = findBlock(blockName, locTypeId, typeTypeId);
278 if (mainBlock != false) {
279 mainBlockDisplay = mainBlock['display'];
280 mainBlockId = mainBlock['id'];
281 }
282
283 // Update main location display and id
284 CRM.$("input[name='location_blocks[" + blockName + "][" + blockId + "][mainContactBlockId]']").val(mainBlockId);
285 CRM.$("#main_" + blockName + "_" + blockId).html(mainBlockDisplay);
286
287 // Update controls area
288
289 // Get the parent block once for speed
290 var this_controls = CRM.$("#main_" + blockName + "_" + blockId + "_overwrite");
291
292 // Update primary label
293 if (mainBlock != false && mainBlock['is_primary'] == '1') {
294 this_controls.find(".location_primary").text('Primary');
295 }
296 else {
297 this_controls.find(".location_primary").text('');
298 }
299
300 // Update operation description
301 var operation_description = "{/literal}{ts}add{/ts}{literal}";
302 var add_new_check_length = this_controls.find(".location_operation_checkbox input:checked").length;
303 if (mainBlock != false) {
304 if (add_new_check_length > 0) {
305 operation_description = "{/literal}{ts}add new{/ts}{literal}";
306 }
307 else {
308 operation_description = "{/literal}{ts}overwrite{/ts}{literal}";
309 }
310 }
311 this_controls.find(".location_operation_description").text("(" + operation_description + ")");
312
313 // Skip if the 'add new' or 'set primary' checkboxes were clicked
314 if (event.target.id.match(/(operation|set_other_primary)/) === null) {
315 // Display 'Add new' checkbox if there is a main block, and this is an
316 // email or phone type.
317 if (mainBlock != false && (blockName == 'email' || blockName == 'phone')) {
318 var op_id = 'location_blocks[' + blockName + '][' + blockId + '][operation]';
319 this_controls.find(".location_operation_checkbox").html(
320 '<input id="' + op_id + '" name="' + op_id + '" type="checkbox" value="1" class="crm-form-checkbox"><label for="' + op_id + '">{/literal}{ts}Add new{/ts}{literal}</label>'
321 );
322 }
323 else {
324 this_controls.find(".location_operation_checkbox").html('');
325 }
326 }
327
328 // Skip if 'set primary' was clicked
329 if (event.target.id.match(/(set_other_primary)/) === null) {
330 // Display 'Set primary' checkbox if applicable
331 if (blockName != 'website' && (mainBlock == false || mainBlock['is_primary'] != "1" || add_new_check_length > 0)) {
332 var prim_id = 'location_blocks[' + blockName + '][' + blockId + '][set_other_primary]';
333 this_controls.find(".location_set_other_primary").html(
334 '<input id="' + prim_id + '" name="' + prim_id + '" type="checkbox" value="1" class="crm-form-checkbox"><label for="' + prim_id + '">{/literal}{ts}Set as primary{/ts}{literal}</label>'
335 );
336 }
337 else {
338 this_controls.find(".location_set_other_primary").html('');
339 }
340 }
341
342 }
343
344 /**
345 * Look for a matching 'main' contact location block by entity, location and
346 * type
347 *
348 * @param entName string
349 * The entity name to lookup.
350 * @param locationID int
351 * The location ID to lookup.
352 * @param typeID int
353 * The type ID to lookup.
354 *
355 * @returns boolean|object
356 * Returns false if no match, otherwise an object with the location ID and
357 * display value.
358 */
359 function findBlock(entName, locationID, typeID) {
360 var entityArray = allBlock[entName];
361 var result = false;
362 for (var i = 0; i < entityArray.length; i++) {
363 // Match based on location and type ID, depending on the entity info
364 if (locationBlockInfo[entName]['hasLocation'] == false || locationID == entityArray[i]['location_type_id']) {
365 if (locationBlockInfo[entName]['hasType'] == false || typeID == entityArray[i][locationBlockInfo[entName]['hasType']]) {
366 result = {
367 display: entityArray[i][locationBlockInfo[entName]['displayField']],
368 id: entityArray[i]['id'],
369 is_primary: entityArray[i]['is_primary']
370 };
371 break;
372 }
373 }
374 }
375 return result;
376 }
377
378 /**
379 * Called when a 'set primary' checkbox is clicked in order to disable any
380 * other 'set primary' checkboxes for blocks of the same entity. So don't let
381 * users try to set two different phone numbers as primary on the form.
382 *
383 * @param event object
384 * The event that triggered the update
385 */
386 function updateSetPrimaries(event) {
387 var nameSplit = event.target.name.split('[');
388 var blockName = nameSplit[1].slice(0, -1);
389 var controls = CRM.$('span.location_block_controls[id^="main_' + blockName + '"]');
390
391 // Enable everything
392 controls.find('input[id$="[set_other_primary]"]:not(:checked)').removeAttr("disabled");
393
394 // If one is checked, disable the others
395 if (controls.find('input[id$="[set_other_primary]"]:checked').length > 0) {
396 controls.find('input[id$="[set_other_primary]"]:not(:checked)').attr("disabled", "disabled");
397 }
398 }
399
400 /**
401 * Toggle the location type and the is_primary on & off depending on whether the merge box is ticked.
402 *
403 * @param element
404 */
405 function toggleRelatedLocationFields(element) {
406 relatedElements = CRM.$(element).parent().siblings('td').find('input,select,label,hidden');
407 if (CRM.$(element).is(':checked')) {
408 relatedElements.removeClass('disabled').attr('disabled', false);
409
410 }
411 else {
412 relatedElements.addClass('disabled').attr('disabled', true);
413 }
414
415 }
416
417 CRM.$(function($) {
418 $('input.crm-form-checkbox[data-is_location]').on('click', function(){
419 toggleRelatedLocationFields(this)
420 });
421
422 // Show/hide matching data rows
423 $('.toggle_equal_rows').click(function() {
424 $('tr.merge-row-equal').toggle();
425 });
426
427 // Call mergeBlock whenever a location type is changed
428 // (This is applied to the body because the inputs can be added dynamically
429 // to the form, and we need to catch when they change.)
430 $('body').on('change', 'select[id$="locTypeId"],select[id$="typeTypeId"],input[id$="[operation]"],input[id$="[set_other_primary]"]', function(event){
431
432 // All the information we need is held in the id, separated by underscores
433 var nameSplit = this.name.split('[');
434
435 // Lookup the main value, if any are available
436 if (allBlock[nameSplit[1].slice(0, -1)] != undefined) {
437 updateMainLocationBlock(nameSplit[1].slice(0, -1), nameSplit[2].slice(0, -1), event);
438 }
439
440 // Update all 'set primary' checkboxes
441 updateSetPrimaries(event);
442
443 });
444
445 });
446
447 </script>
448 {/literal}
449
450 {* process the dupe contacts *}
451 {include file="CRM/common/dedupe.tpl"}