/** * Each object type may have its own special rules, and re-implement this function. * * @param int $access_level * * @return bool */ protected function canShowByType($access_level) { // Hide media objects if they are attached to private records $linked_ids = Database::prepare("SELECT l_from FROM `##link` WHERE l_to = ? AND l_file = ?")->execute(array($this->xref, $this->tree->getTreeId()))->fetchOneColumn(); foreach ($linked_ids as $linked_id) { $linked_record = GedcomRecord::getInstance($linked_id, $this->tree); if ($linked_record && !$linked_record->canShow($access_level)) { return false; } } // ... otherwise apply default behaviour return parent::canShowByType($access_level); }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $ctype, $WT_TREE; $num = $this->getBlockSetting($block_id, 'num', '10'); $count_placement = $this->getBlockSetting($block_id, 'count_placement', 'before'); $block = $this->getBlockSetting($block_id, 'block', '0'); foreach (array('count_placement', 'num', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle(); $content = ''; // load the lines from the file $top10 = Database::prepare("SELECT page_parameter, page_count" . " FROM `##hit_counter`" . " WHERE gedcom_id = :tree_id AND page_name IN ('individual.php','family.php','source.php','repo.php','note.php','mediaviewer.php')" . " ORDER BY page_count DESC LIMIT :limit")->execute(array('tree_id' => $WT_TREE->getTreeId(), 'limit' => (int) $num))->fetchAssoc(); if ($block) { $content .= '<table width="90%">'; } else { $content .= '<table>'; } foreach ($top10 as $id => $count) { $record = GedcomRecord::getInstance($id, $WT_TREE); if ($record && $record->canShow()) { $content .= '<tr>'; if ($count_placement == 'before') { $content .= '<td dir="ltr" style="text-align:right">[' . $count . ']</td>'; } $content .= '<td class="name2" ><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>'; if ($count_placement == 'after') { $content .= '<td dir="ltr" style="text-align:right">[' . $count . ']</td>'; } $content .= '</tr>'; } } $content .= "</table>"; if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
/** * This is a general purpose hook, allowing modules to respond to routes * of the form module.php?mod=FOO&mod_action=BAR * * @param string $mod_action */ public function modAction($mod_action) { global $WT_TREE; switch ($mod_action) { case 'menu-add-favorite': // Process the "add to user favorites" menu item on indi/fam/etc. pages $record = GedcomRecord::getInstance(Filter::post('xref', WT_REGEX_XREF), $WT_TREE); if (Auth::check() && $record->canShowName()) { self::addFavorite(array('user_id' => Auth::id(), 'gedcom_id' => $record->getTree()->getTreeId(), 'gid' => $record->getXref(), 'type' => $record::RECORD_TYPE, 'url' => null, 'note' => null, 'title' => null)); FlashMessages::addMessage(I18N::translate('“%s” has been added to your favorites.', $record->getFullName())); } break; } }
/** * Startup activity * * @param GedcomRecord|null $record */ public function __construct(GedcomRecord $record = null) { $this->record = $record; // Automatically fix broken links if ($this->record && $this->record->canEdit()) { $broken_links = 0; foreach ($this->record->getFacts('HUSB|WIFE|CHIL|FAMS|FAMC|REPO') as $fact) { if (!$fact->isPendingDeletion() && $fact->getTarget() === null) { $this->record->deleteFact($fact->getFactId(), false); FlashMessages::addMessage(I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue())); $broken_links = true; } } foreach ($this->record->getFacts('NOTE|SOUR|OBJE') as $fact) { // These can be links or inline. Only delete links. if (!$fact->isPendingDeletion() && $fact->getTarget() === null && preg_match('/^@.*@$/', $fact->getValue())) { $this->record->deleteFact($fact->getFactId(), false); FlashMessages::addMessage(I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue())); $broken_links = true; } } if ($broken_links) { // Reload the updated family $this->record = GedcomRecord::getInstance($this->record->getXref(), $this->record->getTree()); } } parent::__construct(); // We want robots to index this page $this->setMetaRobots('index,follow'); // Set a page title if ($this->record) { if ($this->record->canShowName()) { // e.g. "John Doe" or "1881 Census of Wales" $this->setPageTitle($this->record->getFullName()); } else { // e.g. "Individual" or "Source" $record = $this->record; $this->setPageTitle(GedcomTag::getLabel($record::RECORD_TYPE)); } } else { // No such record $this->setPageTitle(I18N::translate('Private')); } }
/** * Search for a media object. */ private static function mediaQuery() { global $WT_TREE; $iid2 = Filter::get('iid', WT_REGEX_XREF); $controller = new SimpleController(); $controller->setPageTitle(I18N::translate('Link to an existing media object'))->pageHeader(); $record = GedcomRecord::getInstance($iid2, $WT_TREE); if ($record) { $headjs = ''; if ($record instanceof Family) { if ($record->getHusband()) { $headjs = $record->getHusband()->getXref(); } elseif ($record->getWife()) { $headjs = $record->getWife()->getXref(); } } ?> <script> function insertId() { if (window.opener.document.getElementById('addlinkQueue')) { // alert('Please move this alert window and examine the contents of the pop-up window, then click OK') window.opener.insertRowToTable('<?php echo $record->getXref(); ?> ', '<?php echo htmlspecialchars($record->getFullName()); ?> ', '<?php echo $headjs; ?> '); window.close(); } } </script> <?php } else { ?> <script> function insertId() { window.opener.alert('<?php echo $iid2; ?> - <?php echo I18N::translate('Not a valid individual, family, or source ID'); ?> '); window.close(); } </script> <?php } ?> <script>window.onLoad = insertId();</script> <?php }
/** * Get the record to which this fact links * * @return Individual|Family|Source|Repository|Media|Note|null */ public function getTarget() { $xref = trim($this->getValue(), '@'); switch ($this->tag) { case 'FAMC': case 'FAMS': return Family::getInstance($xref, $this->getParent()->getTree()); case 'HUSB': case 'WIFE': case 'CHIL': return Individual::getInstance($xref, $this->getParent()->getTree()); case 'SOUR': return Source::getInstance($xref, $this->getParent()->getTree()); case 'OBJE': return Media::getInstance($xref, $this->getParent()->getTree()); case 'REPO': return Repository::getInstance($xref, $this->getParent()->getTree()); case 'NOTE': return Note::getInstance($xref, $this->getParent()->getTree()); default: return GedcomRecord::getInstance($xref, $this->getParent()->getTree()); } }
/** * Create a new record from GEDCOM data. * * @param string $gedcom * * @throws \Exception * * @return GedcomRecord */ public function createRecord($gedcom) { if (preg_match('/^0 @(' . WT_REGEX_XREF . ')@ (' . WT_REGEX_TAG . ')/', $gedcom, $match)) { $xref = $match[1]; $type = $match[2]; } else { throw new \Exception('Invalid argument to GedcomRecord::createRecord(' . $gedcom . ')'); } if (strpos("\r", $gedcom) !== false) { // MSDOS line endings will break things in horrible ways throw new \Exception('Evil line endings found in GedcomRecord::createRecord(' . $gedcom . ')'); } // webtrees creates XREFs containing digits. Anything else (e.g. “new”) is just a placeholder. if (!preg_match('/\\d/', $xref)) { $xref = $this->getNewXref($type); $gedcom = preg_replace('/^0 @(' . WT_REGEX_XREF . ')@/', '0 @' . $xref . '@', $gedcom); } // Create a change record, if not already present if (!preg_match('/\\n1 CHAN/', $gedcom)) { $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . Auth::user()->getUserName(); } // Create a pending change Database::prepare("INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, '', ?, ?)")->execute(array($this->tree_id, $xref, $gedcom, Auth::id())); Log::addEditLog('Create: ' . $type . ' ' . $xref); // Accept this pending change if (Auth::user()->getPreference('auto_accept')) { FunctionsImport::acceptAllChanges($xref, $this->tree_id); } // Return the newly created record. Note that since GedcomRecord // has a cache of pending changes, we cannot use it to create a // record with a newly created pending change. return GedcomRecord::getInstance($xref, $this, $gedcom); }
/** * Print a table of events * * @param string[] $change_ids * @param string $sort * * @return string */ public static function changesTable($change_ids, $sort) { global $controller, $WT_TREE; $n = 0; $table_id = 'table-chan-' . Uuid::uuid4(); // lists requires a unique ID in case there are multiple lists per page switch ($sort) { case 'name': //name $aaSorting = "[5,'asc'], [4,'desc']"; break; case 'date_asc': //date ascending $aaSorting = "[4,'asc'], [5,'asc']"; break; case 'date_desc': //date descending $aaSorting = "[4,'desc'], [5,'asc']"; break; } $html = ''; $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript(' jQuery.fn.dataTableExt.oSort["unicode-asc" ]=function(a,b) {return a.replace(/<[^<]*>/, "").localeCompare(b.replace(/<[^<]*>/, ""))}; jQuery.fn.dataTableExt.oSort["unicode-desc"]=function(a,b) {return b.replace(/<[^<]*>/, "").localeCompare(a.replace(/<[^<]*>/, ""))}; jQuery("#' . $table_id . '").dataTable({ dom: \'t\', paging: false, autoWidth:false, lengthChange: false, filter: false, ' . I18N::datatablesI18N() . ', jQueryUI: true, sorting: [' . $aaSorting . '], columns: [ /* 0-Type */ { sortable: false, class: "center" }, /* 1-Record */ { dataSort: 5 }, /* 2-Change */ { dataSort: 4 }, /* 3-By */ null, /* 4-DATE */ { visible: false }, /* 5-SORTNAME */{ type: "unicode", visible: false } ] }); '); //-- table header $html .= '<table id="' . $table_id . '" class="width100">'; $html .= '<thead><tr>'; $html .= '<th></th>'; $html .= '<th>' . I18N::translate('Record') . '</th>'; $html .= '<th>' . GedcomTag::getLabel('CHAN') . '</th>'; $html .= '<th>' . GedcomTag::getLabel('_WT_USER') . '</th>'; $html .= '<th>DATE</th>'; //hidden by datatables code $html .= '<th>SORTNAME</th>'; //hidden by datatables code $html .= '</tr></thead><tbody>'; //-- table body foreach ($change_ids as $change_id) { $record = GedcomRecord::getInstance($change_id, $WT_TREE); if (!$record || !$record->canShow()) { continue; } $html .= '<tr><td>'; switch ($record::RECORD_TYPE) { case 'INDI': $icon = $record->getSexImage('small'); break; case 'FAM': $icon = '<i class="icon-button_family"></i>'; break; case 'OBJE': $icon = '<i class="icon-button_media"></i>'; break; case 'NOTE': $icon = '<i class="icon-button_note"></i>'; break; case 'SOUR': $icon = '<i class="icon-button_source"></i>'; break; case 'REPO': $icon = '<i class="icon-button_repository"></i>'; break; default: $icon = ' '; break; } $html .= '<a href="' . $record->getHtmlUrl() . '">' . $icon . '</a>'; $html .= '</td>'; ++$n; //-- Record name(s) $name = $record->getFullName(); $html .= '<td class="wrap">'; $html .= '<a href="' . $record->getHtmlUrl() . '">' . $name . '</a>'; if ($record instanceof Individual) { $addname = $record->getAddName(); if ($addname) { $html .= '<div class="indent"><a href="' . $record->getHtmlUrl() . '">' . $addname . '</a></div>'; } } $html .= "</td>"; //-- Last change date/time $html .= '<td class="wrap">' . $record->lastChangeTimestamp() . '</td>'; //-- Last change user $html .= '<td class="wrap">' . Filter::escapeHtml($record->lastChangeUser()) . '</td>'; //-- change date (sortable) hidden by datatables code $html .= '<td>' . $record->lastChangeTimestamp(true) . '</td>'; //-- names (sortable) hidden by datatables code $html .= '<td>' . $record->getSortName() . '</td></tr>'; } $html .= '</tbody></table>'; return $html; }
/** * A list for the side bar. * * @return string */ public function getCartList() { global $WT_TREE; $cart = Session::get('cart', array()); if (!array_key_exists($WT_TREE->getTreeId(), $cart)) { $cart[$WT_TREE->getTreeId()] = array(); } $pid = Filter::get('pid', WT_REGEX_XREF); if (!$cart[$WT_TREE->getTreeId()]) { $out = I18N::translate('Your clippings cart is empty.'); } else { $out = '<ul>'; foreach (array_keys($cart[$WT_TREE->getTreeId()]) as $xref) { $record = GedcomRecord::getInstance($xref, $WT_TREE); if ($record instanceof Individual || $record instanceof Family) { switch ($record::RECORD_TYPE) { case 'INDI': $icon = 'icon-indis'; break; case 'FAM': $icon = 'icon-sfamily'; break; } $out .= '<li>'; if (!empty($icon)) { $out .= '<i class="' . $icon . '"></i>'; } $out .= '<a href="' . $record->getHtmlUrl() . '">'; if ($record instanceof Individual) { $out .= $record->getSexImage(); } $out .= ' ' . $record->getFullName() . ' '; if ($record instanceof Individual && $record->canShow()) { $out .= ' (' . $record->getLifeSpan() . ')'; } $out .= '</a>'; $out .= '<a class="icon-remove remove_cart" href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&remove=' . $xref . '&pid=' . $pid . '" title="' . I18N::translate('Remove') . '"></a>'; $out .= '</li>'; } } $out .= '</ul>'; } if ($cart[$WT_TREE->getTreeId()]) { $out .= '<br><a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&empty=true&pid=' . $pid . '" class="remove_cart">' . I18N::translate('Empty the clippings cart') . '</a>' . '<br>' . '<a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&download=true&pid=' . $pid . '" class="add_cart">' . I18N::translate('Download') . '</a>'; } $record = Individual::getInstance($pid, $WT_TREE); if ($record && !array_key_exists($record->getXref(), $cart[$WT_TREE->getTreeId()])) { $out .= '<br><a href="module.php?mod=' . $this->getName() . '&mod_action=ajax&sb_action=clippings&add=' . $pid . '&pid=' . $pid . '" class="add_cart"><i class="icon-clippings"></i> ' . I18N::translate('Add %s to the clippings cart', $record->getFullName()) . '</a>'; } return $out; }
*/ namespace Fisharebest\Webtrees; /** * Defined in session.php * * @global Tree $WT_TREE */ global $WT_TREE; use Fisharebest\Webtrees\Controller\GedcomRecordController; use Fisharebest\Webtrees\Functions\FunctionsPrint; use Fisharebest\Webtrees\Functions\FunctionsPrintFacts; use Fisharebest\Webtrees\Functions\FunctionsPrintLists; define('WT_SCRIPT_NAME', 'gedrecord.php'); require './includes/session.php'; $record = GedcomRecord::getInstance(Filter::get('pid', WT_REGEX_XREF), $WT_TREE); if ($record instanceof Individual || $record instanceof Family || $record instanceof Source || $record instanceof Repository || $record instanceof Note || $record instanceof Media) { header('Location: ' . WT_BASE_URL . $record->getRawUrl()); return; } $controller = new GedcomRecordController($record); if ($controller->record && $controller->record->canShow()) { $controller->pageHeader(); if ($controller->record->isPendingDeletion()) { if (Auth::isModerator($controller->record->getTree())) { echo '<p class="ui-state-highlight">', I18N::translate('This record has been deleted. You should review the deletion and then %1$s or %2$s it.', '<a href="#" onclick="accept_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'accept') . '</a>', '<a href="#" onclick="reject_changes(\'' . $controller->record->getXref() . '\');">' . I18N::translateContext('You should review the deletion and then accept or reject it.', 'reject') . '</a>'), ' ', FunctionsPrint::helpLink('pending_changes'), '</p>'; } elseif (Auth::isEditor($controller->record->getTree())) { echo '<p class="ui-state-highlight">', I18N::translate('This record has been deleted. The deletion will need to be reviewed by a moderator.'), ' ', FunctionsPrint::helpLink('pending_changes'), '</p>'; } } elseif ($controller->record->isPendingAddtion()) { if (Auth::isModerator($controller->record->getTree())) {
/** * Format a list of facts for display * * @param Fact[] $list * @param string $tag1 * @param string $tag2 * @param bool $show_sex_symbols * * @return string */ function calendar_list_text($list, $tag1, $tag2, $show_sex_symbols) { global $males, $females, $WT_TREE; $html = ''; foreach ($list as $id => $facts) { $tmp = GedcomRecord::getInstance($id, $WT_TREE); $html .= $tag1 . '<a href="' . $tmp->getHtmlUrl() . '">' . $tmp->getFullName() . '</a> '; if ($show_sex_symbols && $tmp instanceof Individual) { switch ($tmp->getSex()) { case 'M': $html .= '<i class="icon-sex_m_9x9" title="' . I18N::translate('Male') . '"></i>'; ++$males; break; case 'F': $html .= '<i class="icon-sex_f_9x9" title="' . I18N::translate('Female') . '"></i>'; ++$females; break; default: $html .= '<i class="icon-sex_u_9x9" title="' . I18N::translateContext('unknown gender', 'Unknown') . '"></i>'; break; } } $html .= '<div class="indent">' . $facts . '</div>' . $tag2; } return $html; }
/** * Determine if the family parents are married. * * Don't use the default function because we want to privatize the record but display the name * and the parents of the spouse if the spouse him/herself is not private. * * @param type $family * @return boolean */ private function getMarriage($family) { $record = GedcomRecord::getInstance($family->getXref(), $this->tree); foreach ($record->getFacts('MARR', false, Auth::PRIV_HIDE) as $fact) { if ($fact) { return true; } } }
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $ctype, $controller, $WT_TREE; $show_other = $this->getBlockSetting($block_id, 'show_other', self::DEFAULT_SHOW_OTHER); $show_unassigned = $this->getBlockSetting($block_id, 'show_unassigned', self::DEFAULT_SHOW_UNASSIGNED); $show_future = $this->getBlockSetting($block_id, 'show_future', self::DEFAULT_SHOW_FUTURE); $block = $this->getBlockSetting($block_id, 'block', self::DEFAULT_BLOCK); foreach (array('show_unassigned', 'show_other', 'show_future', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle(); $table_id = Uuid::uuid4(); // create a unique ID $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript(' jQuery("#' . $table_id . '").dataTable({ dom: \'t\', ' . I18N::datatablesI18N() . ', autoWidth: false, paginate: false, lengthChange: false, filter: false, info: true, jQueryUI: true, columns: [ null, null, null, null ] }); jQuery("#' . $table_id . '").css("visibility", "visible"); jQuery(".loading-image").css("display", "none"); '); $content = ''; $content .= '<div class="loading-image"> </div>'; $content .= '<table id="' . $table_id . '" style="visibility:hidden;">'; $content .= '<thead><tr>'; $content .= '<th>' . GedcomTag::getLabel('DATE') . '</th>'; $content .= '<th>' . I18N::translate('Record') . '</th>'; $content .= '<th>' . I18N::translate('Username') . '</th>'; $content .= '<th>' . GedcomTag::getLabel('TEXT') . '</th>'; $content .= '</tr></thead><tbody>'; $found = false; $end_jd = $show_future ? 99999999 : WT_CLIENT_JD; $xrefs = Database::prepare("SELECT DISTINCT d_gid FROM `##dates`" . " WHERE d_file = :tree_id AND d_fact = '_TODO' AND d_julianday1 < :jd")->execute(array('tree_id' => $WT_TREE->getTreeId(), 'jd' => $end_jd))->fetchOneColumn(); $facts = array(); foreach ($xrefs as $xref) { $record = GedcomRecord::getInstance($xref, $WT_TREE); if ($record->canShow()) { foreach ($record->getFacts('_TODO') as $fact) { $facts[] = $fact; } } } foreach ($facts as $fact) { $record = $fact->getParent(); $user_name = $fact->getAttribute('_WT_USER'); if ($user_name === Auth::user()->getUserName() || !$user_name && $show_unassigned || $user_name && $show_other) { $content .= '<tr>'; $content .= '<td data-sort="' . $fact->getDate()->julianDay() . '">' . $fact->getDate()->display() . '</td>'; $content .= '<td data-sort="' . Filter::escapeHtml($record->getSortName()) . '"><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>'; $content .= '<td>' . $user_name . '</td>'; $content .= '<td dir="auto">' . $fact->getValue() . '</td>'; $content .= '</tr>'; $found = true; } } $content .= '</tbody></table>'; if (!$found) { $content .= '<p>' . I18N::translate('There are no research tasks in this family tree.') . '</p>'; } if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
$diff_lines = array(); foreach ($differences as $difference) { switch ($difference[1]) { case MyersDiff::DELETE: $diff_lines[] = '<del>' . $difference[0] . '</del>'; break; case MyersDiff::INSERT: $diff_lines[] = '<ins>' . $difference[0] . '</ins>'; break; default: $diff_lines[] = $difference[0]; } } // Only convert valid xrefs to links $data[] = array($row->change_id, $row->change_time, I18N::translate($row->status), GedcomRecord::getInstance($row->xref, Tree::findByName($gedc)) ? "<a href='gedrecord.php?pid={$row->xref}&ged={$row->gedcom_name}'>{$row->xref}</a>" : $row->xref, '<div class="gedcom-data" dir="ltr">' . preg_replace_callback('/@(' . WT_REGEX_XREF . ')@/', function ($match) use($gedc) { return GedcomRecord::getInstance($match[1], Tree::findByName($gedc)) ? "<a href='#' onclick='return edit_raw(\"{$match[1]}\");'>{$match[0]}</a>" : $match[0]; }, implode("\n", $diff_lines)) . '</div>', $row->user_name, $row->gedcom_name); } header('Content-type: application/json'); // See http://www.datatables.net/usage/server-side echo json_encode(array('draw' => Filter::getInteger('draw'), 'recordsTotal' => $recordsTotal, 'recordsFiltered' => $recordsFiltered, 'data' => $data)); return; } $controller->pageHeader()->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addExternalJavascript(WT_MOMENT_JS_URL)->addExternalJavascript(WT_BOOTSTRAP_DATETIMEPICKER_JS_URL)->addInlineJavascript(' jQuery(".table-site-changes").dataTable( { processing: true, serverSide: true, ajax: "' . WT_BASE_URL . WT_SCRIPT_NAME . '?action=load_json&from=' . $from . '&to=' . $to . '&type=' . $type . '&oldged=' . rawurlencode($oldged) . '&newged=' . rawurlencode($newged) . '&xref=' . rawurlencode($xref) . '&user='******'&gedc=' . rawurlencode($gedc) . '", ' . I18N::datatablesI18N(array(10, 20, 50, 100, 500, 1000, -1)) . ', sorting: [[ 0, "desc" ]], pageLength: ' . Auth::user()->getPreference('admin_site_change_page_size', 10) . ',
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $ctype, $WT_TREE; $sendmail = $this->getBlockSetting($block_id, 'sendmail', '1'); $days = $this->getBlockSetting($block_id, 'days', '1'); $block = $this->getBlockSetting($block_id, 'block', '1'); foreach (array('days', 'sendmail', 'block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $changes = Database::prepare("SELECT 1" . " FROM `##change`" . " WHERE status='pending'" . " LIMIT 1")->fetchOne(); if ($changes === '1' && $sendmail === '1') { // There are pending changes - tell moderators/managers/administrators about them. if (WT_TIMESTAMP - Site::getPreference('LAST_CHANGE_EMAIL') > 60 * 60 * 24 * $days) { // Which users have pending changes? foreach (User::all() as $user) { if ($user->getPreference('contactmethod') !== 'none') { foreach (Tree::getAll() as $tree) { if ($tree->hasPendingEdit() && Auth::isManager($tree, $user)) { I18N::init($user->getPreference('language')); Mail::systemMessage($tree, $user, I18N::translate('Pending changes'), I18N::translate('There are pending changes for you to moderate.') . Mail::EOL . Mail::EOL . '<a href="' . WT_BASE_URL . 'index.php?ged=' . $WT_TREE->getNameUrl() . '">' . WT_BASE_URL . 'index.php?ged=' . $WT_TREE->getNameUrl() . '</a>'); I18N::init(WT_LOCALE); } } } } Site::setPreference('LAST_CHANGE_EMAIL', WT_TIMESTAMP); } } if (Auth::isEditor($WT_TREE) && $WT_TREE->hasPendingEdit()) { $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; if ($ctype === 'user' || Auth::isManager($WT_TREE)) { $title = '<a class="icon-admin" title="' . I18N::translate('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; } else { $title = ''; } $title .= $this->getTitle(); $content = ''; if (Auth::isModerator($WT_TREE)) { $content .= "<a href=\"#\" onclick=\"window.open('edit_changes.php','_blank', chan_window_specs); return false;\">" . I18N::translate('There are pending changes for you to moderate.') . "</a><br>"; } if ($sendmail === '1') { $content .= I18N::translate('Last email reminder was sent ') . FunctionsDate::formatTimestamp(Site::getPreference('LAST_CHANGE_EMAIL')) . "<br>"; $content .= I18N::translate('Next email reminder will be sent after ') . FunctionsDate::formatTimestamp(Site::getPreference('LAST_CHANGE_EMAIL') + 60 * 60 * 24 * $days) . "<br><br>"; } $content .= '<ul>'; $changes = Database::prepare("SELECT xref" . " FROM `##change`" . " WHERE status='pending'" . " AND gedcom_id=?" . " GROUP BY xref")->execute(array($WT_TREE->getTreeId()))->fetchAll(); foreach ($changes as $change) { $record = GedcomRecord::getInstance($change->xref, $WT_TREE); if ($record->canShow()) { $content .= '<li><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></li>'; } } $content .= '</ul>'; if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } } }
/** * XML </ Relatives> */ private function relativesEndHandler() { global $report, $WT_TREE; $this->process_repeats--; if ($this->process_repeats > 0) { return; } // Check if there is any relatives if (count($this->list) > 0) { $lineoffset = 0; foreach ($this->repeats_stack as $rep) { $lineoffset += $rep[1]; } //-- read the xml from the file $lines = file($report); while (strpos($lines[$lineoffset + $this->repeat_bytes], "<Relatives") === false && $lineoffset + $this->repeat_bytes > 0) { $lineoffset--; } $lineoffset++; $reportxml = "<tempdoc>\n"; $line_nr = $lineoffset + $this->repeat_bytes; // Relatives Level counter $count = 1; while (0 < $count) { if (strpos($lines[$line_nr], "<Relatives") !== false) { $count++; } elseif (strpos($lines[$line_nr], "</Relatives") !== false) { $count--; } if (0 < $count) { $reportxml .= $lines[$line_nr]; } $line_nr++; } // No need to drag this unset($lines); $reportxml .= "</tempdoc>\n"; // Save original values array_push($this->parser_stack, $this->parser); $oldgedrec = $this->gedrec; $this->list_total = count($this->list); $this->list_private = 0; foreach ($this->list as $key => $value) { if (isset($value->generation)) { $this->generation = $value->generation; } $tmp = GedcomRecord::getInstance($key, $WT_TREE); $this->gedrec = $tmp->privatizeGedcom(Auth::accessLevel($WT_TREE)); $repeat_parser = xml_parser_create(); $this->parser = $repeat_parser; xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); xml_set_element_handler($repeat_parser, array($this, 'startElement'), array($this, 'endElement')); xml_set_character_data_handler($repeat_parser, array($this, 'characterData')); if (!xml_parse($repeat_parser, $reportxml, true)) { throw new \DomainException(sprintf("RelativesEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser))); } xml_parser_free($repeat_parser); } // Clean up the list array $this->list = array(); $this->parser = array_pop($this->parser_stack); $this->gedrec = $oldgedrec; } list($this->repeats, $this->repeat_bytes) = array_pop($this->repeats_stack); }
echo 'colspan="2"'; } echo ' style="text-align: center;">'; echo '<a href="', $place->getURL(), '&action=show" class="formField">', $place->getPlaceName(), '</a>'; echo '</td></tr>'; } echo '</table>'; } echo '</td></tr></table>'; if ($place_id && $action == 'show') { // -- array of names $myindilist = array(); $myfamlist = array(); $positions = Database::prepare("SELECT DISTINCT pl_gid FROM `##placelinks` WHERE pl_p_id=? AND pl_file=?")->execute(array($place_id, $WT_TREE->getTreeId()))->fetchOneColumn(); foreach ($positions as $position) { $record = GedcomRecord::getInstance($position, $WT_TREE); if ($record && $record->canShow()) { if ($record instanceof Individual) { $myindilist[] = $record; } if ($record instanceof Family) { $myfamlist[] = $record; } } } echo '<br>'; //-- display results $controller->addInlineJavascript('jQuery("#places-tabs").tabs();')->addInlineJavascript('jQuery("#places-tabs").css("visibility", "visible");')->addInlineJavascript('jQuery(".loading-image").css("display", "none");'); echo '<div class="loading-image"> </div>'; echo '<div id="places-tabs"><ul>'; if ($myindilist) {
/** * Generate the HTML content of this block. * * @param int $block_id * @param bool $template * @param string[] $cfg * * @return string */ public function getBlock($block_id, $template = true, $cfg = array()) { global $ctype, $controller, $WT_TREE; $action = Filter::get('action'); switch ($action) { case 'deletefav': $favorite_id = Filter::getInteger('favorite_id'); if ($favorite_id) { self::deleteFavorite($favorite_id); } break; case 'addfav': $gid = Filter::get('gid', WT_REGEX_XREF); $favnote = Filter::get('favnote'); $url = Filter::getUrl('url'); $favtitle = Filter::get('favtitle'); if ($gid) { $record = GedcomRecord::getInstance($gid, $WT_TREE); if ($record && $record->canShow()) { self::addFavorite(array('user_id' => $ctype === 'user' ? Auth::id() : null, 'gedcom_id' => $WT_TREE->getTreeId(), 'gid' => $record->getXref(), 'type' => $record::RECORD_TYPE, 'url' => null, 'note' => $favnote, 'title' => $favtitle)); } } elseif ($url) { self::addFavorite(array('user_id' => $ctype === 'user' ? Auth::id() : null, 'gedcom_id' => $WT_TREE->getTreeId(), 'gid' => null, 'type' => 'URL', 'url' => $url, 'note' => $favnote, 'title' => $favtitle ? $favtitle : $url)); } break; } $block = $this->getBlockSetting($block_id, 'block', '0'); foreach (array('block') as $name) { if (array_key_exists($name, $cfg)) { ${$name} = $cfg[$name]; } } $userfavs = $this->getFavorites($ctype === 'user' ? Auth::id() : $WT_TREE->getTreeId()); if (!is_array($userfavs)) { $userfavs = array(); } $id = $this->getName() . $block_id; $class = $this->getName() . '_block'; $title = $this->getTitle(); if (Auth::check()) { $controller->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL)->addInlineJavascript('autocomplete();'); } $content = ''; if ($userfavs) { foreach ($userfavs as $key => $favorite) { if (isset($favorite['id'])) { $key = $favorite['id']; } $removeFavourite = '<a class="font9" href="index.php?ctype=' . $ctype . '&ged=' . $WT_TREE->getNameHtml() . '&action=deletefav&favorite_id=' . $key . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to remove this item from your list of favorites?') . '\');">' . I18N::translate('Remove') . '</a> '; if ($favorite['type'] == 'URL') { $content .= '<div id="boxurl' . $key . '.0" class="person_box">'; if ($ctype == 'user' || Auth::isManager($WT_TREE)) { $content .= $removeFavourite; } $content .= '<a href="' . $favorite['url'] . '"><b>' . $favorite['title'] . '</b></a>'; $content .= '<br>' . $favorite['note']; $content .= '</div>'; } else { $record = GedcomRecord::getInstance($favorite['gid'], $WT_TREE); if ($record && $record->canShow()) { if ($record instanceof Individual) { $content .= '<div id="box' . $favorite["gid"] . '.0" class="person_box action_header'; switch ($record->getsex()) { case 'M': break; case 'F': $content .= 'F'; break; default: $content .= 'NN'; break; } $content .= '">'; if ($ctype == "user" || Auth::isManager($WT_TREE)) { $content .= $removeFavourite; } $content .= Theme::theme()->individualBoxLarge($record); $content .= $favorite['note']; $content .= '</div>'; } else { $content .= '<div id="box' . $favorite['gid'] . '.0" class="person_box">'; if ($ctype == 'user' || Auth::isManager($WT_TREE)) { $content .= $removeFavourite; } $content .= $record->formatList('span'); $content .= '<br>' . $favorite['note']; $content .= '</div>'; } } } } } if ($ctype == 'user' || Auth::isManager($WT_TREE)) { $uniqueID = Uuid::uuid4(); // This block can theoretically appear multiple times, so use a unique ID. $content .= '<div class="add_fav_head">'; $content .= '<a href="#" onclick="return expand_layer(\'add_fav' . $uniqueID . '\');">' . I18N::translate('Add a new favorite') . '<i id="add_fav' . $uniqueID . '_img" class="icon-plus"></i></a>'; $content .= '</div>'; $content .= '<div id="add_fav' . $uniqueID . '" style="display: none;">'; $content .= '<form name="addfavform" method="get" action="index.php">'; $content .= '<input type="hidden" name="action" value="addfav">'; $content .= '<input type="hidden" name="ctype" value="' . $ctype . '">'; $content .= '<input type="hidden" name="ged" value="' . $WT_TREE->getNameHtml() . '">'; $content .= '<div class="add_fav_ref">'; $content .= '<input type="radio" name="fav_category" value="record" checked onclick="jQuery(\'#gid' . $uniqueID . '\').removeAttr(\'disabled\'); jQuery(\'#url, #favtitle\').attr(\'disabled\',\'disabled\').val(\'\');">'; $content .= '<label for="gid' . $uniqueID . '">' . I18N::translate('Enter an individual, family, or source ID') . '</label>'; $content .= '<input class="pedigree_form" data-autocomplete-type="IFSRO" type="text" name="gid" id="gid' . $uniqueID . '" size="5" value="">'; $content .= ' ' . FunctionsPrint::printFindIndividualLink('gid' . $uniqueID); $content .= ' ' . FunctionsPrint::printFindFamilyLink('gid' . $uniqueID); $content .= ' ' . FunctionsPrint::printFindSourceLink('gid' . $uniqueID); $content .= ' ' . FunctionsPrint::printFindRepositoryLink('gid' . $uniqueID); $content .= ' ' . FunctionsPrint::printFindNoteLink('gid' . $uniqueID); $content .= ' ' . FunctionsPrint::printFindMediaLink('gid' . $uniqueID); $content .= '</div>'; $content .= '<div class="add_fav_url">'; $content .= '<input type="radio" name="fav_category" value="url" onclick="jQuery(\'#url, #favtitle\').removeAttr(\'disabled\'); jQuery(\'#gid' . $uniqueID . '\').attr(\'disabled\',\'disabled\').val(\'\');">'; $content .= '<input type="text" name="url" id="url" size="20" value="" placeholder="' . GedcomTag::getLabel('URL') . '" disabled> '; $content .= '<input type="text" name="favtitle" id="favtitle" size="20" value="" placeholder="' . I18N::translate('Title') . '" disabled>'; $content .= '<p>' . I18N::translate('Enter an optional note about this favorite') . '</p>'; $content .= '<textarea name="favnote" rows="6" cols="50"></textarea>'; $content .= '</div>'; $content .= '<input type="submit" value="' . I18N::translate('Add') . '">'; $content .= '</form></div>'; } if ($template) { if ($block) { $class .= ' small_inner_block'; } return Theme::theme()->formatBlock($id, $title, $class, $content); } else { return $content; } }
// Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges() $glevels = array_merge(array('1'), $glevels); $tag = array_merge(array('FILE'), $tag); $islink = array_merge(array(0), $islink); $text = array_merge(array($newFilename), $text); $record = GedcomRecord::getInstance($pid, $WT_TREE); $newrec = "0 @{$pid}@ OBJE\n"; $newrec = FunctionsEdit::handleUpdates($newrec); $record->updateRecord($newrec, $update_CHAN); if ($move_file) { // We've moved a file. Therefore we must approve the change, as rejecting // the change will create broken references. FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId()); } if ($pid && $linktoid) { $record = GedcomRecord::getInstance($linktoid, $WT_TREE); $record->createFact('1 OBJE @' . $pid . '@', true); Log::addEditLog('Media ID ' . $pid . " successfully added to {$linktoid}."); } $controller->pageHeader(); if ($messages) { echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; } else { $controller->addInlineJavascript('closePopupAndReloadParent();'); } return; case 'showmediaform': $controller->setPageTitle(I18N::translate('Create a new media object')); $action = 'create'; break; case 'editmedia':
/** * Events * * @param string $type * @param string $direction * @param string $facts * * @return string */ private function eventQuery($type, $direction, $facts) { $eventTypes = array('BIRT' => I18N::translate('birth'), 'DEAT' => I18N::translate('death'), 'MARR' => I18N::translate('marriage'), 'ADOP' => I18N::translate('adoption'), 'BURI' => I18N::translate('burial'), 'CENS' => I18N::translate('census added')); $fact_query = "IN ('" . str_replace('|', "','", $facts) . "')"; if ($direction != 'ASC') { $direction = 'DESC'; } $rows = $this->runSql('' . ' SELECT SQL_CACHE' . ' d_gid AS id,' . ' d_year AS year,' . ' d_fact AS fact,' . ' d_type AS type' . ' FROM' . " `##dates`" . ' WHERE' . " d_file={$this->tree->getTreeId()} AND" . " d_gid<>'HEAD' AND" . " d_fact {$fact_query} AND" . ' d_julianday1<>0' . ' ORDER BY' . " d_julianday1 {$direction}, d_type LIMIT 1"); if (!isset($rows[0])) { return ''; } $row = $rows[0]; $record = GedcomRecord::getInstance($row['id'], $this->tree); switch ($type) { default: case 'full': if ($record->canShow()) { $result = $record->formatList('span', false, $record->getFullName()); } else { $result = I18N::translate('This information is private and cannot be shown.'); } break; case 'year': $date = new Date($row['type'] . ' ' . $row['year']); $result = $date->display(); break; case 'type': if (isset($eventTypes[$row['fact']])) { $result = $eventTypes[$row['fact']]; } else { $result = GedcomTag::getLabel($row['fact']); } break; case 'name': $result = "<a href=\"" . $record->getHtmlUrl() . "\">" . $record->getFullName() . "</a>"; break; case 'place': $fact = $record->getFirstFact($row['fact']); if ($fact) { $result = FunctionsPrint::formatFactPlace($fact, true, true, true); } else { $result = I18N::translate('Private'); } break; } return $result; }
/** * Print a row for the notes tab on the individual page. * * @param Fact $fact * @param int $level */ public static function printMainNotes(Fact $fact, $level) { $factrec = $fact->getGedcom(); $fact_id = $fact->getFactId(); $parent = $fact->getParent(); $pid = $parent->getXref(); if ($fact->isPendingAddition()) { $styleadd = ' new'; $can_edit = $level == 1 && $fact->canEdit(); } elseif ($fact->isPendingDeletion()) { $styleadd = ' old'; $can_edit = false; } else { $styleadd = ''; $can_edit = $level == 1 && $fact->canEdit(); } $ct = preg_match_all("/{$level} NOTE (.*)/", $factrec, $match, PREG_SET_ORDER); for ($j = 0; $j < $ct; $j++) { // Note object, or inline note? if (preg_match("/{$level} NOTE @(.*)@/", $match[$j][0], $nmatch)) { $note = Note::getInstance($nmatch[1], $fact->getParent()->getTree()); if ($note && !$note->canShow()) { continue; } } else { $note = null; } if ($level >= 2) { echo '<tr class="row_note2"><td class="descriptionbox rela ', $styleadd, ' width20">'; } else { echo '<tr><td class="descriptionbox ', $styleadd, ' width20">'; } if ($can_edit) { echo '<a onclick="return edit_record(\'', $pid, '\', \'', $fact_id, '\');" href="#" title="', I18N::translate('Edit'), '">'; if ($level < 2) { if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) { echo '<i class="icon-note"></i> '; } if ($note) { echo GedcomTag::getLabel('SHARED_NOTE'); } else { echo GedcomTag::getLabel('NOTE'); } echo '</a>'; echo '<div class="editfacts">'; echo "<div class=\"editlink\"><a class=\"editicon\" onclick=\"return edit_record('{$pid}', '{$fact_id}');\" href=\"#\" title=\"" . I18N::translate('Edit') . "\"><span class=\"link_text\">" . I18N::translate('Edit') . "</span></a></div>"; echo '<div class="copylink"><a class="copyicon" href="#" onclick="return copy_fact(\'', $pid, '\', \'', $fact_id, '\');" title="' . I18N::translate('Copy') . '"><span class="link_text">' . I18N::translate('Copy') . '</span></a></div>'; echo "<div class=\"deletelink\"><a class=\"deleteicon\" onclick=\"return delete_fact('" . I18N::translate('Are you sure you want to delete this fact?') . "', '{$pid}', '{$fact_id}');\" href=\"#\" title=\"" . I18N::translate('Delete') . "\"><span class=\"link_text\">" . I18N::translate('Delete') . "</span></a></div>"; if ($note) { echo '<a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a>'; } echo '</div>'; } } else { if ($level < 2) { if ($fact->getParent()->getTree()->getPreference('SHOW_FACT_ICONS')) { echo '<i class="icon-note"></i> '; } if ($note) { echo GedcomTag::getLabel('SHARED_NOTE'); } else { echo GedcomTag::getLabel('NOTE'); } } $factlines = explode("\n", $factrec); // 1 BIRT Y\n2 NOTE ... $factwords = explode(" ", $factlines[0]); // 1 BIRT Y $factname = $factwords[1]; // BIRT $parent = GedcomRecord::getInstance($pid, $fact->getParent()->getTree()); if ($factname == 'EVEN' || $factname == 'FACT') { // Add ' EVEN' to provide sensible output for an event with an empty TYPE record $ct = preg_match("/2 TYPE (.*)/", $factrec, $ematch); if ($ct > 0) { $factname = trim($ematch[1]); echo $factname; } else { echo GedcomTag::getLabel($factname, $parent); } } elseif ($factname != 'NOTE') { // Note is already printed echo GedcomTag::getLabel($factname, $parent); if ($note) { echo '<div class="editfacts"><a class="icon-note" href="', $note->getHtmlUrl(), '" title="' . I18N::translate('View') . '"><span class="link_text">' . I18N::translate('View') . '</span></a></div>'; } } } echo '</td>'; if ($note) { // Note objects if (Module::getModuleByName('GEDFact_assistant')) { // If Census assistant installed, allow it to format the note $text = CensusAssistantModule::formatCensusNote($note); } else { $text = Filter::formatText($note->getNote(), $fact->getParent()->getTree()); } } else { // Inline notes $nrec = Functions::getSubRecord($level, "{$level} NOTE", $factrec, $j + 1); $text = $match[$j][1] . Functions::getCont($level + 1, $nrec); $text = Filter::formatText($text, $fact->getParent()->getTree()); } echo '<td class="optionbox', $styleadd, ' wrap">'; echo $text; if (!empty($noterec)) { echo self::printFactSources($noterec, 1); } // 2 RESN tags. Note, there can be more than one, such as "privacy" and "locked" if (preg_match_all("/\n2 RESN (.+)/", $factrec, $matches)) { foreach ($matches[1] as $match) { echo '<br><span class="label">', GedcomTag::getLabel('RESN'), ':</span> <span class="field">'; switch ($match) { case 'none': // Note: "2 RESN none" is not valid gedcom, and the GUI will not let you add it. // However, webtrees privacy rules will interpret it as "show an otherwise private fact to public". echo '<i class="icon-resn-none"></i> ', I18N::translate('Show to visitors'); break; case 'privacy': echo '<i class="icon-resn-privacy"></i> ', I18N::translate('Show to members'); break; case 'confidential': echo '<i class="icon-resn-confidential"></i> ', I18N::translate('Show to managers'); break; case 'locked': echo '<i class="icon-resn-locked"></i> ', I18N::translate('Only managers can edit'); break; default: echo $match; break; } echo '</span>'; } } echo '</td></tr>'; } }
/** * add a new tag input field * * called for each fact to be edited on a form. * Fact level=0 means a new empty form : data are POSTed by name * else data are POSTed using arrays : * glevels[] : tag level * islink[] : tag is a link * tag[] : tag name * text[] : tag value * * @param string $tag fact record to edit (eg 2 DATE xxxxx) * @param string $upperlevel optional upper level tag (eg BIRT) * @param string $label An optional label to echo instead of the default * @param string $extra optional text to display after the input field * @param Individual $person For male/female translations * * @return string */ public static function addSimpleTag($tag, $upperlevel = '', $label = '', $extra = null, Individual $person = null) { global $tags, $main_fact, $xref, $bdm, $action, $WT_TREE; // Keep track of SOUR fields, so we can reference them in subsequent PAGE fields. static $source_element_id; $subnamefacts = array('NPFX', 'GIVN', 'SPFX', 'SURN', 'NSFX', '_MARNM_SURN'); preg_match('/^(?:(\\d+) (' . WT_REGEX_TAG . ') ?(.*))/', $tag, $match); list(, $level, $fact, $value) = $match; $level = (int) $level; // element name : used to POST data if ($level === 0) { if ($upperlevel) { $element_name = $upperlevel . '_' . $fact; } else { $element_name = $fact; } } else { $element_name = 'text[]'; } if ($level === 1) { $main_fact = $fact; } // element id : used by javascript functions if ($level === 0) { $element_id = $fact; } else { $element_id = $fact . Uuid::uuid4(); } if ($upperlevel) { $element_id = $upperlevel . '_' . $fact . Uuid::uuid4(); } // field value $islink = substr($value, 0, 1) === '@' && substr($value, 0, 2) !== '@#'; if ($islink) { $value = trim(substr($tag, strlen($fact) + 3), ' @\\r'); } else { $value = (string) substr($tag, strlen($fact) + 3); } if ($fact === 'REPO' || $fact === 'SOUR' || $fact === 'OBJE' || $fact === 'FAMC') { $islink = true; } if ($fact === 'SHARED_NOTE_EDIT' || $fact === 'SHARED_NOTE') { $islink = true; $fact = 'NOTE'; } // label echo '<tr id="', $element_id, '_tr"'; if ($fact === 'MAP' || ($fact === 'LATI' || $fact === 'LONG') && $value === '') { echo ' style="display:none;"'; } echo '>'; if (in_array($fact, $subnamefacts) || $fact === 'LATI' || $fact === 'LONG') { echo '<td class="optionbox wrap width25">'; } else { echo '<td class="descriptionbox wrap width25">'; } // tag name if ($label) { echo $label; } elseif ($upperlevel) { echo GedcomTag::getLabel($upperlevel . ':' . $fact); } else { echo GedcomTag::getLabel($fact); } // If using GEDFact-assistant window if ($action === 'addnewnote_assisted') { // Do not print on GEDFact Assistant window } else { // Not all facts have help text. switch ($fact) { case 'NAME': if ($upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN') { echo FunctionsPrint::helpLink($fact); } break; case 'DATE': case 'PLAC': case 'RESN': case 'ROMN': case 'SURN': case '_HEB': echo FunctionsPrint::helpLink($fact); break; } } // tag level if ($level > 0) { if ($fact === 'TEXT' && $level > 1) { echo '<input type="hidden" name="glevels[]" value="', $level - 1, '">'; echo '<input type="hidden" name="islink[]" value="0">'; echo '<input type="hidden" name="tag[]" value="DATA">'; // leave data text[] value empty because the following TEXT line will cause the DATA to be added echo '<input type="hidden" name="text[]" value="">'; } echo '<input type="hidden" name="glevels[]" value="', $level, '">'; echo '<input type="hidden" name="islink[]" value="', $islink, '">'; echo '<input type="hidden" name="tag[]" value="', $fact, '">'; } echo '</td>'; // value echo '<td class="optionbox wrap">'; // retrieve linked NOTE if ($fact === 'NOTE' && $islink) { $note1 = Note::getInstance($value, $WT_TREE); if ($note1) { $noterec = $note1->getGedcom(); preg_match('/' . $value . '/i', $noterec, $notematch); $value = $notematch[0]; } } // Show names for spouses in MARR/HUSB/AGE and MARR/WIFE/AGE if ($fact === 'HUSB' || $fact === 'WIFE') { $family = Family::getInstance($xref, $WT_TREE); if ($family) { $spouse_link = $family->getFirstFact($fact); if ($spouse_link) { $spouse = $spouse_link->getTarget(); if ($spouse) { echo $spouse->getFullName(); } } } } if (in_array($fact, Config::emptyFacts()) && ($value === '' || $value === 'Y' || $value === 'y')) { echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" value="', $value, '">'; if ($level <= 1) { echo '<input type="checkbox" '; if ($value) { echo 'checked'; } echo ' onclick="document.getElementById(\'' . $element_id . '\').value = (this.checked) ? \'Y\' : \'\';">'; echo I18N::translate('yes'); } if ($fact === 'CENS' && $value === 'Y') { echo self::censusDateSelector(WT_LOCALE, $xref); if (Module::getModuleByName('GEDFact_assistant') && GedcomRecord::getInstance($xref, $WT_TREE) instanceof Individual) { echo '<div></div><a href="#" style="display: none;" id="assistant-link" onclick="return activateCensusAssistant();">' . I18N::translate('Create a new shared note using assistant') . '</a></div>'; } } } elseif ($fact === 'TEMP') { echo self::selectEditControl($element_name, GedcomCodeTemp::templeNames(), I18N::translate('No temple - living ordinance'), $value); } elseif ($fact === 'ADOP') { echo self::editFieldAdoption($element_name, $value, '', $person); } elseif ($fact === 'PEDI') { echo self::editFieldPedigree($element_name, $value, '', $person); } elseif ($fact === 'STAT') { echo self::selectEditControl($element_name, GedcomCodeStat::statusNames($upperlevel), '', $value); } elseif ($fact === 'RELA') { echo self::editFieldRelationship($element_name, strtolower($value)); } elseif ($fact === 'QUAY') { echo self::selectEditControl($element_name, GedcomCodeQuay::getValues(), '', $value); } elseif ($fact === '_WT_USER') { echo self::editFieldUsername($element_name, $value); } elseif ($fact === 'RESN') { echo self::editFieldRestriction($element_name, $value); } elseif ($fact === '_PRIM') { echo '<select id="', $element_id, '" name="', $element_name, '" >'; echo '<option value=""></option>'; echo '<option value="Y" '; if ($value === 'Y') { echo ' selected'; } echo '>', I18N::translate('always'), '</option>'; echo '<option value="N" '; if ($value === 'N') { echo 'selected'; } echo '>', I18N::translate('never'), '</option>'; echo '</select>'; echo '<p class="small text-muted">', I18N::translate('Use this image for charts and on the individual’s page.'), '</p>'; } elseif ($fact === 'SEX') { echo '<select id="', $element_id, '" name="', $element_name, '"><option value="M" '; if ($value === 'M') { echo 'selected'; } echo '>', I18N::translate('Male'), '</option><option value="F" '; if ($value === 'F') { echo 'selected'; } echo '>', I18N::translate('Female'), '</option><option value="U" '; if ($value === 'U' || empty($value)) { echo 'selected'; } echo '>', I18N::translateContext('unknown gender', 'Unknown'), '</option></select>'; } elseif ($fact === 'TYPE' && $level === 3) { //-- Build the selector for the Media 'TYPE' Fact echo '<select name="text[]"><option selected value="" ></option>'; $selectedValue = strtolower($value); if (!array_key_exists($selectedValue, GedcomTag::getFileFormTypes())) { echo '<option selected value="', Filter::escapeHtml($value), '" >', Filter::escapeHtml($value), '</option>'; } foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue) { echo '<option value="', $typeName, '" '; if ($selectedValue === $typeName) { echo 'selected'; } echo '>', $typeValue, '</option>'; } echo '</select>'; } elseif ($fact === 'NAME' && $upperlevel !== 'REPO' && $upperlevel !== 'UNKNOWN' || $fact === '_MARNM') { // Populated in javascript from sub-tags echo '<input type="hidden" id="', $element_id, '" name="', $element_name, '" onchange="updateTextName(\'', $element_id, '\');" value="', Filter::escapeHtml($value), '" class="', $fact, '">'; echo '<span id="', $element_id, '_display" dir="auto">', Filter::escapeHtml($value), '</span>'; echo ' <a href="#edit_name" onclick="convertHidden(\'', $element_id, '\'); return false;" class="icon-edit_indi" title="' . I18N::translate('Edit name') . '"></a>'; } else { // textarea if ($fact === 'TEXT' || $fact === 'ADDR' || $fact === 'NOTE' && !$islink) { echo '<textarea id="', $element_id, '" name="', $element_name, '" dir="auto">', Filter::escapeHtml($value), '</textarea><br>'; } else { // text // If using GEDFact-assistant window if ($action === 'addnewnote_assisted') { echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" style="width:4.1em;" dir="ltr"'; } else { echo '<input type="text" id="', $element_id, '" name="', $element_name, '" value="', Filter::escapeHtml($value), '" dir="ltr"'; } echo ' class="', $fact, '"'; if (in_array($fact, $subnamefacts)) { echo ' onblur="updatewholename();" onkeyup="updatewholename();"'; } // Extra markup for specific fact types switch ($fact) { case 'ALIA': case 'ASSO': case '_ASSO': echo ' data-autocomplete-type="ASSO" data-autocomplete-extra="input.DATE"'; break; case 'DATE': echo ' onblur="valid_date(this);" onmouseout="valid_date(this);"'; break; case 'GIVN': echo ' autofocus data-autocomplete-type="GIVN"'; break; case 'LATI': echo ' onblur="valid_lati_long(this, \'N\', \'S\');" onmouseout="valid_lati_long(this, \'N\', \'S\');"'; break; case 'LONG': echo ' onblur="valid_lati_long(this, \'E\', \'W\');" onmouseout="valid_lati_long(this, \'E\', \'W\');"'; break; case 'NOTE': // Shared notes. Inline notes are handled elsewhere. echo ' data-autocomplete-type="NOTE"'; break; case 'OBJE': echo ' data-autocomplete-type="OBJE"'; break; case 'PAGE': echo ' data-autocomplete-type="PAGE" data-autocomplete-extra="#' . $source_element_id . '"'; break; case 'PLAC': echo ' data-autocomplete-type="PLAC"'; break; case 'REPO': echo ' data-autocomplete-type="REPO"'; break; case 'SOUR': $source_element_id = $element_id; echo ' data-autocomplete-type="SOUR"'; break; case 'SURN': case '_MARNM_SURN': echo ' data-autocomplete-type="SURN"'; break; case 'TIME': echo ' pattern="([0-1][0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?" dir="ltr" placeholder="' . I18N::translate('hh:mm or hh:mm:ss') . '"'; break; } echo '>'; } $tmp_array = array('TYPE', 'TIME', 'NOTE', 'SOUR', 'REPO', 'OBJE', 'ASSO', '_ASSO', 'AGE'); // split PLAC if ($fact === 'PLAC') { echo '<div id="', $element_id, '_pop" style="display: inline;">'; echo FunctionsPrint::printSpecialCharacterLink($element_id), ' ', FunctionsPrint::printFindPlaceLink($element_id); echo '<span onclick="jQuery(\'tr[id^=', $upperlevel, '_LATI],tr[id^=', $upperlevel, '_LONG],tr[id^=LATI],tr[id^=LONG]\').toggle(\'fast\'); return false;" class="icon-target" title="', GedcomTag::getLabel('LATI'), ' / ', GedcomTag::getLabel('LONG'), '"></span>'; echo '</div>'; if (Module::getModuleByName('places_assistant')) { \PlacesAssistantModule::setup_place_subfields($element_id); \PlacesAssistantModule::print_place_subfields($element_id); } } elseif (!in_array($fact, $tmp_array)) { echo FunctionsPrint::printSpecialCharacterLink($element_id); } } // MARRiage TYPE : hide text field and show a selection list if ($fact === 'TYPE' && $level === 2 && $tags[0] === 'MARR') { echo '<script>'; echo 'document.getElementById(\'', $element_id, '\').style.display=\'none\''; echo '</script>'; echo '<select id="', $element_id, '_sel" onchange="document.getElementById(\'', $element_id, '\').value=this.value;" >'; foreach (array('Unknown', 'Civil', 'Religious', 'Partners') as $key) { if ($key === 'Unknown') { echo '<option value="" '; } else { echo '<option value="', $key, '" '; } $a = strtolower($key); $b = strtolower($value); if ($b !== '' && strpos($a, $b) !== false || strpos($b, $a) !== false) { echo 'selected'; } echo '>', GedcomTag::getLabel('MARR_' . strtoupper($key)), '</option>'; } echo '</select>'; } elseif ($fact === 'TYPE' && $level === 0) { // NAME TYPE : hide text field and show a selection list $onchange = 'onchange="document.getElementById(\'' . $element_id . '\').value=this.value;"'; echo self::editFieldNameType($element_name, $value, $onchange, $person); echo '<script>document.getElementById("', $element_id, '").style.display="none";</script>'; } // popup links switch ($fact) { case 'DATE': echo self::printCalendarPopup($element_id); break; case 'FAMC': case 'FAMS': echo FunctionsPrint::printFindFamilyLink($element_id); break; case 'ALIA': case 'ASSO': case '_ASSO': echo FunctionsPrint::printFindIndividualLink($element_id, $element_id . '_description'); break; case 'FILE': FunctionsPrint::printFindMediaLink($element_id, '0file'); break; case 'SOUR': echo FunctionsPrint::printFindSourceLink($element_id, $element_id . '_description'), ' ', self::printAddNewSourceLink($element_id); //-- checkboxes to apply '1 SOUR' to BIRT/MARR/DEAT as '2 SOUR' if ($level === 1) { echo '<br>'; switch ($WT_TREE->getPreference('PREFER_LEVEL2_SOURCES')) { case '2': // records $level1_checked = 'checked'; $level2_checked = ''; break; case '1': // facts $level1_checked = ''; $level2_checked = 'checked'; break; case '0': // none // none default: $level1_checked = ''; $level2_checked = ''; break; } if (strpos($bdm, 'B') !== false) { echo ' <label><input type="checkbox" name="SOUR_INDI" ', $level1_checked, ' value="1">', I18N::translate('Individual'), '</label>'; if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { foreach ($matches[1] as $match) { if (!in_array($match, explode('|', WT_EVENTS_DEAT))) { echo ' <label><input type="checkbox" name="SOUR_', $match, '" ', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>'; } } } } if (strpos($bdm, 'D') !== false) { if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FACTS'), $matches)) { foreach ($matches[1] as $match) { if (in_array($match, explode('|', WT_EVENTS_DEAT))) { echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>'; } } } } if (strpos($bdm, 'M') !== false) { echo ' <label><input type="checkbox" name="SOUR_FAM" ', $level1_checked, ' value="1">', I18N::translate('Family'), '</label>'; if (preg_match_all('/(' . WT_REGEX_TAG . ')/', $WT_TREE->getPreference('QUICK_REQUIRED_FAMFACTS'), $matches)) { foreach ($matches[1] as $match) { echo ' <label><input type="checkbox" name="SOUR_', $match, '"', $level2_checked, ' value="1">', GedcomTag::getLabel($match), '</label>'; } } } } break; case 'REPO': echo FunctionsPrint::printFindRepositoryLink($element_id), ' ', self::printAddNewRepositoryLink($element_id); break; case 'NOTE': // Shared Notes Icons ======================================== if ($islink) { // Print regular Shared Note icons --------------------------- echo ' ', FunctionsPrint::printFindNoteLink($element_id, $element_id . '_description'), ' ', self::printAddNewNoteLink($element_id); if ($value) { echo ' ', self::printEditNoteLink($value); } } break; case 'OBJE': echo FunctionsPrint::printFindMediaLink($element_id, '1media'); if (!$value) { echo ' ', self::printAddNewMediaLink($element_id); $value = 'new'; } break; } echo '<div id="' . $element_id . '_description">'; // current value if ($fact === 'DATE') { $date = new Date($value); echo $date->display(); } if (($fact === 'ASSO' || $fact === '_ASSO') && $value === '') { if ($level === 1) { echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this individual, such as a friend or an employer.') . '</p>'; } else { echo '<p class="small text-muted">' . I18N::translate('An associate is another individual who was involved with this fact or event, such as a witness or a priest.') . '</p>'; } } if ($value && $value !== 'new' && $islink) { switch ($fact) { case 'ALIA': case 'ASSO': case '_ASSO': $tmp = Individual::getInstance($value, $WT_TREE); if ($tmp) { echo ' ', $tmp->getFullName(); } break; case 'SOUR': $tmp = Source::getInstance($value, $WT_TREE); if ($tmp) { echo ' ', $tmp->getFullName(); } break; case 'NOTE': $tmp = Note::getInstance($value, $WT_TREE); if ($tmp) { echo ' ', $tmp->getFullName(); } break; case 'OBJE': $tmp = Media::getInstance($value, $WT_TREE); if ($tmp) { echo ' ', $tmp->getFullName(); } break; case 'REPO': $tmp = Repository::getInstance($value, $WT_TREE); if ($tmp) { echo ' ', $tmp->getFullName(); } break; } } // pastable values if ($fact === 'FORM' && $upperlevel === 'OBJE') { FunctionsPrint::printAutoPasteLink($element_id, Config::fileFormats()); } echo '</div>', $extra, '</td></tr>'; return $element_id; }
// Level 1 links $source->deleteFact($fact->getFactId(), true); } elseif (strpos($fact->getGedcom(), ' @' . $target . '@')) { // Level 2-3 links $source->updateFact($fact->getFactId(), preg_replace(array('/\\n2 OBJE @' . $target . '@(\\n[3-9].*)*/', '/\\n3 OBJE @' . $target . '@(\\n[4-9].*)*/'), '', $fact->getGedcom()), true); } } } } } else { http_response_code(406); } break; case 'reject-changes': // Reject all the pending changes for a record $record = GedcomRecord::getInstance(Filter::post('xref', WT_REGEX_XREF), $WT_TREE); if ($record && $record->canEdit() && Auth::isModerator($record->getTree())) { FlashMessages::addMessage(I18N::translate('The changes to “%s” have been rejected.', $record->getFullName())); FunctionsImport::rejectAllChanges($record); } else { http_response_code(406); } break; case 'theme': // Change the current theme $theme = Filter::post('theme'); if (Site::getPreference('ALLOW_USER_THEMES') && array_key_exists($theme, Theme::themeNames())) { Session::put('theme_id', $theme); // Remember our selection Auth::user()->setPreference('theme', $theme); } else {
/** * Get the current view of a record, allowing for pending changes * * @param string $xref * @param string $type * * @return string */ public static function getLatestRecord($xref, $type) { global $WT_TREE; switch ($type) { case 'INDI': return Individual::getInstance($xref, $WT_TREE)->getGedcom(); case 'FAM': return Family::getInstance($xref, $WT_TREE)->getGedcom(); case 'SOUR': return Source::getInstance($xref, $WT_TREE)->getGedcom(); case 'REPO': return Repository::getInstance($xref, $WT_TREE)->getGedcom(); case 'OBJE': return Media::getInstance($xref, $WT_TREE)->getGedcom(); case 'NOTE': return Note::getInstance($xref, $WT_TREE)->getGedcom(); default: return GedcomRecord::getInstance($xref, $WT_TREE)->getGedcom(); } }
/** * Export the database in GEDCOM format * * @param Tree $tree Which tree to export * @param resource $gedout Handle to a writable stream * @param string[] $exportOptions Export options are as follows: * 'privatize': which Privacy rules apply? (none, visitor, user, manager) * 'toANSI': should the output be produced in ISO-8859-1 instead of UTF-8? (yes, no) * 'path': what constant should prefix all media file paths? (eg: media/ or c:\my pictures\my family * 'slashes': what folder separators apply to media file paths? (forward, backward) */ public static function exportGedcom(Tree $tree, $gedout, $exportOptions) { switch ($exportOptions['privatize']) { case 'gedadmin': $access_level = Auth::PRIV_NONE; break; case 'user': $access_level = Auth::PRIV_USER; break; case 'visitor': $access_level = Auth::PRIV_PRIVATE; break; case 'none': $access_level = Auth::PRIV_HIDE; break; } $head = self::gedcomHeader($tree); if ($exportOptions['toANSI'] == 'yes') { $head = str_replace('UTF-8', 'ANSI', $head); $head = utf8_decode($head); } $head = self::reformatRecord($head); fwrite($gedout, $head); // Buffer the output. Lots of small fwrite() calls can be very slow when writing large gedcoms. $buffer = ''; // Generate the OBJE/SOUR/REPO/NOTE records first, as their privacy calcualations involve // database queries, and we wish to avoid large gaps between queries due to MySQL connection timeouts. $tmp_gedcom = ''; $rows = Database::prepare("SELECT m_id AS xref, m_gedcom AS gedcom" . " FROM `##media` WHERE m_file = :tree_id ORDER BY m_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Media::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); $rec = self::convertMediaPath($rec, $exportOptions['path']); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT s_id AS xref, s_file AS gedcom_id, s_gedcom AS gedcom" . " FROM `##sources` WHERE s_file = :tree_id ORDER BY s_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Source::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT o_type AS type, o_id AS xref, o_gedcom AS gedcom" . " FROM `##other` WHERE o_file = :tree_id AND o_type NOT IN ('HEAD', 'TRLR') ORDER BY o_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { switch ($row->type) { case 'NOTE': $record = Note::getInstance($row->xref, $tree, $row->gedcom); break; case 'REPO': $record = Repository::getInstance($row->xref, $tree, $row->gedcom); break; default: $record = GedcomRecord::getInstance($row->xref, $tree, $row->gedcom); break; } $rec = $record->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $tmp_gedcom .= self::reformatRecord($rec); } $rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals` WHERE i_file = :tree_id ORDER BY i_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Individual::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $buffer .= self::reformatRecord($rec); if (strlen($buffer) > 65536) { fwrite($gedout, $buffer); $buffer = ''; } } $rows = Database::prepare("SELECT f_id AS xref, f_gedcom AS gedcom" . " FROM `##families` WHERE f_file = :tree_id ORDER BY f_id")->execute(array('tree_id' => $tree->getTreeId()))->fetchAll(); foreach ($rows as $row) { $rec = Family::getInstance($row->xref, $tree, $row->gedcom)->privatizeGedcom($access_level); if ($exportOptions['toANSI'] === 'yes') { $rec = utf8_decode($rec); } $buffer .= self::reformatRecord($rec); if (strlen($buffer) > 65536) { fwrite($gedout, $buffer); $buffer = ''; } } fwrite($gedout, $buffer); fwrite($gedout, $tmp_gedcom); fwrite($gedout, '0 TRLR' . WT_EOL); }
/** * Favorites menu. * * @return Menu|null */ protected function menuFavorites() { global $controller; $show_user_favorites = $this->tree && Module::getModuleByName('user_favorites') && Auth::check(); $show_tree_favorites = $this->tree && Module::getModuleByName('gedcom_favorites'); if ($show_user_favorites && $show_tree_favorites) { $favorites = array_merge(FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()), UserFavoritesModule::getFavorites(Auth::id())); } elseif ($show_user_favorites) { $favorites = UserFavoritesModule::getFavorites(Auth::id()); } elseif ($show_tree_favorites) { $favorites = FamilyTreeFavoritesModule::getFavorites($this->tree->getTreeId()); } else { $favorites = array(); } $submenus = array(); $records = array(); foreach ($favorites as $favorite) { switch ($favorite['type']) { case 'URL': $submenus[] = new Menu($favorite['title'], $favorite['url']); break; case 'INDI': case 'FAM': case 'SOUR': case 'OBJE': case 'NOTE': $record = GedcomRecord::getInstance($favorite['gid'], $this->tree); if ($record && $record->canShowName()) { $submenus[] = new Menu($record->getFullName(), $record->getHtmlUrl()); $records[] = $record; } break; } } if ($show_user_favorites && isset($controller->record) && $controller->record instanceof GedcomRecord && !in_array($controller->record, $records)) { $submenus[] = new Menu(I18N::translate('Add to favorites'), '#', '', array('onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite", {xref:"' . $controller->record->getXref() . '"},function(){location.reload();})')); } if (empty($submenus)) { return null; } else { return new Menu(I18N::translate('Favorites'), '#', 'menu-favorites', array(), $submenus); } }
<?php break; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// case 'update': // Update a fact $xref = Filter::post('xref', WT_REGEX_XREF); $fact_id = Filter::post('fact_id'); $keep_chan = Filter::postBool('keep_chan'); if (!Filter::checkCsrf()) { $prev_action = Filter::post('prev_action', 'add|edit|addname|editname'); $fact_type = Filter::post('fact_type', WT_REGEX_TAG); header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME . '?action=' . $prev_action . '&xref=' . $xref . '&fact_id=' . $fact_id . '&fact=' . $fact_type); return; } $record = GedcomRecord::getInstance($xref, $WT_TREE); check_record_access($record); // Arrays for each GEDCOM line $glevels = Filter::postArray('glevels', '[0-9]'); $tag = Filter::postArray('tag', WT_REGEX_TAG); $text = Filter::postArray('text'); $islink = Filter::postArray('islink', '[01]'); $controller->setPageTitle(I18N::translate('Edit'))->pageHeader(); // If the fact has a DATE or PLAC, then delete any value of Y if ($text[0] === 'Y') { for ($n = 1; $n < count($tag); ++$n) { if ($glevels[$n] == 2 && ($tag[$n] === 'DATE' || $tag[$n] === 'PLAC') && $text[$n]) { $text[0] = ''; break; } }
$formats = array('' => I18N::translate('none'), 'markdown' => I18N::translate('markdown')); $source_types = array(0 => I18N::translate('none'), 1 => I18N::translate('facts'), 2 => I18N::translate('records')); $no_yes = array(0 => I18N::translate('no'), 1 => I18N::translate('yes')); $PRIVACY_CONSTANTS = array('none' => I18N::translate('Show to visitors'), 'privacy' => I18N::translate('Show to members'), 'confidential' => I18N::translate('Show to managers'), 'hidden' => I18N::translate('Hide from everyone')); $privacy = array(Auth::PRIV_PRIVATE => I18N::translate('Show to visitors'), Auth::PRIV_USER => I18N::translate('Show to members'), Auth::PRIV_NONE => I18N::translate('Show to managers'), Auth::PRIV_HIDE => I18N::translate('Hide from everyone')); $tags = array_unique(array_merge(explode(',', $WT_TREE->getPreference('INDI_FACTS_ADD')), explode(',', $WT_TREE->getPreference('INDI_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('FAM_FACTS_ADD')), explode(',', $WT_TREE->getPreference('FAM_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('NOTE_FACTS_ADD')), explode(',', $WT_TREE->getPreference('NOTE_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('SOUR_FACTS_ADD')), explode(',', $WT_TREE->getPreference('SOUR_FACTS_UNIQUE')), explode(',', $WT_TREE->getPreference('REPO_FACTS_ADD')), explode(',', $WT_TREE->getPreference('REPO_FACTS_UNIQUE')), array('SOUR', 'REPO', 'OBJE', '_PRIM', 'NOTE', 'SUBM', 'SUBN', '_UID', 'CHAN'))); $all_tags = array(); foreach ($tags as $tag) { if ($tag) { $all_tags[$tag] = GedcomTag::getLabel($tag); } } uasort($all_tags, '\\Fisharebest\\Webtrees\\I18N::strcasecmp'); $resns = Database::prepare("SELECT default_resn_id, tag_type, xref, resn" . " FROM `##default_resn`" . " LEFT JOIN `##name` ON (gedcom_id=n_file AND xref=n_id AND n_num=0)" . " WHERE gedcom_id=?" . " ORDER BY xref IS NULL, n_sort, xref, tag_type")->execute(array($WT_TREE->getTreeId()))->fetchAll(); foreach ($resns as $resn) { $resn->record = GedcomRecord::getInstance($resn->xref, $WT_TREE); if ($resn->tag_type) { $resn->tag_label = GedcomTag::getLabel($resn->tag_type); } else { $resn->tag_label = ''; } } usort($resns, function (\stdClass $x, \stdClass $y) { return I18N::strcasecmp($x->tag_label, $y->tag_label); }); // We have two fields in one $CALENDAR_FORMATS = explode('_and_', $WT_TREE->getPreference('CALENDAR_FORMAT') . '_and_'); // Split into separate fields $relatives_events = explode(',', $WT_TREE->getPreference('SHOW_RELATIVES_EVENTS')); switch (Filter::post('action')) { case 'privacy':
/** * Startup activity */ public function __construct() { global $WT_TREE; parent::__construct(); // $action comes from GET (search) or POST (replace) if (Filter::post('action')) { $this->action = Filter::post('action', 'replace', 'general'); $this->query = Filter::post('query'); $this->replace = Filter::post('replace'); $this->replaceNames = Filter::post('replaceNames', 'checked', ''); $this->replacePlaces = Filter::post('replacePlaces', 'checked', ''); $this->replacePlacesWord = Filter::post('replacePlacesWord', 'checked', ''); $this->replaceAll = Filter::post('replaceAll', 'checked', ''); } else { $this->action = Filter::get('action', 'advanced|general|soundex|replace|header', 'general'); $this->query = Filter::get('query'); $this->replace = Filter::get('replace'); $this->replaceNames = Filter::get('replaceNames', 'checked', ''); $this->replacePlaces = Filter::get('replacePlaces', 'checked', ''); $this->replacePlacesWord = Filter::get('replacePlacesWord', 'checked', ''); $this->replaceAll = Filter::get('replaceAll', 'checked', ''); } // Only editors can use search/replace if ($this->action === 'replace' && !Auth::isEditor($WT_TREE)) { $this->action = 'general'; } $this->srindi = Filter::get('srindi', 'checked', ''); $this->srfams = Filter::get('srfams', 'checked', ''); $this->srsour = Filter::get('srsour', 'checked', ''); $this->srnote = Filter::get('srnote', 'checked', ''); $this->soundex = Filter::get('soundex', 'DaitchM|Russell', 'DaitchM'); $this->showasso = Filter::get('showasso'); $this->firstname = Filter::get('firstname'); $this->lastname = Filter::get('lastname'); $this->place = Filter::get('place'); $this->year = Filter::get('year'); // If no record types specified, search individuals if (!$this->srfams && !$this->srsour && !$this->srnote) { $this->srindi = 'checked'; } // If no replace types specifiied, replace full records if (!$this->replaceNames && !$this->replacePlaces && !$this->replacePlacesWord) { $this->replaceAll = 'checked'; } // Trees to search if (Site::getPreference('ALLOW_CHANGE_GEDCOM')) { foreach (Tree::getAll() as $search_tree) { if (Filter::get('tree_' . $search_tree->getTreeId())) { $this->search_trees[] = $search_tree; } } if (!$this->search_trees) { $this->search_trees[] = $WT_TREE; } } else { $this->search_trees[] = $WT_TREE; } // If we want to show associated persons, build the list switch ($this->action) { case 'header': // We can type in an XREF into the header search, and jump straight to it. // Otherwise, the header search is the same as the general search if (preg_match('/' . WT_REGEX_XREF . '/', $this->query)) { $record = GedcomRecord::getInstance($this->query, $WT_TREE); if ($record && $record->canShowName()) { header('Location: ' . WT_BASE_URL . $record->getRawUrl()); exit; } } $this->action = 'general'; $this->srindi = 'checked'; $this->srfams = 'checked'; $this->srsour = 'checked'; $this->srnote = 'checked'; $this->setPageTitle(I18N::translate('General search')); $this->generalSearch(); break; case 'general': $this->setPageTitle(I18N::translate('General search')); $this->generalSearch(); break; case 'soundex': // Create a dummy search query to use as a title to the results list $this->query = trim($this->firstname . ' ' . $this->lastname . ' ' . $this->place); $this->setPageTitle(I18N::translate('Phonetic search')); $this->soundexSearch(); break; case 'replace': $this->setPageTitle(I18N::translate('Search and replace')); $this->search_trees = array($WT_TREE); $this->srindi = 'checked'; $this->srfams = 'checked'; $this->srsour = 'checked'; $this->srnote = 'checked'; if (Filter::post('query')) { $this->searchAndReplace($WT_TREE); header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME . '?action=replace&query=' . Filter::escapeUrl($this->query) . '&replace=' . Filter::escapeUrl($this->replace) . '&replaceAll=' . $this->replaceAll . '&replaceNames=' . $this->replaceNames . '&replacePlaces=' . $this->replacePlaces . '&replacePlacesWord=' . $this->replacePlacesWord); exit; } } }
/** * Find records that have changed since a given julian day * * @param Tree $tree Changes for which tree * @param int $jd Julian day * * @return GedcomRecord[] List of records with changes */ private function getRecentChanges(Tree $tree, $jd) { $sql = "SELECT d_gid FROM `##dates`" . " WHERE d_fact='CHAN' AND d_julianday1 >= :jd AND d_file = :tree_id"; $vars = array('jd' => $jd, 'tree_id' => $tree->getTreeId()); $xrefs = Database::prepare($sql)->execute($vars)->fetchOneColumn(); $records = array(); foreach ($xrefs as $xref) { $record = GedcomRecord::getInstance($xref, $tree); if ($record->canShow()) { $records[] = $record; } } return $records; }