xref: /webtrees/app/Module/ClippingsCartModule.php (revision 047f239b70b792655dbaa183656298db216028ae)
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\GedcomRecord;
23use Fisharebest\Webtrees\Html;
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
83			echo '<script>';
84			echo 'function radAncestors(elementid) {var radFamilies=document.getElementById(elementid);radFamilies.checked=true;}';
85			echo '</script>';
86
87			if (!$cart[$WT_TREE->getTreeId()]) {
88				echo '<h2>', I18N::translate('Family tree clippings cart'), '</h2>';
89			}
90
91			if ($clip_ctrl->action == 'add') {
92				$record = GedcomRecord::getInstance($clip_ctrl->id, $WT_TREE);
93				if ($clip_ctrl->type === 'FAM') { ?>
94					<form action="module.php">
95						<input type="hidden" name="mod" value="clippings">
96						<input type="hidden" name="mod_action" value="index">
97						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
98						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
99						<input type="hidden" name="action" value="add1">
100						<table>
101							<thead>
102								<tr>
103									<td class="topbottombar">
104										<?= I18N::translate('Add to the clippings cart') ?>
105									</td>
106								</tr>
107							</thead>
108							<tbody>
109								<tr>
110									<td class="optionbox">
111										<input type="radio" name="others" value="parents">
112										<?= $record->getFullName() ?>
113									</td>
114								</tr>
115								<tr>
116									<td class="optionbox">
117										<input type="radio" name="others" value="members" checked>
118										<?= /* I18N: %s is a family (husband + wife) */
119										I18N::translate('%s and their children', $record->getFullName()) ?>
120									</td>
121								</tr>
122								<tr>
123									<td class="optionbox">
124										<input type="radio" name="others" value="descendants">
125										<?= /* I18N: %s is a family (husband + wife) */
126										I18N::translate('%s and their descendants', $record->getFullName()) ?>
127									</td>
128								</tr>
129							</tbody>
130							<tfoot>
131								<tr>
132									<td class="topbottombar"><input type="submit" value="<?= I18N::translate('continue') ?>">
133									</td>
134								</tr>
135							</tfoot>
136						</table>
137					</form>
138				<?php } elseif ($clip_ctrl->type === 'INDI') { ?>
139					<form action="module.php">
140						<input type="hidden" name="mod" value="clippings">
141						<input type="hidden" name="mod_action" value="index">
142						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
143						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
144						<input type="hidden" name="action" value="add1">
145						<table>
146							<thead>
147								<tr>
148									<td class="topbottombar">
149										<?= I18N::translate('Add to the clippings cart') ?>
150									</td>
151								</tr>
152							</thead>
153							<tbody>
154								<tr>
155									<td class="optionbox">
156										<label>
157											<input type="radio" name="others" checked value="none">
158											<?= $record->getFullName() ?>
159										</label>
160									</td>
161								</tr>
162								<tr>
163									<td class="optionbox">
164										<label>
165											<input type="radio" name="others" value="parents">
166											<?php
167											if ($record->getSex() === 'F') {
168												echo /* I18N: %s is a woman's name */
169												I18N::translate('%s, her parents and siblings', $record->getFullName());
170											} else {
171												echo /* I18N: %s is a man's name */
172												I18N::translate('%s, his parents and siblings', $record->getFullName());
173											}
174											?>
175										</label>
176									</td>
177								</tr>
178								<tr>
179									<td class="optionbox">
180										<label>
181											<input type="radio" name="others" value="members">
182											<?php
183											if ($record->getSex() === 'F') {
184												echo /* I18N: %s is a woman's name */
185												I18N::translate('%s, her spouses and children', $record->getFullName());
186											} else {
187												echo /* I18N: %s is a man's name */
188												I18N::translate('%s, his spouses and children', $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="ancestors" id="ancestors">
198											<?php
199											if ($record->getSex() === 'F') {
200												echo /* I18N: %s is a woman's name */
201												I18N::translate('%s and her ancestors', $record->getFullName());
202											} else {
203												echo /* I18N: %s is a man's name */
204												I18N::translate('%s and his ancestors', $record->getFullName());
205											}
206											?>
207										</label>
208										<br>
209										<?= I18N::translate('Number of generations') ?>
210										<input type="text" size="5" name="level1" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestors');">
211									</td>
212								</tr>
213								<tr>
214									<td class="optionbox">
215										<label>
216											<input type="radio" name="others" value="ancestorsfamilies" id="ancestorsfamilies">
217											<?php
218											if ($record->getSex() === 'F') {
219												echo /* I18N: %s is a woman's name */
220												I18N::translate('%s, her ancestors and their families', $record->getFullName());
221											} else {
222												echo /* I18N: %s is a man's name */
223												I18N::translate('%s, his ancestors and their families', $record->getFullName());
224											}
225											?>
226										</label>
227										<br>
228										<?= I18N::translate('Number of generations') ?>
229										<input type="text" size="5" name="level2" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('ancestorsfamilies');">
230									</td>
231								</tr>
232								<tr>
233									<td class="optionbox">
234										<label>
235											<input type="radio" name="others" value="descendants" id="descendants">
236											<?php
237											if ($record->getSex() === 'F') {
238												echo /* I18N: %s is a woman's name */
239												I18N::translate('%s, her spouses and descendants', $record->getFullName());
240											} else {
241												echo /* I18N: %s is a man's name */
242												I18N::translate('%s, his spouses and descendants', $record->getFullName());
243											}
244											?>
245										</label>
246										<br>
247										<?= I18N::translate('Number of generations') ?>
248										<input type="text" size="5" name="level3" value="<?= $MAX_PEDIGREE_GENERATIONS ?>" onfocus="radAncestors('descendants');">
249									</td>
250								</tr>
251							</tbody>
252							<tfoot>
253								<tr>
254									<td class="topbottombar">
255										<input type="submit" value="<?= I18N::translate('continue') ?>">
256									</td>
257								</tr>
258							</tfoot>
259						</table>
260					</form>
261				<?php } elseif ($clip_ctrl->type === 'SOUR') { ?>
262					<form action="module.php">
263						<input type="hidden" name="mod" value="clippings">
264						<input type="hidden" name="mod_action" value="index">
265						<input type="hidden" name="id" value="<?= $clip_ctrl->id ?>">
266						<input type="hidden" name="type" value="<?= $clip_ctrl->type ?>">
267						<input type="hidden" name="action" value="add1">
268						<table>
269							<thead>
270								<tr>
271									<td class="topbottombar">
272										<?= I18N::translate('Add to the clippings cart') ?>
273									</td>
274								</tr>
275							</thead>
276							<tbody>
277								<tr>
278									<td class="optionbox">
279										<label>
280											<input type="radio" name="others" checked value="none">
281											<?= $record->getFullName() ?>
282										</label>
283									</td>
284								</tr>
285								<tr>
286									<td class="optionbox">
287										<label>
288											<input type="radio" name="others" value="linked">
289											<?= /* I18N: %s is the name of a source */
290											I18N::translate('%s and the individuals that reference it.', $record->getFullName()) ?>
291										</label>
292									</td>
293								</tr>
294							</tbody>
295							<tfoot>
296								<tr>
297									<td class="topbottombar">
298										<input type="submit" value="<?= I18N::translate('continue') ?>">
299									</td>
300								</tr>
301							</tfoot>
302						</table>
303					</form>
304				<?php }
305			}
306
307			if (!$cart[$WT_TREE->getTreeId()]) {
308				if ($clip_ctrl->action != 'add') {
309					echo I18N::translate('The clippings cart allows you to take extracts from this family tree and download them as a GEDCOM file.');
310					?>
311					<form name="addin" action="module.php">
312						<input type="hidden" name="mod" value="clippings">
313						<input type="hidden" name="mod_action" value="index">
314						<table>
315							<thead>
316								<tr>
317									<td colspan="2" class="topbottombar">
318										<?= I18N::translate('Add to the clippings cart') ?>
319									</td>
320								</tr>
321							</thead>
322							<tbody>
323								<tr>
324									<td class="optionbox">
325										<input type="hidden" name="action" value="add">
326										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="5">
327									</td>
328									<td class="optionbox">
329										<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
330									</td>
331								</tr>
332							</tbody>
333						</table>
334					</form>
335					<?php
336				}
337
338				// -- end new lines
339				echo I18N::translate('Your clippings cart is empty.');
340			} else {
341				// Keep track of the INDI from the parent page, otherwise it will
342				// get lost after ajax updates
343				$pid = Filter::get('pid', WT_REGEX_XREF);
344
345				if ($clip_ctrl->action !== 'download' && $clip_ctrl->action !== 'add') { ?>
346					<form action="module.php">
347						<input type="hidden" name="mod" value="clippings">
348						<input type="hidden" name="mod_action" value="index">
349						<input type="hidden" name="action" value="download">
350						<input type="hidden" name="pid" value="<?= $pid ?>">
351						<table>
352							<tr>
353								<td colspan="2" class="topbottombar">
354									<h2><?= I18N::translate('Download') ?></h2>
355								</td>
356							</tr>
357							<tr>
358								<td class="descriptionbox width50 wrap">
359									<?= 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.') ?>
360								</td>
361								<td class="optionbox wrap">
362									<input type="checkbox" name="Zip" value="yes">
363									<?= I18N::translate('Zip file(s)') ?>
364								</td>
365							</tr>
366							<tr>
367								<td class="descriptionbox width50 wrap">
368									<?= I18N::translate('Include media (automatically zips files)') ?>
369								</td>
370								<td class="optionbox">
371									<input type="checkbox" name="IncludeMedia" value="yes">
372								</td>
373							</tr>
374
375							<?php if (Auth::isManager($WT_TREE)) { ?>
376								<tr>
377									<td class="descriptionbox width50 wrap">
378										<?= I18N::translate('Apply privacy settings') ?>
379									</td>
380									<td class="optionbox">
381										<input type="radio" name="privatize_export" value="none" checked>
382										<?= I18N::translate('None') ?>
383										<br>
384										<input type="radio" name="privatize_export" value="gedadmin">
385										<?= I18N::translate('Manager') ?>
386										<br>
387										<input type="radio" name="privatize_export" value="user">
388										<?= I18N::translate('Member') ?>
389										<br>
390										<input type="radio" name="privatize_export" value="visitor">
391										<?= I18N::translate('Visitor') ?>
392									</td>
393								</tr>
394							<?php } elseif (Auth::isMember($WT_TREE)) { ?>
395								<tr>
396									<td class="descriptionbox width50 wrap">
397										<?= I18N::translate('Apply privacy settings') ?>
398									</td>
399									<td class="optionbox">
400										<input type="radio" name="privatize_export" value="user" checked> <?= I18N::translate('Member') ?><br>
401										<input type="radio" name="privatize_export" value="visitor"> <?= I18N::translate('Visitor') ?>
402									</td>
403								</tr>
404							<?php } ?>
405
406							<tr>
407								<td class="descriptionbox width50 wrap">
408									<?= I18N::translate('Convert from UTF-8 to ISO-8859-1') ?>
409								</td>
410								<td class="optionbox">
411									<input type="checkbox" name="convert" value="yes">
412								</td>
413							</tr>
414
415							<tr>
416								<td class="descriptionbox width50 wrap">
417									<?= I18N::translate('Add the GEDCOM media path to filenames') ?>
418								</td>
419								<td class="optionbox">
420									<input type="checkbox" name="conv_path" value="<?= Html::escape($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) ?>">
421									<span dir="auto"><?= Html::escape($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) ?></span>
422								</td>
423							</tr>
424
425							<tr>
426								<td class="topbottombar" colspan="2">
427									<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('download') ?>">
428								</td>
429							</tr>
430						</table>
431					</form>
432					<br>
433
434					<form name="addin" action="module.php">
435						<input type="hidden" name="mod" value="clippings">
436						<input type="hidden" name="mod_action" value="index">
437						<table>
438							<thead>
439								<tr>
440									<td colspan="2" class="topbottombar" style="text-align:center; ">
441										<?= I18N::translate('Add to the clippings cart') ?>
442									</td>
443								</tr>
444							</thead>
445							<tbody>
446								<tr>
447									<td class="optionbox">
448										<input type="hidden" name="action" value="add">
449										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="8">
450									</td>
451									<td class="optionbox">
452										<input type="submit" value="<?= /* I18N: A button label. */ I18N::translate('add') ?>">
453									</td>
454								</tr>
455							</tbody>
456							<tfoot>
457								<tr>
458									<th colspan="2">
459										<a href="module.php?mod=clippings&amp;mod_action=index&amp;action=empty">
460											<?= I18N::translate('Empty the clippings cart') ?>
461										</a>
462									</th>
463								</tr>
464							</tfoot>
465						</table>
466					</form>
467
468				<?php } ?>
469
470				<h2>
471					<?= I18N::translate('Family tree clippings cart') ?>
472				</h2>
473				<table id="mycart" class="sortable list_table width100">
474					<thead>
475						<tr>
476							<th class="list_label"><?= I18N::translate('Record') ?></th>
477							<th class="list_label"><?= I18N::translate('Remove') ?></th>
478						</tr>
479					</thead>
480					<tbody>
481						<?php
482						foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
483							$record = GedcomRecord::getInstance($xref, $WT_TREE);
484							if ($record) {
485								switch ($record::RECORD_TYPE) {
486								case 'INDI':
487									$icon = 'icon-indis';
488									break;
489								case 'FAM':
490									$icon = 'icon-sfamily';
491									break;
492								case 'SOUR':
493									$icon = 'icon-source';
494									break;
495								case 'REPO':
496									$icon = 'icon-repository';
497									break;
498								case 'NOTE':
499									$icon = 'icon-note';
500									break;
501								case 'OBJE':
502									$icon = 'icon-media';
503									break;
504								default:
505									$icon = 'icon-clippings';
506									break;
507								}
508								?>
509								<tr>
510									<td class="list_value">
511										<i class="<?= $icon ?>"></i>
512										<?php
513										echo '<a href="', $record->getHtmlUrl(), '">', $record->getFullName(), '</a>';
514										?>
515									</td>
516									<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>
517								</tr>
518								<?php
519							}
520						}
521						?>
522				</table>
523				<?php
524			}
525			break;
526		default:
527			http_response_code(404);
528			break;
529		}
530	}
531
532	/**
533	 * The user can re-order menus. Until they do, they are shown in this order.
534	 *
535	 * @return int
536	 */
537	public function defaultMenuOrder() {
538		return 20;
539	}
540
541	/**
542	 * A menu, to be added to the main application menu.
543	 *
544	 * @return Menu|null
545	 */
546	public function getMenu() {
547		global $controller, $WT_TREE;
548
549		$submenus = [];
550		if (isset($controller->record)) {
551			$submenus[] = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippings-cart', ['rel' => 'nofollow']);
552		}
553		if (!empty($controller->record) && $controller->record->canShow()) {
554			$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']);
555		}
556
557		if ($submenus) {
558			return new Menu($this->getTitle(), '#', 'menu-clippings', ['rel' => 'nofollow'], $submenus);
559		} else {
560			return new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippings', ['rel' => 'nofollow']);
561		}
562	}
563
564	/** {@inheritdoc} */
565	public function defaultSidebarOrder() {
566		return 60;
567	}
568
569	/** {@inheritdoc} */
570	public function hasSidebarContent() {
571		// Creating a controller has the side effect of initialising the cart
572		new ClippingsCartController;
573
574		return true;
575	}
576
577	/**
578	 * Load this sidebar synchronously.
579	 *
580	 * @return string
581	 */
582	public function getSidebarContent() {
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($clip_ctrl);
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 = '<ul>';
673			foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
674				$record = GedcomRecord::getInstance($xref, $WT_TREE);
675				if ($record instanceof Individual || $record instanceof Family) {
676					switch ($record::RECORD_TYPE) {
677					case 'INDI':
678						$icon = 'icon-indis';
679						break;
680					case 'FAM':
681						$icon = 'icon-sfamily';
682						break;
683					}
684					$out .= '<li>';
685					if (!empty($icon)) {
686						$out .= '<i class="' . $icon . '"></i>';
687					}
688					$out .= '<a href="' . $record->getHtmlUrl() . '">';
689					if ($record instanceof Individual) {
690						$out .= $record->getSexImage();
691					}
692					$out .= ' ' . $record->getFullName() . ' ';
693					if ($record instanceof Individual && $record->canShow()) {
694						$out .= ' (' . $record->getLifeSpan() . ')';
695					}
696					$out .= '</a>';
697					$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>';
698					$out .= '</li>';
699				}
700			}
701			$out .= '</ul>';
702		}
703
704		if ($cart[$WT_TREE->getTreeId()]) {
705			$out .=
706				'<br><a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;empty=true&amp;pid=' . $pid . '" class="remove_cart">' .
707				I18N::translate('Empty the clippings cart') .
708				'</a>' .
709				'<br>' .
710				'<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;download=true&amp;pid=' . $pid . '" class="add_cart">' .
711				I18N::translate('Download') .
712				'</a>';
713		}
714		$record = Individual::getInstance($pid, $WT_TREE);
715		if ($record && !array_key_exists($record->getXref(), $cart[$WT_TREE->getTreeId()])) {
716			$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>';
717		}
718
719		return $out;
720	}
721
722	/**
723	 * A form to choose the download options.
724	 *
725	 * @param ClippingsCartController $clip_ctrl
726	 *
727	 * @return string
728	 */
729	public function downloadForm(ClippingsCartController $clip_ctrl) {
730		global $WT_TREE;
731
732		$pid = Filter::get('pid', WT_REGEX_XREF);
733
734		$out = '<script>';
735		$out .= 'function cancelDownload() {
736				var link = "module.php?mod=' . $this->getName() . '&mod_action=ajax&pid=' . $pid . '";
737				$("#sb_clippings_content").load(link);
738			}';
739		$out .= '</script>';
740		$out .= '<form action="module.php">
741		<input type="hidden" name="mod" value="clippings">
742		<input type="hidden" name="mod_action" value="index">
743		<input type="hidden" name="pid" value="' . $pid . '">
744		<input type="hidden" name="action" value="download">
745		<table>
746		<tr><td colspan="2" class="topbottombar"><h2>' . I18N::translate('Download') . '</h2></td></tr>
747		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Zip file(s)') . '</td>
748		<td class="optionbox"><input type="checkbox" name="Zip" value="yes" checked></td></tr>
749
750		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Include media (automatically zips files)') . '</td>
751		<td class="optionbox"><input type="checkbox" name="IncludeMedia" value="yes" checked></td></tr>
752		';
753
754		if (Auth::isManager($WT_TREE)) {
755			$out .=
756				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
757				'<td class="optionbox">' .
758				'<input type="radio" name="privatize_export" value="none" checked> ' . I18N::translate('None') . '<br>' .
759				'<input type="radio" name="privatize_export" value="gedadmin"> ' . I18N::translate('Manager') . '<br>' .
760				'<input type="radio" name="privatize_export" value="user"> ' . I18N::translate('Member') . '<br>' .
761				'<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
762				'</td></tr>';
763		} elseif (Auth::isMember($WT_TREE)) {
764			$out .=
765				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
766				'<td class="list_value">' .
767				'<input type="radio" name="privatize_export" value="user" checked> ' . I18N::translate('Member') . '<br>' .
768				'<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
769				'</td></tr>';
770		}
771
772		$out .= '
773		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Convert from UTF-8 to ISO-8859-1') . '</td>
774		<td class="optionbox"><input type="checkbox" name="convert" value="yes"></td></tr>
775
776		<tr>
777		<td class="descriptionbox width50 wrap">' . I18N::translate('Add the GEDCOM media path to filenames') . '</td>
778		<td class="optionbox">
779		<input type="checkbox" name="conv_path" value="' . Html::escape($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) . '">
780		<span dir="auto">' . Html::escape($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) . '</span></td>
781		</tr>
782
783		<input type="hidden" name="conv_path" value="' . $clip_ctrl->conv_path . '">
784
785		</td></tr>
786
787		<tr><td class="topbottombar" colspan="2">
788		<input type="button" value="' . /* I18N: A button label. */ I18N::translate('cancel') . '" onclick="cancelDownload();">
789		<input type="submit" value="' . /* I18N: A button label. */ I18N::translate('download') . '">
790		</form>';
791
792		return $out;
793	}
794}
795