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