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