xref: /webtrees/app/Module/ClippingsCartModule.php (revision 28dbc609fe8399f6cf632e89bb356bba2436b4d4)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2018 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16namespace Fisharebest\Webtrees\Module;
17
18use Fisharebest\Webtrees\Auth;
19use Fisharebest\Webtrees\Controller\PageController;
20use Fisharebest\Webtrees\Family;
21use Fisharebest\Webtrees\Filter;
22use Fisharebest\Webtrees\GedcomRecord;
23use Fisharebest\Webtrees\Html;
24use Fisharebest\Webtrees\I18N;
25use Fisharebest\Webtrees\Individual;
26use Fisharebest\Webtrees\Menu;
27use Fisharebest\Webtrees\Module;
28use Fisharebest\Webtrees\Module\ClippingsCart\ClippingsCartController;
29use Fisharebest\Webtrees\Session;
30use Fisharebest\Webtrees\Tree;
31
32/**
33 * Class ClippingsCartModule
34 */
35class ClippingsCartModule extends AbstractModule implements ModuleMenuInterface, ModuleSidebarInterface {
36	/** {@inheritdoc} */
37	public function getTitle() {
38		return /* I18N: Name of a module */
39			I18N::translate('Clippings cart');
40	}
41
42	/** {@inheritdoc} */
43	public function getDescription() {
44		return /* I18N: Description of the “Clippings cart” module */
45			I18N::translate('Select records from your family tree and save them as a GEDCOM file.');
46	}
47
48	/**
49	 * What is the default access level for this module?
50	 *
51	 * Some modules are aimed at admins or managers, and are not generally shown to users.
52	 *
53	 * @return int
54	 */
55	public function defaultAccessLevel() {
56		return Auth::PRIV_USER;
57	}
58
59	/**
60	 * This is a general purpose hook, allowing modules to respond to routes
61	 * of the form module.php?mod=FOO&mod_action=BAR
62	 *
63	 * @param string $mod_action
64	 */
65	public function modAction($mod_action) {
66		global $WT_TREE;
67
68		// Only allow access if either the menu or sidebar is enabled.
69		if (
70			!array_key_exists($this->getName(), Module::getActiveSidebars($WT_TREE)) &&
71			!array_key_exists($this->getName(), Module::getActiveMenus($WT_TREE))
72		) {
73			http_response_code(404);
74
75			return;
76		}
77
78		switch ($mod_action) {
79			case 'ajax':
80				$html = $this->getSidebarAjaxContent();
81				header('Content-Type: text/html; charset=UTF-8');
82				echo $html;
83				break;
84			case 'index':
85				global $controller, $WT_TREE;
86
87				$MAX_PEDIGREE_GENERATIONS = $WT_TREE->getPreference('MAX_PEDIGREE_GENERATIONS');
88
89				$clip_ctrl = new ClippingsCartController;
90				$cart      = Session::get('cart');
91
92				$controller = new PageController;
93				$controller
94					->setPageTitle($this->getTitle())
95					->pageHeader();
96
97				echo '<script>';
98				echo 'function radAncestors(elementid) {var radFamilies=document.getElementById(elementid);radFamilies.checked=true;}';
99				echo '</script>';
100				echo '<div class="clipping-cart">';
101
102				if (!$cart[$WT_TREE->getTreeId()]) {
103					echo '<h2>', I18N::translate('Family tree clippings cart'), '</h2>';
104				}
105
106				if ($clip_ctrl->action == 'add') {
107					$record = GedcomRecord::getInstance($clip_ctrl->id, $WT_TREE);
108					if ($clip_ctrl->type === 'FAM') { ?>
109					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" action="module.php">
110						<input type="hidden" name="mod" value="clippings">
111						<input type="hidden" name="mod_action" value="index">
112						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
113						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
114						<input type="hidden" name="action" value="add1">
115						<table class="add-to center">
116							<thead>
117								<tr>
118									<td class="topbottombar">
119										<?= I18N::translate('Add to the clippings cart') ?>
120									</td>
121								</tr>
122							</thead>
123							<tbody>
124								<tr>
125									<td class="optionbox">
126										<input type="radio" name="others" value="parents">
127										<?= $record->getFullName() ?>
128									</td>
129								</tr>
130								<tr>
131									<td class="optionbox">
132										<input type="radio" name="others" value="members" checked>
133										<?= /* I18N: %s is a family (husband + wife) */
134											I18N::translate('%s and their children', $record->getFullName()) ?>
135									</td>
136								</tr>
137								<tr>
138									<td class="optionbox">
139										<input type="radio" name="others" value="descendants">
140										<?= /* I18N: %s is a family (husband + wife) */
141											I18N::translate('%s and their descendants', $record->getFullName()) ?>
142									</td>
143								</tr>
144							</tbody>
145							<tfoot>
146								<tr>
147									<td class="topbottombar"><input type="submit" value="<?= I18N::translate('continue') ?>">
148									</td>
149								</tr>
150							</tfoot>
151						</table>
152					</form>
153				</div>
154				<?php } elseif ($clip_ctrl->type === 'INDI') { ?>
155					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" action="module.php">
156						<input type="hidden" name="mod" value="clippings">
157						<input type="hidden" name="mod_action" value="index">
158						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
159						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
160						<input type="hidden" name="action" value="add1">
161						<table class="add-to center">
162							<thead>
163								<tr>
164									<td class="topbottombar">
165										<?= I18N::translate('Add to the clippings cart') ?>
166									</td>
167								</tr>
168							</thead>
169							<tbody>
170								<tr>
171									<td class="optionbox">
172										<label>
173											<input type="radio" name="others" checked value="none">
174											<?= $record->getFullName() ?>
175										</label>
176									</td>
177								</tr>
178								<tr>
179									<td class="optionbox">
180										<label>
181											<input type="radio" name="others" value="parents">
182											<?php
183												if ($record->getSex() === 'F') {
184													echo /* I18N: %s is a woman's name */
185													I18N::translate('%s, her parents and siblings', $record->getFullName());
186												} else {
187													echo /* I18N: %s is a man's name */
188													I18N::translate('%s, his parents and siblings', $record->getFullName());
189												}
190												?>
191										</label>
192									</td>
193								</tr>
194								<tr>
195									<td class="optionbox">
196										<label>
197											<input type="radio" name="others" value="members">
198											<?php
199												if ($record->getSex() === 'F') {
200													echo /* I18N: %s is a woman's name */
201													I18N::translate('%s, her spouses and children', $record->getFullName());
202												} else {
203													echo /* I18N: %s is a man's name */
204													I18N::translate('%s, his spouses and children', $record->getFullName());
205												}
206												?>
207										</label>
208									</td>
209								</tr>
210								<tr>
211									<td class="optionbox">
212										<label>
213											<input type="radio" name="others" value="ancestors" id="ancestors">
214											<?php
215												if ($record->getSex() === 'F') {
216													echo /* I18N: %s is a woman's name */
217													I18N::translate('%s and her ancestors', $record->getFullName());
218												} else {
219													echo /* I18N: %s is a man's name */
220													I18N::translate('%s and his ancestors', $record->getFullName());
221												}
222												?>
223										</label>
224										<br>
225										<?= I18N::translate('Number of generations') ?>
226											<input type="text" size="5" name="level1" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestors');">
227									</td>
228								</tr>
229								<tr>
230									<td class="optionbox">
231										<label>
232											<input type="radio" name="others" value="ancestorsfamilies" id="ancestorsfamilies">
233											<?php
234												if ($record->getSex() === 'F') {
235													echo /* I18N: %s is a woman's name */
236													I18N::translate('%s, her ancestors and their families', $record->getFullName());
237												} else {
238													echo /* I18N: %s is a man's name */
239													I18N::translate('%s, his ancestors and their families', $record->getFullName());
240												}
241												?>
242										</label>
243										<br>
244										<?= I18N::translate('Number of generations') ?>
245											<input type="text" size="5" name="level2" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestorsfamilies');">
246									</td>
247								</tr>
248								<tr>
249									<td class="optionbox">
250										<label>
251											<input type="radio" name="others" value="descendants" id="descendants">
252											<?php
253												if ($record->getSex() === 'F') {
254													echo /* I18N: %s is a woman's name */
255													I18N::translate('%s, her spouses and descendants', $record->getFullName());
256												} else {
257													echo /* I18N: %s is a man's name */
258													I18N::translate('%s, his spouses and descendants', $record->getFullName());
259												}
260												?>
261										</label>
262										<br>
263										<?= I18N::translate('Number of generations') ?>
264											<input type="text" size="5" name="level3" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('descendants');">
265									</td>
266								</tr>
267							</tbody>
268							<tfoot>
269								<tr>
270									<td class="topbottombar">
271										<input type="submit" value="<?= I18N::translate('continue') ?>">
272									</td>
273								</tr>
274							</tfoot>
275						</table>
276					</form>
277				</div>
278				<?php } elseif ($clip_ctrl->type === 'SOUR') { ?>
279					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" action="module.php">
280						<input type="hidden" name="mod" value="clippings">
281						<input type="hidden" name="mod_action" value="index">
282						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
283						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
284						<input type="hidden" name="action" value="add1">
285						<table class="add-to center">
286							<thead>
287								<tr>
288									<td class="topbottombar">
289										<?= I18N::translate('Add to the clippings cart') ?>
290									</td>
291								</tr>
292							</thead>
293							<tbody>
294								<tr>
295									<td class="optionbox">
296										<label>
297											<input type="radio" name="others" checked value="none">
298											<?= $record->getFullName() ?>
299										</label>
300									</td>
301								</tr>
302								<tr>
303									<td class="optionbox">
304										<label>
305											<input type="radio" name="others" value="linked">
306											<?= /* I18N: %s is the name of a source */
307												I18N::translate('%s and the individuals that reference it.', $record->getFullName()) ?>
308										</label>
309									</td>
310								</tr>
311							</tbody>
312							<tfoot>
313								<tr>
314									<td class="topbottombar">
315										<input type="submit" value="<?= I18N::translate('continue') ?>">
316									</td>
317								</tr>
318							</tfoot>
319						</table>
320					</form>
321				</div>
322				<?php }
323				}
324
325				if (!$cart[$WT_TREE->getTreeId()]) {
326					if ($clip_ctrl->action != 'add') {
327						echo '<div class="center">';
328						echo I18N::translate('The clippings cart allows you to take extracts from this family tree and download them as a GEDCOM file.');
329						echo '</div>';
330						?>
331					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" name="addin" action="module.php">
332						<input type="hidden" name="mod" value="clippings">
333						<input type="hidden" name="mod_action" value="index">
334						<table class="add-to center">
335							<thead>
336								<tr>
337									<td colspan="2" class="topbottombar">
338										<?= I18N::translate('Add to the clippings cart') ?>
339									</td>
340								</tr>
341							</thead>
342							<tbody>
343								<tr>
344									<td class="optionbox">
345										<input type="hidden" name="action" value="add">
346										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="5">
347									</td>
348									<td class="optionbox">
349										<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
350									</td>
351								</tr>
352							</tbody>
353						</table>
354					</form>
355				</div>
356					<?php
357					}
358					echo '<div class="center">';
359					// -- end new lines
360					echo I18N::translate('Your clippings cart is empty.');
361					echo '</div>';
362				} else {
363					// Keep track of the INDI from the parent page, otherwise it will
364					// get lost after ajax updates
365					$pid = Filter::get('pid', WT_REGEX_XREF);
366
367					if ($clip_ctrl->action !== 'download' && $clip_ctrl->action !== 'add') { ?>
368					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" action="module.php">
369						<input type="hidden" name="mod" value="clippings">
370						<input type="hidden" name="mod_action" value="index">
371						<input type="hidden" name="action" value="download">
372						<input type="hidden" name="pid" value="<?= $pid ?>">
373						<table class="add-to center">
374							<tr>
375								<td colspan="2" class="topbottombar">
376									<h2><?= I18N::translate('Download') ?></h2>
377								</td>
378							</tr>
379							<?php if (Auth::isManager($WT_TREE)) { ?>
380								<tr>
381									<td class="descriptionbox width50 wrap">
382										<?= I18N::translate('Apply privacy settings') ?>
383									</td>
384									<td class="optionbox">
385										<input type="radio" name="privatize_export" value="none" checked>
386										<?= I18N::translate('None') ?>
387										<br>
388										<input type="radio" name="privatize_export" value="gedadmin">
389										<?= I18N::translate('Manager') ?>
390										<br>
391										<input type="radio" name="privatize_export" value="user">
392										<?= I18N::translate('Member') ?>
393										<br>
394										<input type="radio" name="privatize_export" value="visitor">
395										<?= I18N::translate('Visitor') ?>
396									</td>
397								</tr>
398							<?php } elseif (Auth::isMember($WT_TREE)) { ?>
399								<tr>
400									<td class="descriptionbox width50 wrap">
401										<?= I18N::translate('Apply privacy settings') ?>
402									</td>
403									<td class="optionbox">
404										<input type="radio" name="privatize_export" value="user" checked> <?= I18N::translate('Member') ?><br>
405										<input type="radio" name="privatize_export" value="visitor"> <?= I18N::translate('Visitor') ?>
406									</td>
407								</tr>
408							<?php } ?>
409
410							<tr>
411								<td class="descriptionbox width50 wrap">
412									<?= I18N::translate('Convert from UTF-8 to ISO-8859-1') ?>
413								</td>
414								<td class="optionbox">
415									<input type="checkbox" name="convert" value="yes">
416								</td>
417							</tr>
418
419							<tr>
420								<td class="topbottombar" colspan="2">
421									<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('download') ?>">
422								</td>
423							</tr>
424						</table>
425					</form>
426				</div>
427					<br>
428
429					<form class="wt-page-options wt-page-options-clipping-cart hidden-print" name="addin" action="module.php">
430						<input type="hidden" name="mod" value="clippings">
431						<input type="hidden" name="mod_action" value="index">
432						<table class="add-to center">
433							<thead>
434								<tr>
435									<td colspan="2" class="topbottombar" style="text-align:center; ">
436										<?= I18N::translate('Add to the clippings cart') ?>
437									</td>
438								</tr>
439							</thead>
440							<tbody>
441								<tr>
442									<td class="optionbox">
443										<input type="hidden" name="action" value="add">
444										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="8">
445									</td>
446									<td class="optionbox">
447										<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
448									</td>
449								</tr>
450							</tbody>
451							<tfoot>
452								<tr>
453									<th colspan="2">
454										<a href="module.php?mod=clippings&amp;mod_action=index&amp;action=empty">
455											<?= I18N::translate('Empty the clippings cart') ?>
456										</a>
457									</th>
458								</tr>
459							</tfoot>
460						</table>
461					</form>
462				</div>
463				<?php } ?>
464				<div class="clipping-cart">
465				<h2>
466					<?= I18N::translate('Family tree clippings cart') ?>
467				</h2>
468				<table id="mycart" class="sortable list_table width50">
469					<thead>
470						<tr>
471							<th class="list_label"><?= I18N::translate('Record') ?></th>
472							<th class="list_label"><?= I18N::translate('Remove') ?></th>
473						</tr>
474					</thead>
475					<tbody>
476						<?php
477							foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
478								$record = GedcomRecord::getInstance($xref, $WT_TREE);
479								if ($record) {
480									switch ($record::RECORD_TYPE) {
481										case 'INDI':
482											$icon = 'icon-indis';
483											break;
484										case 'FAM':
485											$icon = 'icon-sfamily';
486											break;
487										case 'SOUR':
488											$icon = 'icon-source';
489											break;
490										case 'REPO':
491											$icon = 'icon-repository';
492											break;
493										case 'NOTE':
494											$icon = 'icon-note';
495											break;
496										case 'OBJE':
497											$icon = 'icon-media';
498											break;
499										default:
500											$icon = 'icon-clippings';
501											break;
502									}
503								?>
504								<tr>
505									<td class="list_value">
506										<i class="<?= $icon ?>"></i>
507										<?php
508										echo '<a href="', e($record->url()), '">', $record->getFullName(), '</a>';
509										?>
510									</td>
511									<td class="list_value center vmiddle"><a href="module.php?mod=clippings&amp;mod_action=index&amp;action=remove&amp;id=<?= $xref ?>" class="icon-remove" title="<?= I18N::translate('Remove') ?>"></a></td>
512								</tr>
513								<?php
514							}
515						}
516						?>
517				</table>
518			</div>
519				<?php
520			}
521			break;
522			default:
523				http_response_code(404);
524				break;
525		}
526	}
527
528	/**
529	 * The user can re-order menus. Until they do, they are shown in this order.
530	 *
531	 * @return int
532	 */
533	public function defaultMenuOrder() {
534		return 20;
535	}
536
537	/**
538	 * A menu, to be added to the main application menu.
539	 *
540	 * @param Tree $tree
541	 *
542	 * @return Menu|null
543	 */
544	public function getMenu(Tree $tree) {
545		global $controller;
546
547		$submenus = [];
548		if (isset($controller->record)) {
549			$submenus[] = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $tree->getNameUrl(), 'menu-clippings-cart', ['rel' => 'nofollow']);
550		}
551		if (!empty($controller->record) && $controller->record->canShow()) {
552			$submenus[] = new Menu(I18N::translate('Add to the clippings cart'), 'module.php?mod=clippings&amp;mod_action=index&amp;action=add&amp;id=' . $controller->record->getXref(), 'menu-clippings-add', ['rel' => 'nofollow']);
553		}
554
555		if ($submenus) {
556			return new Menu($this->getTitle(), '#', 'menu-clippings', ['rel' => 'nofollow'], $submenus);
557		} else {
558			return new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $tree->getNameUrl(), 'menu-clippings', ['rel' => 'nofollow']);
559		}
560	}
561
562	/** {@inheritdoc} */
563	public function defaultSidebarOrder() {
564		return 60;
565	}
566
567	/** {@inheritdoc} */
568	public function hasSidebarContent(Individual $individual) {
569		// Creating a controller has the side effect of initialising the cart
570		new ClippingsCartController;
571
572		return true;
573	}
574
575	/**
576	 * Load this sidebar synchronously.
577	 *
578	 * @param Individual $individual
579	 *
580	 * @return string
581	 */
582	public function getSidebarContent(Individual $individual) {
583		global $controller;
584
585		$controller->addInlineJavascript('
586				$("#sb_clippings_content").on("click", ".add_cart, .remove_cart", function() {
587					$("#sb_clippings_content").load(this.href);
588					return false;
589				});
590			');
591
592		return '<div id="sb_clippings_content">' . $this->getCartList() . '</div>';
593	}
594
595	/** {@inheritdoc} */
596	public function getSidebarAjaxContent() {
597		global $WT_TREE;
598
599		$cart = Session::get('cart');
600
601		$clip_ctrl         = new ClippingsCartController;
602		$add               = Filter::get('add', WT_REGEX_XREF);
603		$add1              = Filter::get('add1', WT_REGEX_XREF);
604		$remove            = Filter::get('remove', WT_REGEX_XREF);
605		$others            = Filter::get('others');
606		$clip_ctrl->level1 = Filter::getInteger('level1');
607		$clip_ctrl->level2 = Filter::getInteger('level2');
608		$clip_ctrl->level3 = Filter::getInteger('level3');
609		if ($add) {
610			$record = GedcomRecord::getInstance($add, $WT_TREE);
611			if ($record) {
612				$clip_ctrl->id   = $record->getXref();
613				$clip_ctrl->type = $record::RECORD_TYPE;
614				$clip_ctrl->addClipping($record);
615			}
616		} elseif ($add1) {
617			$record = Individual::getInstance($add1, $WT_TREE);
618			if ($record) {
619				$clip_ctrl->id   = $record->getXref();
620				$clip_ctrl->type = $record::RECORD_TYPE;
621				if ($others == 'parents') {
622					foreach ($record->getChildFamilies() as $family) {
623						$clip_ctrl->addClipping($family);
624						$clip_ctrl->addFamilyMembers($family);
625					}
626				} elseif ($others == 'ancestors') {
627					$clip_ctrl->addAncestorsToCart($record, $clip_ctrl->level1);
628				} elseif ($others == 'ancestorsfamilies') {
629					$clip_ctrl->addAncestorsToCartFamilies($record, $clip_ctrl->level2);
630				} elseif ($others == 'members') {
631					foreach ($record->getSpouseFamilies() as $family) {
632						$clip_ctrl->addClipping($family);
633						$clip_ctrl->addFamilyMembers($family);
634					}
635				} elseif ($others == 'descendants') {
636					foreach ($record->getSpouseFamilies() as $family) {
637						$clip_ctrl->addClipping($family);
638						$clip_ctrl->addFamilyDescendancy($family, $clip_ctrl->level3);
639					}
640				}
641			}
642		} elseif ($remove) {
643			unset($cart[$WT_TREE->getTreeId()][$remove]);
644			Session::put('cart', $cart);
645		} elseif (isset($_REQUEST['empty'])) {
646			$cart[$WT_TREE->getTreeId()] = [];
647			Session::put('cart', $cart);
648		} elseif (isset($_REQUEST['download'])) {
649			return $this->downloadForm();
650		}
651
652		return $this->getCartList();
653	}
654
655	/**
656	 * A list for the side bar.
657	 *
658	 * @return string
659	 */
660	public function getCartList() {
661		global $WT_TREE;
662
663		$cart = Session::get('cart', []);
664		if (!array_key_exists($WT_TREE->getTreeId(), $cart)) {
665			$cart[$WT_TREE->getTreeId()] = [];
666		}
667		$pid = Filter::get('pid', WT_REGEX_XREF);
668
669		if (!$cart[$WT_TREE->getTreeId()]) {
670			$out = I18N::translate('Your clippings cart is empty.');
671		} else {
672			$out = '';
673			if (!empty($cart[$WT_TREE->getTreeId()])) {
674				$out .=
675					'<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;empty=true&amp;pid=' . $pid . '" class="remove_cart">' .
676					I18N::translate('Empty the clippings cart') .
677					'</a>' .
678					'<br>' .
679					'<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;download=true&amp;pid=' . $pid . '" class="add_cart">' .
680					I18N::translate('Download') .
681					'</a><br><br>';
682			}
683			$out .= '<ul>';
684			foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
685				$record = GedcomRecord::getInstance($xref, $WT_TREE);
686				if ($record instanceof Individual || $record instanceof Family) {
687					switch ($record::RECORD_TYPE) {
688						case 'INDI':
689							$icon = 'icon-indis';
690							break;
691						case 'FAM':
692							$icon = 'icon-sfamily';
693							break;
694					}
695					$out .= '<li>';
696					if (!empty($icon)) {
697						$out .= '<i class="' . $icon . '"></i>';
698					}
699					$out .= '<a href="' . e($record->url()) . '">';
700					if ($record instanceof Individual) {
701						$out .= $record->getSexImage();
702					}
703					$out .= ' ' . $record->getFullName() . ' ';
704					if ($record instanceof Individual && $record->canShow()) {
705						$out .= ' (' . $record->getLifeSpan() . ')';
706					}
707					$out .= '</a>';
708					$out .= '<a class="icon-remove remove_cart" href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;remove=' . $xref . '&amp;pid=' . $pid . '" title="' . I18N::translate('Remove') . '"></a>';
709					$out .= '</li>';
710				}
711			}
712			$out .= '</ul>';
713		}
714
715		$record = Individual::getInstance($pid, $WT_TREE);
716		if ($record && !array_key_exists($record->getXref(), $cart[$WT_TREE->getTreeId()])) {
717			$out .= '<br><a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;action=add1&amp;type=INDI&amp;id=' . $pid . '&amp;pid=' . $pid . '" class="add_cart"><i class="icon-clippings"></i> ' . I18N::translate('Add %s to the clippings cart', $record->getFullName()) . '</a>';
718		}
719
720		return $out;
721	}
722
723	/**
724	 * A form to choose the download options.
725	 *
726	 * @return string
727	 */
728	public function downloadForm() {
729		global $WT_TREE;
730
731		$pid = Filter::get('pid', WT_REGEX_XREF);
732
733		$out = '<script>';
734		$out .= 'function cancelDownload() {
735				var link = "module.php?mod=' . $this->getName() . '&mod_action=ajax&pid=' . $pid . '";
736				$("#sb_clippings_content").load(link);
737			}';
738		$out .= '</script>';
739		$out .= '<form class="wt-page-options wt-page-options-clipping-cart hidden-print" action="module.php">
740		<input type="hidden" name="mod" value="clippings">
741		<input type="hidden" name="mod_action" value="index">
742		<input type="hidden" name="pid" value="' . $pid . '">
743		<input type="hidden" name="action" value="download">
744		<table>
745		<tr><td colspan="2" class="topbottombar"><h2>' . I18N::translate('Download') . '</h2></td></tr>
746		';
747
748		if (Auth::isManager($WT_TREE)) {
749			$out .=
750				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
751				'<td class="optionbox">' .
752				'<input type="radio" name="privatize_export" value="none" checked> ' . I18N::translate('None') . '<br>' .
753				'<input type="radio" name="privatize_export" value="gedadmin"> ' . I18N::translate('Manager') . '<br>' .
754				'<input type="radio" name="privatize_export" value="user"> ' . I18N::translate('Member') . '<br>' .
755				'<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
756				'</td></tr>';
757		} elseif (Auth::isMember($WT_TREE)) {
758			$out .=
759				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
760				'<td class="list_value">' .
761				'<input type="radio" name="privatize_export" value="user" checked> ' . I18N::translate('Member') . '<br>' .
762				'<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
763				'</td></tr>';
764		}
765
766		$out .= '
767		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Convert from UTF-8 to ISO-8859-1') . '</td>
768		<td class="optionbox"><input type="checkbox" name="convert" value="yes"></td></tr>
769
770		<tr><td class="topbottombar" colspan="2">
771		<input type="button" class="btn btn-secondary" value="' . /* I18N: A button label. */ I18N::translate('cancel') . '" onclick="cancelDownload();">
772		<input type="submit" class="btn btn-primary" value="' . /* I18N: A button label. */ I18N::translate('download') . '">
773		</form>';
774
775		return $out;
776	}
777}
778