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