xref: /webtrees/app/Module/ClippingsCartModule.php (revision 323788f4145f5a5554b028e0581a6e2063364968)
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									&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
202									<?php echo I18N::translate('Number of generations'); ?>
203									<input type="text" size="5" name="level1" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('ancestors');">
204								</td>
205							</tr>
206							<tr>
207								<td class="optionbox">
208									<label>
209										<input type="radio" name="others" value="ancestorsfamilies" id="ancestorsfamilies">
210										<?php
211										if ($record->getSex() === 'F') {
212											echo /* I18N: %s is a woman's name */ I18N::translate('%s, her ancestors and their families', $record->getFullName());
213										} else {
214											echo /* I18N: %s is a man's name */ I18N::translate('%s, his ancestors and their families', $record->getFullName());
215										}
216										?>
217									</label>
218									<br >
219									&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
220									<?php echo I18N::translate('Number of generations'); ?>
221									<input type="text" size="5" name="level2" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('ancestorsfamilies');">
222								</td>
223							</tr>
224							<tr>
225								<td class="optionbox">
226									<label>
227										<input type="radio" name="others" value="descendants" id="descendants">
228										<?php
229										if ($record->getSex() === 'F') {
230											echo /* I18N: %s is a woman's name */ I18N::translate('%s, her spouses and descendants', $record->getFullName());
231										} else {
232											echo /* I18N: %s is a man's name */ I18N::translate('%s, his spouses and descendants', $record->getFullName());
233										}
234										?>
235									</label>
236									<br >
237									&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
238									<?php echo I18N::translate('Number of generations'); ?>
239									<input type="text" size="5" name="level3" value="<?php echo $MAX_PEDIGREE_GENERATIONS; ?>" onfocus="radAncestors('descendants');">
240								</td>
241							</tr>
242						</tbody>
243						<tfoot>
244							<tr>
245								<td class="topbottombar">
246									<input type="submit" value="<?php echo I18N::translate('continue'); ?>">
247								</td>
248							</tr>
249						</tfoot>
250					</table>
251				</form>
252				<?php } elseif ($clip_ctrl->type === 'SOUR') { ?>
253				<form action="module.php" method="get">
254					<input type="hidden" name="mod" value="clippings">
255					<input type="hidden" name="mod_action" value="index">
256					<input type="hidden" name="id" value="<?php echo $clip_ctrl->id; ?>">
257					<input type="hidden" name="type" value="<?php echo $clip_ctrl->type; ?>">
258					<input type="hidden" name="action" value="add1"></td></tr>
259					<table>
260						<thead>
261							<tr>
262								<td class="topbottombar">
263									<?php echo I18N::translate('Add to the clippings cart'); ?>
264								</td>
265							</tr>
266						</thead>
267						<tbody>
268							<tr>
269								<td class="optionbox">
270									<label>
271										<input type="radio" name="others" checked value="none">
272										<?php echo $record->getFullName(); ?>
273									</label>
274								</td>
275							</tr>
276							<tr>
277								<td class="optionbox">
278									<label>
279										<input type="radio" name="others" value="linked">
280										<?php echo /* I18N: %s is the name of a source */ I18N::translate('%s and the individuals that reference it.', $record->getFullName()); ?>
281									</label>
282								</td>
283							</tr>
284						</tbody>
285						<tfoot>
286							<tr>
287								<td class="topbottombar">
288									<input type="submit" value="<?php echo I18N::translate('continue'); ?>">
289								</td>
290							</tr>
291						</tfoot>
292					</table>
293				</form>
294				<?php }
295				}
296
297			if (!$cart[$WT_TREE->getTreeId()]) {
298				if ($clip_ctrl->action != 'add') {
299					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>');
300					?>
301					<form method="get" name="addin" action="module.php">
302					<input type="hidden" name="mod" value="clippings">
303					<input type="hidden" name="mod_action" value="index">
304						<table>
305							<thead>
306								<tr>
307									<td colspan="2" class="topbottombar">
308										<?php echo I18N::translate('Add to the clippings cart'); ?>
309									</td>
310								</tr>
311							</thead>
312							<tbody>
313								<tr>
314									<td class="optionbox">
315										<input type="hidden" name="action" value="add">
316										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="5">
317									</td>
318									<td class="optionbox">
319										<?php echo FunctionsPrint::printFindIndividualLink('cart_item_id'); ?>
320										<?php echo FunctionsPrint::printFindFamilyLink('cart_item_id'); ?>
321										<?php echo FunctionsPrint::printFindSourceLink('cart_item_id', ''); ?>
322										<input type="submit" value="<?php echo I18N::translate('Add'); ?>">
323									</td>
324								</tr>
325							</tbody>
326						</table>
327					</form>
328					<?php
329				}
330
331				// -- end new lines
332				echo I18N::translate('Your clippings cart is empty.');
333			} else {
334				// Keep track of the INDI from the parent page, otherwise it will
335				// get lost after ajax updates
336				$pid = Filter::get('pid', WT_REGEX_XREF);
337
338				if ($clip_ctrl->action != 'download' && $clip_ctrl->action != 'add') { ?>
339					<table><tr><td class="width33" valign="top" rowspan="3">
340					<form method="get" action="module.php">
341					<input type="hidden" name="mod" value="clippings">
342					<input type="hidden" name="mod_action" value="index">
343					<input type="hidden" name="action" value="download">
344					<input type="hidden" name="pid" value="<?php echo $pid; ?>">
345					<table>
346					<tr><td colspan="2" class="topbottombar"><h2><?php echo I18N::translate('Download'); ?></h2></td></tr>
347					<tr>
348						<td class="descriptionbox width50 wrap">
349							<?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.'); ?>
350						</td>
351						<td class="optionbox wrap">
352							<input type="checkbox" name="Zip" value="yes">
353							<?php echo I18N::translate('Zip file(s)'); ?>
354						</td>
355					</tr>
356					<tr>
357						<td class="descriptionbox width50 wrap">
358							<?php echo I18N::translate('Include media (automatically zips files)'); ?>
359						</td>
360					<td class="optionbox"><input type="checkbox" name="IncludeMedia" value="yes"></td></tr>
361
362					<?php if (Auth::isManager($WT_TREE)) {	?>
363						<tr><td class="descriptionbox width50 wrap"><?php echo I18N::translate('Apply privacy settings'); ?></td>
364						<td class="optionbox">
365							<input type="radio" name="privatize_export" value="none" checked> <?php echo I18N::translate('None'); ?><br>
366							<input type="radio" name="privatize_export" value="gedadmin"> <?php echo I18N::translate('Manager'); ?><br>
367							<input type="radio" name="privatize_export" value="user"> <?php echo I18N::translate('Member'); ?><br>
368							<input type="radio" name="privatize_export" value="visitor"> <?php echo I18N::translate('Visitor'); ?>
369						</td></tr>
370					<?php } elseif (Auth::isMember($WT_TREE)) { ?>
371						<tr><td class="descriptionbox width50 wrap"><?php echo I18N::translate('Apply privacy settings'); ?></td>
372						<td class="optionbox">
373							<input type="radio" name="privatize_export" value="user" checked> <?php echo I18N::translate('Member'); ?><br>
374							<input type="radio" name="privatize_export" value="visitor"> <?php echo I18N::translate('Visitor'); ?>
375						</td></tr>
376					<?php } ?>
377
378					<tr><td class="descriptionbox width50 wrap"><?php echo I18N::translate('Convert from UTF-8 to ISO-8859-1'); ?></td>
379					<td class="optionbox"><input type="checkbox" name="convert" value="yes"></td></tr>
380
381					<tr><td class="descriptionbox width50 wrap"><?php echo I18N::translate('Add the GEDCOM media path to filenames'); ?></td>
382					<td class="optionbox">
383						<input type="checkbox" name="conv_path" value="<?php echo Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')); ?>">
384						<span dir="auto"><?php echo Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')); ?></span>
385					</td></tr>
386
387					<tr><td class="topbottombar" colspan="2">
388					<input type="submit" value="<?php echo I18N::translate('Download'); ?>">
389					</form>
390					</td></tr>
391					</table>
392					</td></tr>
393					</table>
394					<br>
395
396					<form method="get" name="addin" action="module.php">
397						<input type="hidden" name="mod" value="clippings">
398						<input type="hidden" name="mod_action" value="index">
399						<table>
400							<thead>
401								<tr>
402									<td colspan="2" class="topbottombar" style="text-align:center; ">
403										<?php echo I18N::translate('Add to the clippings cart'); ?>
404									</td>
405								</tr>
406							</thead>
407							<tbody>
408								<tr>
409									<td class="optionbox">
410										<input type="hidden" name="action" value="add">
411										<input type="text" data-autocomplete-type="IFSRO" name="id" id="cart_item_id" size="8">
412									</td>
413									<td class="optionbox">
414										<?php echo FunctionsPrint::printFindIndividualLink('cart_item_id'); ?>
415										<?php echo FunctionsPrint::printFindFamilyLink('cart_item_id'); ?>
416										<?php echo FunctionsPrint::printFindSourceLink('cart_item_id'); ?>
417										<input type="submit" value="<?php echo I18N::translate('Add'); ?>">
418									</td>
419								</tr>
420								</tbody>
421						</table>
422					</form>
423
424
425				<?php } ?>
426				<br><a href="module.php?mod=clippings&amp;mod_action=index&amp;action=empty"><?php echo I18N::translate('Empty the clippings cart'); ?></a>
427				</td></tr>
428
429				<tr><td class="topbottombar"><h2><?php echo I18N::translate('Family tree clippings cart'); ?></h2></td></tr>
430
431				<tr><td valign="top">
432				<table id="mycart" class="sortable list_table width100">
433					<tr>
434						<th class="list_label"><?php echo I18N::translate('Record'); ?></th>
435						<th class="list_label"><?php echo I18N::translate('Remove'); ?></th>
436					</tr>
437			<?php
438				foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
439					$record = GedcomRecord::getInstance($xref, $WT_TREE);
440					if ($record) {
441						switch ($record::RECORD_TYPE) {
442						case 'INDI': $icon = 'icon-indis'; break;
443						case 'FAM':  $icon = 'icon-sfamily'; break;
444						case 'SOUR': $icon = 'icon-source'; break;
445						case 'REPO': $icon = 'icon-repository'; break;
446						case 'NOTE': $icon = 'icon-note'; break;
447						case 'OBJE': $icon = 'icon-media'; break;
448						default:     $icon = 'icon-clippings'; break;
449						}
450						?>
451						<tr><td class="list_value">
452							<i class="<?php echo $icon; ?>"></i>
453						<?php
454						echo '<a href="', $record->getHtmlUrl(), '">', $record->getFullName(), '</a>';
455						?>
456						</td>
457						<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>
458					</tr>
459					<?php
460					}
461				}
462			?>
463				</table>
464				</td></tr></table>
465			<?php
466			}
467			break;
468		default:
469			http_response_code(404);
470			break;
471		}
472	}
473
474	/**
475	 * The user can re-order menus.  Until they do, they are shown in this order.
476	 *
477	 * @return int
478	 */
479	public function defaultMenuOrder() {
480		return 20;
481	}
482
483	/**
484	 * A menu, to be added to the main application menu.
485	 *
486	 * @return Menu|null
487	 */
488	public function getMenu() {
489		global $controller, $WT_TREE;
490
491		//-- main clippings menu item
492		$menu = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippings', array('rel' => 'nofollow'));
493		if (isset($controller->record)) {
494			$submenu = new Menu($this->getTitle(), 'module.php?mod=clippings&amp;mod_action=index&amp;ged=' . $WT_TREE->getNameUrl(), 'menu-clippingscart', array('rel' => 'nofollow'));
495			$menu->addSubmenu($submenu);
496		}
497		if (!empty($controller->record) && $controller->record->canShow()) {
498			$submenu = 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'));
499			$menu->addSubmenu($submenu);
500		}
501
502		return $menu;
503	}
504
505	/** {@inheritdoc} */
506	public function defaultSidebarOrder() {
507		return 60;
508	}
509
510	/** {@inheritdoc} */
511	public function hasSidebarContent() {
512		// Creating a controller has the side effect of initialising the cart
513		new ClippingsCartController;
514
515		return true;
516	}
517
518	/**
519	 * Load this sidebar synchronously.
520	 *
521	 * @return string
522	 */
523	public function getSidebarContent() {
524		global $controller;
525
526		$controller->addInlineJavascript('
527				jQuery("#sb_clippings_content").on("click", ".add_cart, .remove_cart", function() {
528					jQuery("#sb_clippings_content").load(this.href);
529					return false;
530				});
531			');
532
533		return '<div id="sb_clippings_content">' . $this->getCartList() . '</div>';
534	}
535
536	/** {@inheritdoc} */
537	public function getSidebarAjaxContent() {
538		global $WT_TREE;
539
540		$cart = Session::get('cart');
541
542		$clip_ctrl         = new ClippingsCartController;
543		$add               = Filter::get('add', WT_REGEX_XREF);
544		$add1              = Filter::get('add1', WT_REGEX_XREF);
545		$remove            = Filter::get('remove', WT_REGEX_XREF);
546		$others            = Filter::get('others');
547		$clip_ctrl->level1 = Filter::getInteger('level1');
548		$clip_ctrl->level2 = Filter::getInteger('level2');
549		$clip_ctrl->level3 = Filter::getInteger('level3');
550		if ($add) {
551			$record = GedcomRecord::getInstance($add, $WT_TREE);
552			if ($record) {
553				$clip_ctrl->id   = $record->getXref();
554				$clip_ctrl->type = $record::RECORD_TYPE;
555				$clip_ctrl->addClipping($record);
556			}
557		} elseif ($add1) {
558			$record = Individual::getInstance($add1, $WT_TREE);
559			if ($record) {
560				$clip_ctrl->id   = $record->getXref();
561				$clip_ctrl->type = $record::RECORD_TYPE;
562				if ($others == 'parents') {
563					foreach ($record->getChildFamilies() as $family) {
564						$clip_ctrl->addClipping($family);
565						$clip_ctrl->addFamilyMembers($family);
566					}
567				} elseif ($others == 'ancestors') {
568					$clip_ctrl->addAncestorsToCart($record, $clip_ctrl->level1);
569				} elseif ($others == 'ancestorsfamilies') {
570					$clip_ctrl->addAncestorsToCartFamilies($record, $clip_ctrl->level2);
571				} elseif ($others == 'members') {
572					foreach ($record->getSpouseFamilies() as $family) {
573						$clip_ctrl->addClipping($family);
574						$clip_ctrl->addFamilyMembers($family);
575					}
576				} elseif ($others == 'descendants') {
577					foreach ($record->getSpouseFamilies() as $family) {
578						$clip_ctrl->addClipping($family);
579						$clip_ctrl->addFamilyDescendancy($family, $clip_ctrl->level3);
580					}
581				}
582			}
583		} elseif ($remove) {
584			unset($cart[$WT_TREE->getTreeId()][$remove]);
585			Session::put('cart', $cart);
586		} elseif (isset($_REQUEST['empty'])) {
587			$cart[$WT_TREE->getTreeId()] = array();
588			Session::put('cart', $cart);
589		} elseif (isset($_REQUEST['download'])) {
590			return $this->downloadForm($clip_ctrl);
591		}
592
593		return $this->getCartList();
594	}
595
596	/**
597	 * A list for the side bar.
598	 *
599	 * @return string
600	 */
601	public function getCartList() {
602		global $WT_TREE;
603
604		$cart = Session::get('cart', array());
605		if (!array_key_exists($WT_TREE->getTreeId(), $cart)) {
606			$cart[$WT_TREE->getTreeId()] = array();
607		}
608		$pid = Filter::get('pid', WT_REGEX_XREF);
609
610		if (!$cart[$WT_TREE->getTreeId()]) {
611			$out = I18N::translate('Your clippings cart is empty.');
612		} else {
613			$out = '<ul>';
614			foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) {
615				$record = GedcomRecord::getInstance($xref, $WT_TREE);
616				if ($record instanceof Individual || $record instanceof Family) {
617					switch ($record::RECORD_TYPE) {
618					case 'INDI':
619						$icon = 'icon-indis';
620						break;
621					case 'FAM':
622						$icon = 'icon-sfamily';
623						break;
624					}
625					$out .= '<li>';
626					if (!empty($icon)) {
627						$out .= '<i class="' . $icon . '"></i>';
628					}
629					$out .= '<a href="' . $record->getHtmlUrl() . '">';
630					if ($record instanceof Individual) {
631						$out .= $record->getSexImage();
632					}
633					$out .= ' ' . $record->getFullName() . ' ';
634					if ($record instanceof Individual && $record->canShow()) {
635						$out .= ' (' . $record->getLifeSpan() . ')';
636					}
637					$out .= '</a>';
638					$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>';
639					$out .= '</li>';
640				}
641			}
642			$out .= '</ul>';
643		}
644
645		if ($cart[$WT_TREE->getTreeId()]) {
646			$out .=
647				'<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">' .
648				I18N::translate('Empty the clippings cart') .
649				'</a>' .
650				'<br>' .
651				'<a href="module.php?mod=' . $this->getName() . '&amp;mod_action=ajax&amp;sb_action=clippings&amp;download=true&amp;pid=' . $pid . '" class="add_cart">' .
652				I18N::translate('Download') .
653				'</a>';
654		}
655		$record = Individual::getInstance($pid, $WT_TREE);
656		if ($record && !array_key_exists($record->getXref(), $cart[$WT_TREE->getTreeId()])) {
657			$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>';
658		}
659
660		return $out;
661	}
662
663	/**
664	 * A form to choose the download options.
665	 *
666	 * @param ClippingsCartController $clip_ctrl
667	 *
668	 * @return string
669	 */
670	public function downloadForm(ClippingsCartController $clip_ctrl) {
671		global $WT_TREE;
672
673		$pid = Filter::get('pid', WT_REGEX_XREF);
674
675		$out = '<script>';
676		$out .= 'function cancelDownload() {
677				var link = "module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&pid=' . $pid . '";
678				jQuery("#sb_clippings_content").load(link);
679			}';
680		$out .= '</script>';
681		$out .= '<form method="get" action="module.php">
682		<input type="hidden" name="mod" value="clippings">
683		<input type="hidden" name="mod_action" value="index">
684		<input type="hidden" name="pid" value="' . $pid . '">
685		<input type="hidden" name="action" value="download">
686		<table>
687		<tr><td colspan="2" class="topbottombar"><h2>' . I18N::translate('Download') . '</h2></td></tr>
688		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Zip file(s)') . '</td>
689		<td class="optionbox"><input type="checkbox" name="Zip" value="yes" checked></td></tr>
690
691		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Include media (automatically zips files)') . '</td>
692		<td class="optionbox"><input type="checkbox" name="IncludeMedia" value="yes" checked></td></tr>
693		';
694
695		if (Auth::isManager($WT_TREE)) {
696			$out .=
697				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
698				'<td class="optionbox">' .
699				'	<input type="radio" name="privatize_export" value="none" checked> ' . I18N::translate('None') . '<br>' .
700				'	<input type="radio" name="privatize_export" value="gedadmin"> ' . I18N::translate('Manager') . '<br>' .
701				'	<input type="radio" name="privatize_export" value="user"> ' . I18N::translate('Member') . '<br>' .
702				'	<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
703				'</td></tr>';
704		} elseif (Auth::isMember($WT_TREE)) {
705			$out .=
706				'<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Apply privacy settings') . '</td>' .
707				'<td class="list_value">' .
708				'	<input type="radio" name="privatize_export" value="user" checked> ' . I18N::translate('Member') . '<br>' .
709				'	<input type="radio" name="privatize_export" value="visitor"> ' . I18N::translate('Visitor') .
710				'</td></tr>';
711		}
712
713		$out .= '
714		<tr><td class="descriptionbox width50 wrap">' . I18N::translate('Convert from UTF-8 to ISO-8859-1') . '</td>
715		<td class="optionbox"><input type="checkbox" name="convert" value="yes"></td></tr>
716
717		<tr>
718		<td class="descriptionbox width50 wrap">' . I18N::translate('Add the GEDCOM media path to filenames') . '</td>
719		<td class="optionbox">
720		<input type="checkbox" name="conv_path" value="' . Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) . '">
721		<span dir="auto">' . Filter::escapeHtml($WT_TREE->getPreference('GEDCOM_MEDIA_PATH')) . '</span></td>
722		</tr>
723
724		<input type="hidden" name="conv_path" value="' . $clip_ctrl->conv_path . '">
725
726		</td></tr>
727
728		<tr><td class="topbottombar" colspan="2">
729		<input type="button" value="' . I18N::translate('Cancel') . '" onclick="cancelDownload();">
730		<input type="submit" value="' . I18N::translate('Download') . '">
731		</form>';
732
733		return $out;
734	}
735}
736