/** * constructor */ function wfSpecialPlaceMap() { global $wgOut, $wgRequest, $wgUser; $wgOut->setArticleRelated(false); $wgOut->setRobotpolicy('noindex,nofollow'); $titleText = $wgRequest->getVal('pagetitle'); $error = ''; if ($titleText) { $title = Title::newFromText($titleText, NS_PLACE); if (is_null($title) || $title->getNamespace() != NS_PLACE || !$title->exists()) { $error = 'Please enter the title of a place page'; } else { $revision = StructuredData::getRevision($title, true); if (!$revision) { $error = "Place map revision not found!\n"; } else { $sk = $wgUser->getSkin(); $text =& $revision->getText(); $xml = StructuredData::getXml('place', $text); $wgOut->setPageTitle('Map of ' . $revision->getTitle()->getText()); // place map $wgOut->addHTML('<H2>Map for ' . $sk->makeKnownLinkObj($revision->getTitle(), $revision->getTitle()->getText()) . '</H2>'); $wgOut->addHTML('<div id="placemap" style="width: 760px; height: 520px"></div><br>'); $mapData = SpecialPlaceMap::getContainedPlaceMapData($xml); if (!$mapData) { $mapData = SpecialPlaceMap::getSelfMapData($revision->getTitle(), $xml); } $wgOut->addHTML(SpecialPlaceMap::getMapScripts(1, $mapData)); $wgOut->addHTML('<div id="latlnginst" style="display: block">Click on the map to see the latitude and longitude at the cursor position.</div>'); $wgOut->addHTML('<div id="latlngbox" style="display: none">Clicked on Latitude: <span id="latbox"></span> Longitude: <span id="lngbox"></span></div><br>'); $unmappedPlaces = SpecialPlaceMap::getUnmappedPlaces($sk, $xml); if ($unmappedPlaces) { $wgOut->addHTML("<h3>Places not on map</h3>" . $unmappedPlaces); } return; } } } $wgOut->setPageTitle('Place Map'); if ($error) { $wgOut->addHTML("<p><font color=red>{$error}</font></p>"); } $queryBoxStyle = 'width:100%;text-align:center;'; $form = <<<END <form name="search" action="/wiki/Special:PlaceMap" method="get"> <div id="searchFormDiv" style="{$queryBoxStyle}"> Place title: <input type="text" name="pagetitle" size=24 maxlength="100" value="{$titleText}" onfocus="select()" /> <input type="submit" value="Go" /> </div> </form> END; $wgOut->addHTML($form); }
private function loadPedigree() { // read the person if ($this->title->getNamespace() == NS_PERSON) { $revision = Revision::loadFromTitle($this->dbr, $this->title); // use load instead of new because I don't want ShowPedigree to ever access DB_MASTER if ($revision) { $xml = StructuredData::getXml('person', $revision->getText()); if ($xml) { foreach ($xml->spouse_of_family as $spouseFamily) { $pos = ShowPedigree::SPOUSE_FAMILY_BASE + $this->numSpouseFamilies; $this->loadFamily((string) $spouseFamily['title'], $pos, 0); if (@$this->families[$pos]['exists']) { $this->numSpouseFamilies += 1; } else { $this->families[$pos] = null; } } $this->loadFamily((string) $xml->child_of_family['title'], 1, ShowPedigree::MAX_FAMILIES); if ($this->numSpouseFamilies == 0) { // no spouse families exist; get information on self from the person page (put into ['husband'] - it shouldn't matter) $this->loadSelf($this->families[ShowPedigree::SPOUSE_FAMILY_BASE]['husband'], $xml); } } } $selfTitle = @$this->families[ShowPedigree::SPOUSE_FAMILY_BASE]['husband']['title']; if ($selfTitle) { $this->selfTag = $selfTitle == $this->title->getText() ? 'husband' : 'wife'; $this->spouseTag = $this->selfTag == 'husband' ? 'wife' : 'husband'; } } else { $this->loadFamily($this->title->getText(), 1, ShowPedigree::MAX_FAMILIES); $this->selfTag = ''; $this->spouseTag = ''; } }
/** * Propagate move, delete, or undelete to other articles if necessary * * @param String $newTitleString null in case of delete; same as this title string in case of undelete * @param String $text text of article * @param bool $textChanged set to true if we change the text * @return bool true if success */ protected function propagateMoveDeleteUndelete($newTitleString, $newNs, &$text, &$textChanged) { global $wgESINHandler; $result = true; $newTitle = $newTitleString ? Title::newFromText($newTitleString, NS_FAMILY) : null; // if we're undeleting, add additional people from WLH, getting updated person data if ($this->titleString == $newTitleString) { $wlh = simplexml_load_string($this->getPageTextFromWLH(false)); // get text for all people // TODO is propagateEditData called after Undelete? if so, then we could get updated person attributes there $personText = $this->getPersonData($wlh->husband, $this->xml->husband, 'husband') . $this->getPersonData($wlh->wife, $this->xml->wife, 'wife') . $this->getPersonData($wlh->child, $this->xml->child, 'child') . $wgESINHandler->getImageData($wlh->image, $this->xml->image); // update text: replace old family information with new $text = preg_replace("\$<(husband|wife|child|image) [^>]*>\n\$", '', $text); $text = preg_replace('$</family>$', StructuredData::protectRegexReplace($personText . '</family>'), $text, 1); $this->xml = StructuredData::getXml($this->tagName, $text); $textChanged = true; } // get data to propagate $propagatedData = Family::getPropagatedData($this->xml); foreach ($propagatedData['husbands'] as $p) { $personTitle = Title::newFromText((string) $p, NS_PERSON); PropagationManager::addPropagatedAction($this->title, 'delspouse', $personTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addspouse', $personTitle); } // don't need to check propagated action before calling updatePerson, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updatePerson($personTitle, 'husband', 'spouse_of_family', $newTitleString, $text, $textChanged); } foreach ($propagatedData['wives'] as $p) { $personTitle = Title::newFromText((string) $p, NS_PERSON); PropagationManager::addPropagatedAction($this->title, 'delspouse', $personTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addspouse', $personTitle); } // don't need to check propagated action before calling updatePerson, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updatePerson($personTitle, 'wife', 'spouse_of_family', $newTitleString, $text, $textChanged); } foreach ($propagatedData['children'] as $p) { $personTitle = Title::newFromText((string) $p, NS_PERSON); PropagationManager::addPropagatedAction($this->title, 'delchild', $personTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addchild', $personTitle); } // don't need to check propagated action before calling updatePerson, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updatePerson($personTitle, 'child', 'child_of_family', $newTitleString, $text, $textChanged); } if (StructuredData::removeDuplicateLinks('husband|wife|child', $text)) { $textChanged = true; } $result = $result && $wgESINHandler->propagateSINMoveDeleteUndelete($this->title, 'family', $this->titleString, $newTitleString, $propagatedData, $text, $textChanged); if (!$result) { error_log("ERROR! Family move/delete/undelete not propagated: {$this->titleString} -> " . ($newTitleString ? $newTitleString : "[delete]") . "\n"); } return $result; }
/** * Create edit fields from xml property */ protected function toEditFields(&$textbox1) { global $wgOut, $wgScriptPath, $wgRequest; $result = ''; $target = $wgRequest->getVal('target'); // add javascript functions $wgOut->addScript("<script type=\"text/javascript\" src=\"{$wgScriptPath}/autocomplete.10.js\"></script>"); $invalidStyle = ' style="background-color:#fdd;"'; // $altNames = ''; $surnames = ''; $places = ''; $fromYearStyle = ''; $toYearStyle = ''; $urlStyle = ''; $fromYear = ''; $toYear = ''; $url = ''; $abbrev = ''; $author = ''; $pubInfo = ''; $callNumber = ''; $type = ''; $repoName = ''; $repoAddr = ''; $exists = isset($this->xml); if (!$exists) { global $wgRequest; // construct <source> text from request $text = MySource::getPageText($wgRequest->getVal('a'), $wgRequest->getVal('p'), $wgRequest->getVal('s')); $this->xml = StructuredData::getXml('mysource', $text); } if (isset($this->xml)) { $fromYear = htmlspecialchars((string) $this->xml->from_year); $toYear = htmlspecialchars((string) $this->xml->to_year); $url = htmlspecialchars((string) $this->xml->url); $abbrev = htmlspecialchars((string) $this->xml->abbrev); $author = htmlspecialchars((string) $this->xml->author); $pubInfo = htmlspecialchars((string) $this->xml->publication_info); $callNumber = htmlspecialchars((string) $this->xml->call_number); $type = htmlspecialchars((string) $this->xml->type); $repoName = htmlspecialchars((string) $this->xml->repository_name); $repoAddr = htmlspecialchars((string) $this->xml->repository_addr); // foreach ($this->xml->alternate_name as $altName) { // $altNames .= $altName . "\n"; // } foreach ($this->xml->surname as $surname) { $surnames .= htmlspecialchars($surname) . "\n"; } foreach ($this->xml->place as $place) { $places .= htmlspecialchars($place) . "\n"; } } if (!StructuredData::isValidYear($fromYear) || !StructuredData::isValidYear($toYear)) { if (!StructuredData::isValidYear($fromYear)) { $fromYearStyle = $invalidStyle; } if (!StructuredData::isValidYear($toYear)) { $toYearStyle = $invalidStyle; } $result .= "<p><font color=red>The year range is not valid</font></p>"; } if (!StructuredData::isValidUrl($url)) { $urlStyle = $invalidStyle; $result .= "<p><font color=red>The URL is not valid</font></p>"; } if ($this->isGedcomPage) { list($mysourcePrefix, $mysourceTitle, $mysourceSuffix) = MySource::splitGedcomMySourceTitle($this->titleString); $result .= '<br><label for="title">MySource title</label><input tabindex="1" size="80" name="mysource_title" value="' . htmlspecialchars($mysourceTitle) . '"/>'; } $result .= "<br>"; // $result .= "<label for=\"altNames\">Alternate names (one per line):</label><br><textarea tabindex=\"1\" name=\"altNames\" rows=\"3\" cols=\"40\">".htmlspecialchars($altNames)."</textarea>"; $result .= "<br><label for=\"surnames\">Surnames covered(one per line):</label><br><textarea tabindex=\"1\" name=\"surnames\" rows=\"3\" cols=\"60\">{$surnames}</textarea>" . "<br><label for=\"places\">Places covered (one per line):</label><br><textarea class=\"place_input\" tabindex=\"1\" name=\"places\" rows=\"3\" cols=\"60\">{$places}</textarea>" . "<table>" . "<tr><td align=right>Year range:</td><td align=left><input tabindex=\"1\" name=\"fromYear\" value=\"{$fromYear}\" size=\"5\"{$fromYearStyle}/>" . " - <input tabindex=\"1\" name=\"toYear\" value=\"{$toYear}\" size=\"5\"" . htmlspecialchars($toYearStyle) . "/></td></tr>"; $result .= "<tr><td align=right>URL:</td><td align=left><input tabindex=\"1\" name=\"url\" value=\"{$url}\" size=\"60\"{$urlStyle}/></td></tr>" . "<tr><td align=right>Author:</td><td align=left><input tabindex=\"1\" name=\"author\" value=\"{$author}\" size=\"20\"/></td></tr>" . "<tr><td align=right>Publication info:</td><td align=left><input tabindex=\"1\" name=\"pubInfo\" value=\"{$pubInfo}\" size=\"60\"/></td></tr>" . "<tr><td align=right>Call number:</td><td align=left><input tabindex=\"1\" name=\"callNumber\" value=\"{$callNumber}\" size=\"20\"/></td></tr>" . "<tr><td align=right>Type:</td><td align=left><input tabindex=\"1\" name=\"type\" value=\"{$type}\" size=\"20\"/></td></tr>" . "<tr><td align=right>Repository name:</td><td align=left><input tabindex=\"1\" name=\"repoName\" value=\"{$repoName}\" size=\"60\"/></td></tr>" . "<tr><td align=right>Repository addr:</td><td align=left><input tabindex=\"1\" name=\"repoAddr\" value=\"{$repoAddr}\" size=\"60\"/></td></tr>" . "<tr><td align=right>Abbreviation:</td><td align=left><input tabindex=\"1\" name=\"abbrev\" value=\"{$abbrev}\" size=\"10\"/></td></tr>" . "</table>Text:<br>"; return $result; }
/** * Propagate an article rollback * Sets xml property and calls the abstract function propagateRollbackData($title) * @param Article $article contains text being replaced * @return bool true if propagate succeeded */ public function propagateRollback($article) { global $wgUser, $wrBotUserID; $result = true; // we do propagate bot edits // if ($wgUser->getID() != $wrBotUserID) { $title = $article->getTitle(); $oldText =& $article->fetchContent(); // $article contains the text being replaced; $rollbackRevision contains the new text $rollbackRevision = StructuredData::getRevision($title, false, true); $text =& $rollbackRevision->getText(); $this->xml = StructuredData::getXml($this->tagName, $text); $textChanged = false; $result = $this->propagateEditData($oldText, $text, $textChanged); if ($result && $textChanged) { PropagationManager::enablePropagation(false); $result = $article->doEdit($text, self::PROPAGATE_MESSAGE, PROPAGATE_EDIT_FLAGS); PropagationManager::enablePropagation(true); } // } return $result; }
/** * Propagate move, delete, or undelete to other articles if necessary * * @param String $newTitleString null in case of delete; same as this title string in case of undelete * @param String $text text of article * @param bool $textChanged set to true if we change the text * @return bool true if success */ protected function propagateMoveDeleteUndelete($newTitleString, $newNs, &$text, &$textChanged) { global $wgESINHandler; $result = true; $newTitle = $newTitleString ? Title::newFromText($newTitleString, NS_PERSON) : null; // if we're undeleting, add additional families from WLH if ($this->titleString == $newTitleString) { $wlh = simplexml_load_string($this->getPageTextFromWLH(false)); // get text for all families $familyText = $this->getFamilyData($wlh->child_of_family, $this->xml->child_of_family, 'child_of_family') . $this->getFamilyData($wlh->spouse_of_family, $this->xml->spouse_of_family, 'spouse_of_family') . $wgESINHandler->getImageData($wlh->image, $this->xml->image); // update text: replace old family information with new $text = preg_replace("\$<((child|spouse)_of_family|image) [^>]*>\n\$", '', $text); $text = preg_replace('$</person>$', StructuredData::protectRegexReplace($familyText . '</person>'), $text, 1); $this->xml = StructuredData::getXml($this->tagName, $text); $textChanged = true; } // get data to propagate $propagatedData = Person::getPropagatedData($this->xml); foreach ($propagatedData['parentFamilies'] as $f) { $familyTitle = Title::newFromText((string) $f, NS_FAMILY); PropagationManager::addPropagatedAction($this->title, 'delchild_of_family', $familyTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addchild_of_family', $familyTitle); } // don't need to check propagated action before calling updateFamily, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updateFamily($familyTitle, 'child_of_family', 'child', $newTitleString, $propagatedData, $text, $textChanged); } $spouseTag = $propagatedData['gender'] == 'F' ? 'wife' : 'husband'; foreach ($propagatedData['spouseFamilies'] as $f) { $familyTitle = Title::newFromText((string) $f, NS_FAMILY); PropagationManager::addPropagatedAction($this->title, 'delspouse_of_family', $familyTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addspouse_of_family', $familyTitle); } // don't need to check propagated action before calling updateFamily, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updateFamily($familyTitle, 'spouse_of_family', $spouseTag, $newTitleString, $propagatedData, $text, $textChanged); } if (StructuredData::removeDuplicateLinks('child_of_family|spouse_of_family', $text)) { $textChanged = true; } $result = $result && $wgESINHandler->propagateSINMoveDeleteUndelete($this->title, 'person', $this->titleString, $newTitleString, $propagatedData, $text, $textChanged); if (!$result) { error_log("ERROR! Person move/delete/undelete not propagated: {$this->titleString} -> " . ($newTitleString ? $newTitleString : "[delete]") . "\n"); } return $result; }
private function loadPerson($titleText) { $xml = null; $title = Title::newFromText($titleText, NS_PERSON); $revision = Revision::loadFromTitle($this->dbr, $title); // use load instead of new because I don't want to ever access DB_MASTER if ($revision) { $xml = StructuredData::getXml('person', $revision->getText()); } return $xml; }
/** * Generate family tree page * * @param unknown_type $args user, name, ns, title * @return GE_SUCCESS, GE_INVALID_ARG, GE_NOT_LOGGED_IN, GE_NOT_AUTHORIZED, GE_NOT_FOUND, GE_DUP_KEY, GE_DB_ERROR */ function wfGenerateFamilyTreePage($args) { global $wgUser, $wgAjaxCachePolicy, $wrBotUserID, $wrIsGedcomUpload; // set cache policy $wgAjaxCachePolicy->setPolicy(0); $status = GE_SUCCESS; $ns = ''; $text = ''; $oldText = ''; $titleString = ''; $editFlags = 0; $wrIsGedcomUpload = true; if (!$wgUser->isLoggedIn()) { $status = GE_NOT_LOGGED_IN; } else { if (wfReadOnly() || $wgUser->getID() != $wrBotUserID) { $status = GE_NOT_AUTHORIZED; } else { $xml = simplexml_load_string($args); $ns = (int) $xml['namespace']; $titleString = (string) $xml['title']; PropagationManager::setWhitelist(); // only pages to propagate to are on the whitelist $existingTitles = (string) $xml['existing_titles']; if ($existingTitles) { $existingTitles = explode('|', $existingTitles); foreach ($existingTitles as $existingTitle) { PropagationManager::addWhitelistPage(Title::newFromText($existingTitle)); } } $treeId = (int) $xml['tree_id']; $uid = (string) $xml['uid']; // wfDebug("wfGenerateFamilyTreePage ns=$ns title=$titleString treeId=$treeId\n"); if (!$titleString || !$treeId) { //wfDebug("wfGenerate parmerr $treeId:$titleString\n"); $status = GE_INVALID_ARG; } } } if ($status == GE_SUCCESS) { $dbr =& wfGetDB(DB_SLAVE); $dbr->ignoreErrors(true); $userName = $dbr->selectField('familytree', 'ft_user', array('ft_tree_id' => $treeId)); $errno = $dbr->lastErrno(); if ($errno > 0) { $status = GE_DB_ERROR; } else { if ($userName === false) { $status = GE_NOT_FOUND; } else { $wgUser = User::newFromName($userName, false); // switch the global user if (!$wgUser) { $status = GE_NOT_FOUND; } } } } if ($status == GE_SUCCESS) { $title = Title::newFromText($titleString, $ns); $text = $xml->content; if ($title == null || !$treeId) { //wfDebug("wfGenerate error $treeId $ns $titleString\n"); $status = GE_INVALID_ARG; } else { $article = new Article($title, 0); if (!$article->exists()) { $editFlags = EDIT_NEW; } else { $oldText = $article->getContent(); $editFlags = EDIT_UPDATE; } // else if ($ns == NS_MYSOURCE) { // $existingMysource = true; // $revid = $title->getLatestRevID(GAID_FOR_UPDATE); // } // // TODO during re-upload, we need to notify users of changes if others are watching; should we not suppress RC in this case? // // also, decide whether FamilyTreePropagator should update ftp or not // // (FamilyTreePropagator also processes the tree checkboxes, so we probably don't want it called) // else { //// $editFlags = EDIT_UPDATE; // $status = GE_DUP_KEY; // } } } if ($status == GE_SUCCESS && ($editFlags == EDIT_NEW || $text != $oldText)) { $isUpdatable = true; if ($editFlags == EDIT_UPDATE) { $revision = Revision::newFromId($article->getLatest()); if ($revision && $revision->getComment() != 'gedcom upload') { $isUpdatable = false; error_log("Cannot update existing user-edited page: " . $article->getTitle()->getPrefixedText()); } } if ($isUpdatable) { // NOTE: This doesn't execute the code in FamilyTreePropagator to update familytree_page, so if you edit a page, you'll have to update // the familytree_page.fp_latest yourself. Also, FamilyTreePropagator adds the page to the tree (based upon request checkboxes), but we do this below if (!$article->doEdit($text, 'gedcom upload', $editFlags | EDIT_SUPPRESS_RC)) { $status = GE_WIKI_ERROR; } // TODO remove this if ($ns == NS_PERSON) { $xml = StructuredData::getXml('person', $text); $summaryFields = explode('|', Person::getSummary($xml, $title)); $birthDate = $summaryFields[3]; $deathDate = $summaryFields[5]; $birthYear = ''; $deathYear = ''; if (preg_match('/\\d\\d\\d\\d/', $birthDate, $matches)) { $birthYear = $matches[0]; } if (preg_match('/\\d\\d\\d\\d/', $deathDate, $matches)) { $deathYear = $matches[0]; } if (($birthYear && $birthYear < 1750 || $deathYear && $deathYear < 1750) && !in_array($wgUser->getName(), explode('|', wfMsg('trustedgedcomuploaders')))) { error_log($title->getPrefixedText() . "\n", 3, '/opt/wr/logs/earlypeople.txt'); } } } } if ($status == GE_SUCCESS) { $dbw =& wfGetDB(DB_MASTER); $dbw->ignoreErrors(true); $dbw->begin(); // if ($status == GE_SUCCESS) { // // save the data // $data = $xml->data->asXML(); // if ($data) { // $dataVersion = 1; // $status == fgSaveData($dbw, $treeId, $title, $data, true); // } // else { // $dataVersion = 0; // } // } // add the page to the tree if ($status == GE_SUCCESS) { if (!FamilyTreeUtil::addPage($dbw, $wgUser, $treeId, $title, 0, 0, 0, $uid, 0)) { $status = GE_DB_ERROR; } } // watch the page if ($status == GE_SUCCESS) { StructuredData::addWatch($wgUser, $article, true); } if ($status == GE_SUCCESS) { $dbw->commit(); } else { $dbw->rollback(); } } // return status $titleString = StructuredData::escapeXml($titleString); return "<generate status=\"{$status}\" ns=\"{$ns}\" title=\"{$titleString}\"></generate>"; }
private function submitPage() { global $wgRequest, $wgOut; if (!$wgRequest->wasPosted() || !$wgRequest->getVal('wpEdittime')) { $this->showPage(); return; } // from form $textbox1 = $wgRequest->getText('wpTextbox1'); $ns = $wgRequest->getVal('gedcomns'); $titleString = $wgRequest->getVal('gedcomtitle'); $editPage = (object) array('textbox1' => $textbox1, 'section' => ''); $obj = $this->getPageObj($ns, $titleString); $obj->importEditData($editPage, $wgRequest); if ($obj->getTitle()) { $titleString = $obj->getTitle()->getPrefixedText(); // get updated title in case it was updated } $text = $editPage->textbox1; // grab xml and content from edited data $tagName = $obj->getTagName(); $xml = StructuredData::getXml($tagName, $text); $content = trim(mb_substr($text, mb_strpos($text, '</' . $tagName . '>') + strlen("</{$tagName}>\n"))); // add id's back and remove titles $saveTitles = array(); foreach ($xml->child_of_family as $r) { $r['id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['id']) { $saveTitles[(string) $r['id']] = (string) $r['title']; unset($r['title']); } } foreach ($xml->spouse_of_family as $r) { $r['id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['id']) { $saveTitles[(string) $r['id']] = (string) $r['title']; unset($r['title']); } } foreach ($xml->husband as $r) { $r['id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['id']) { $saveTitles[(string) $r['id']] = (string) $r['title']; unset($r['title']); } } foreach ($xml->wife as $r) { $r['id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['id']) { $saveTitles[(string) $r['id']] = (string) $r['title']; unset($r['title']); } } foreach ($xml->child as $r) { $r['id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['id']) { $saveTitles[(string) $r['id']] = (string) $r['title']; unset($r['title']); } } foreach ($xml->source_citation as $r) { $r['source_id'] = GedcomUtil::getKeyFromTitle((string) $r['title']); if ((string) $r['source_id']) { $saveTitles[(string) $r['source_id']] = (string) $r['title']; unset($r['title']); } } // save data to db $text = $xml->asXML(); $text = substr($text, strpos($text, '<', 1)) . $content; // skip past the <?xml version="1.0"? > header and add content $dbw =& wfGetDB(DB_MASTER); $dbw->begin(); $qtext = $dbw->addQuotes($text); $sql = 'INSERT INTO familytree_gedcom_data (fgd_gedcom_id, fgd_gedcom_key, fgd_text)' . ' VALUES(' . $dbw->addQuotes($this->gedcomid) . ',' . $dbw->addQuotes($this->gedcomkey) . ',' . $qtext . ')' . ' ON DUPLICATE KEY UPDATE fgd_text=' . $qtext; $dbw->query($sql); $dbw->commit(); // convert to in-memory format and save to memory // add titles back foreach ($xml->child_of_family as $r) { if ((string) $r['id']) { $r['title'] = $saveTitles[(string) $r['id']]; } } foreach ($xml->spouse_of_family as $r) { if ((string) $r['id']) { $r['title'] = $saveTitles[(string) $r['id']]; } } foreach ($xml->husband as $r) { if ((string) $r['id']) { $r['title'] = $saveTitles[(string) $r['id']]; } } foreach ($xml->wife as $r) { if ((string) $r['id']) { $r['title'] = $saveTitles[(string) $r['id']]; } } foreach ($xml->child as $r) { if ((string) $r['id']) { $r['title'] = $saveTitles[(string) $r['id']]; } } foreach ($xml->source_citation as $r) { if ((string) $r['source_id']) { $r['title'] = $saveTitles[(string) $r['source_id']]; } } $xml->content = $content; $xml['id'] = $this->gedcomkey; $xml['ns'] = $ns; $xml['title'] = $titleString; $text = $xml->asXML(); $text = substr($text, strpos($text, '<', 1)); // skip past the <?xml version="1.0"? > header GedcomUtil::putGedcomDataString($text); // add script to notify swf of update $gedcomkey = htmlspecialchars($this->gedcomkey); $wgOut->addScript(<<<END <script type="text/javascript"> //<![CDATA[ \$(document).ready(function(){ \ttry { \t if (parent && parent.review) { \t var swf=(navigator.appName.indexOf("Microsoft")!=-1) ? parent.review.window["gedcom"] : parent.review.document["gedcom"]; \t if (swf && swf.pageUpdated) swf.pageUpdated("{$gedcomkey}"); \t } \t} catch (e) {} }); //]]> </script> END ); // show page $this->showPage(); }
/** * Propagate data in xml property to other articles if necessary * @param string $oldText contains text being replaced * @param String $text which we never touch when propagating places * @param bool $textChanged which we never touch when propagating places * @return bool true if propagation was successful */ protected function propagateEditData($oldText, &$text, &$textChanged) { $result = true; // determine current parents and type and lat and lng list($alsoLocatedIn, $type, $lat, $lng, $fromYear, $toYear) = Place::getPropagatedData($this->xml); // determine original parents by retrieving current version list($origAlsoLocatedIn, $origType, $origLat, $origLng, $origFromYear, $origToYear) = array(array(), null, null, null, null, null); if ($oldText) { $origXml = StructuredData::getXml('place', $oldText); if (isset($origXml)) { list($origAlsoLocatedIn, $origType, $origLat, $origLng, $origFromYear, $origToYear) = Place::getPropagatedData($origXml); // maintain place_abbrevs if (!isset($this->xml) || Place::placeAbbrevsChanged($origXml, $this->xml)) { Place::placeAbbrevsDelete($this->titleString); if (isset($this->xml)) { Place::placeAbbrevsAdd($this->titleString, $this->xml); } } } else { // new place comes here or below // add to place_abbrevs Place::placeAbbrevsDelete($this->titleString); Place::placeAbbrevsAdd($this->titleString, $this->xml); } } else { // add to place_abbrevs Place::placeAbbrevsDelete($this->titleString); Place::placeAbbrevsAdd($this->titleString, $this->xml); } // $delAlsoLocatedIn = StructuredData::mapDiff($origAlsoLocatedIn, $alsoLocatedIn, 'place'); // don't remove from X if this place is locatedIn X // if ($this->locatedIn) { // $key = StructuredData::mapSearch($this->locatedIn, $delAlsoLocatedIn, 'place'); // if ($key!==false) { // array_splice($delAlsoLocatedIn, $key, 1); // } // } // if ($type != $origType || $lat != $origLat || $lng != $origLng) { // $updAlsoLocatedIn = $alsoLocatedIn; // } // else { // $updAlsoLocatedIn = array_diff($alsoLocatedIn, $origAlsoLocatedIn); // } // remove from original parent if necessary (don't remove from X if this place is now prevLocatedIn X) // if ($origLocatedIn && $origLocatedIn != $locatedIn && array_search($origLocatedIn, $alsoLocatedIn)===false) { // $parentArticle = StructuredData::getArticle(Title::newFromText((string)$origLocatedIn, NS_PLACE), true); // if ($parentArticle) { // $content =& $parentArticle->fetchContent(); // $updatedContent =& $this->updateContainedPlace(null, null, null, null, $content); // if ($updatedContent) { // $updateResult = $parentArticle->doEdit($updatedContent, self::PROPAGATE_MESSAGE, PROPAGATE_EDIT_FLAGS); // $result = $result && $updateResult; // } // } // } $isRedirect = StructuredData::isRedirect($text); if ($isRedirect) { // add alt name to redirect target list($prefName, $locatedIn) = Place::getPrefNameLocatedIn($this->titleString); $prefName = StructuredData::mb_str_replace($prefName, '_', ' '); // convert _'s back to spaces $newTitle = Title::newFromRedirect($text); $targetArticle = StructuredData::getArticle($newTitle, true); $targetContent =& $targetArticle->fetchContent(); $targetXml = StructuredData::getXml('place', $targetContent); $found = false; foreach ($targetXml->alternate_name as $an) { $altName = (string) $an['name']; if ($altName == $prefName) { $found = true; break; } } if (!$found) { $altName = '<alternate_name name="' . StructuredData::escapeXml($prefName) . '" source="from redirect"/>'; $targetContent = StructuredData::mb_str_replace($targetContent, "<place>", "<place>\n" . $altName); $targetArticle->doEdit($targetContent, 'Add alternate name from redirect', PROPAGATE_EDIT_FLAGS); } // edit wlh pages to point to the target title $job = new PlaceRedirectJob(array('old_title' => $this->titleString, 'new_title' => $newTitle->getText())); $job->insert(); } // update type, lat, or lng if changed, or this place has been redirected or this place is new if ($this->locatedIn && ($isRedirect || !isset($origXml) || $type != $origType || $lat != $origLat || $lng != $origLng || $fromYear != $origFromYear || $toYear != $origToYear)) { $parentArticle = StructuredData::getArticle(Title::newFromText($this->locatedIn, NS_PLACE), true); if ($parentArticle) { $content =& $parentArticle->fetchContent(); if ($isRedirect) { // remove from parent $updatedContent =& $this->updateContainedPlace(null, null, null, null, null, null, $content); } else { $updatedContent =& $this->updateContainedPlace($this->titleString, $type, $lat, $lng, $fromYear, $toYear, $content); } if ($updatedContent) { $updateResult = $parentArticle->doEdit($updatedContent, self::PROPAGATE_MESSAGE . ' [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); $result = $result && $updateResult; } } } // remove from deleted previous parents foreach ($origAlsoLocatedIn as $pli) { if ($this->locatedIn != (string) $pli['place'] && StructuredData::mapArraySearch((string) $pli['place'], $alsoLocatedIn, 'place') === false) { $parentArticle = StructuredData::getArticle(Title::newFromText((string) $pli['place'], NS_PLACE), true); if ($parentArticle) { $content =& $parentArticle->fetchContent(); $updatedContent =& $this->updateContainedPlace(null, null, null, null, null, null, $content); if ($updatedContent) { $updateResult = $parentArticle->doEdit($updatedContent, self::PROPAGATE_MESSAGE . ' [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); $result = $result && $updateResult; } } } } // add to new previous parents or update type, lat, lng on same previous-parents foreach ($alsoLocatedIn as $pli) { $origKey = StructuredData::mapArraySearch((string) $pli['place'], $origAlsoLocatedIn, 'place'); if ($origKey !== false) { $origPli = $origAlsoLocatedIn[$origKey]; } if ($this->locatedIn != (string) $pli['place'] && ($origKey === false || $type != $origType || $lat != $origLat || $lng != $origLng || (string) $pli['from_year'] != (string) $origPli['from_year'] || (string) $pli['to_year'] != (string) $origPli['to_year'])) { $parentArticle = StructuredData::getArticle(Title::newFromText((string) $pli['place'], NS_PLACE), true); if ($parentArticle) { $content =& $parentArticle->fetchContent(); $updatedContent =& $this->updateContainedPlace($this->titleString, $type, $lat, $lng, (string) $pli['from_year'], (string) $pli['to_year'], $content); if ($updatedContent) { $updateResult = $parentArticle->doEdit($updatedContent, self::PROPAGATE_MESSAGE . ' [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); $result = $result && $updateResult; } } } } if (!$result) { error_log("ERROR! Place edit/rollback not propagated: {$this->titleString}\n"); } return $result; }
/** * Propagate move, delete, or undelete to other articles if necessary * * @param String $newTitleString null in case of delete; same as this title string in case of undelete * @param String $text text of article * @param bool $textChanged set to true if we change the text * @return bool true if success */ protected function propagateMoveDeleteUndelete($newTitleString, $newNs, &$text, &$textChanged) { $result = true; $newTitle = $newTitleString ? Title::newFromText($newTitleString, NS_IMAGE) : null; // if we're undeleting, add additional people from WLH, getting updated person data if ($this->titleString == $newTitleString) { list($people, $families) = SDImage::getPropagatedData($this->xml); $this->addWhatLinksHere($people, $families); $pageText = $this->getPageElements($people, 'person', NS_PERSON) . $this->getPageElements($families, 'family', NS_FAMILY); // update text: replace old family information with new $text = preg_replace("\$<(person|family) [^>]*>\n\$", '', $text); $text = preg_replace('$</' . $this->tagName . '>$', StructuredData::protectRegexReplace($pageText . '</' . $this->tagName . '>'), $text, 1); $this->xml = StructuredData::getXml($this->tagName, $text); $textChanged = true; } // get data to propagate list($people, $families) = SDImage::getPropagatedData($this->xml); foreach ($people as $p) { $linkTitle = Title::newFromText((string) $p, NS_PERSON); PropagationManager::addPropagatedAction($this->title, 'dellink', $linkTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addlink', $linkTitle); } // don't need to check propagated action before calling updatePage, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updatePage($linkTitle, 'person', $newTitleString, $text, $textChanged); } foreach ($families as $p) { $linkTitle = Title::newFromText((string) $p, NS_FAMILY); PropagationManager::addPropagatedAction($this->title, 'dellink', $linkTitle); if ($newTitle) { PropagationManager::addPropagatedAction($newTitle, 'addlink', $linkTitle); } // don't need to check propagated action before calling updatePage, because propagateMoveDeleteUndelete is never part of a loop $result = $result && $this->updatePage($linkTitle, 'family', $newTitleString, $text, $textChanged); } if (!$result) { error_log("ERROR! Family move/delete/undelete not propagated: {$this->titleString} -> " . ($newTitleString ? $newTitleString : "[delete]") . "\n"); } return $result; }
/** * Create edit fields from xml property */ protected function toEditFields(&$textbox1) { global $wgOut, $wgScriptPath, $wgRequest; $result = ''; $target = $wgRequest->getVal('target'); // add javascript functions $wgOut->addScript("<script type=\"text/javascript\" src=\"{$wgScriptPath}/autocomplete.10.js\"></script>"); // if ($target && $target != 'AddPage') { // $result .= "<p><font color=red>Add any additional information you have about the source". // ($target == 'gedcom' ? ' and save the page' : ', save the page, then close this window'). // ".</font></p>"; // } $wgOut->addScript("<script type=\"text/javascript\" src=\"{$wgScriptPath}/jquery.multiSelect.yui.1.js\"></script>"); $wgOut->addScript("<script type=\"text/javascript\" src=\"{$wgScriptPath}/source.18.js\"></script>"); $tm = new TipManager(); $sourceType = ''; $authors = ''; $sourceTitle = ''; $subtitle = ''; $publisher = ''; $dateIssued = ''; $placeIssued = ''; $seriesName = ''; $pages = ''; $references = ''; $surnames = ''; $places = ''; $subjects = array(); $ethnicity = ''; $religion = ''; $occupation = ''; $fromYear = ''; $toYear = ''; $invalidStyle = ' style="background-color:#fdd;"'; $fromYearStyle = ''; $toYearStyle = ''; $exists = isset($this->xml); if (!$exists) { // construct <source> text from request $text = Source::getPageText($wgRequest->getVal('sty'), $wgRequest->getVal('st'), $wgRequest->getVal('a'), $wgRequest->getVal('p'), $wgRequest->getVal('pi'), $wgRequest->getVal('pu')); $this->xml = StructuredData::getXml('source', $text); } if (isset($this->xml)) { $sourceType = htmlspecialchars((string) $this->xml->source_type); foreach ($this->xml->author as $author) { $authors .= htmlspecialchars((string) $author) . "\n"; } $sourceTitle = htmlspecialchars((string) $this->xml->source_title); if (!$sourceTitle) { $sourceTitle = htmlspecialchars($this->titleString); } $subtitle = htmlspecialchars((string) $this->xml->subtitle); $publisher = htmlspecialchars((string) $this->xml->publisher); if (!$publisher) { $publisher = htmlspecialchars((string) $this->xml->publication_info); } $dateIssued = htmlspecialchars((string) $this->xml->date_issued); $placeIssued = htmlspecialchars((string) $this->xml->place_issued); $seriesName = htmlspecialchars((string) $this->xml->series_name); $volumes = htmlspecialchars((string) $this->xml->volumes); $pages = htmlspecialchars((string) $this->xml->pages); $references = htmlspecialchars((string) $this->xml->references); foreach ($this->xml->surname as $surname) { $surnames .= htmlspecialchars((string) $surname) . "\n"; } foreach ($this->xml->place as $place) { $places .= htmlspecialchars((string) $place) . "\n"; } foreach ($this->xml->subject as $subject) { $subjects[] = htmlspecialchars((string) $subject); } if (count($subjects) == 0 && (string) $this->xml->source_category) { $subjects[] = htmlspecialchars((string) $this->xml->source_category); } $ethnicity = htmlspecialchars((string) $this->xml->ethnicity); $religion = htmlspecialchars((string) $this->xml->religion); $occupation = htmlspecialchars((string) $this->xml->occupation); $fromYear = htmlspecialchars((string) $this->xml->from_year); $toYear = htmlspecialchars((string) $this->xml->to_year); $url = htmlspecialchars((string) $this->xml->url); // old $callNumber = htmlspecialchars((string) $this->xml->call_number); // old $repoName = htmlspecialchars((string) $this->xml->repository_name); // old $repoAddr = htmlspecialchars((string) $this->xml->repository_addr); // old } $missingAvailability = false; if (isset($this->xml)) { foreach ($this->xml->repository as $repository) { // the source_location condition is temporary if (!(string) $repository['availability'] && stripos((string) $repository['source_location'], 'www.familysearch.org/Eng/Library/fhlcatalog') === false) { $missingAvailability = true; } } if ($url && stripos($url, 'www.familysearch.org/Eng/Library/fhlcatalog') === false) { $missingAvailability = true; } } if ($missingAvailability) { $result .= "<p><font color=red>Please select an Availability</font></p>"; } if (!StructuredData::isValidYear($fromYear) || !StructuredData::isValidYear($toYear)) { if (!StructuredData::isValidYear($fromYear)) { $fromYearStyle = $invalidStyle; } if (!StructuredData::isValidYear($toYear)) { $toYearStyle = $invalidStyle; } $result .= "<p><font color=red>The year range is not valid</font></p>"; } // display edit fields $result .= "<h2>Source information</h2><table>" . '<tr><td align=right>Type:</td><td align=left>' . StructuredData::addSelectToHtml(1, 'source_type', self::$SOURCE_TYPE_OPTIONS, $sourceType, 'onChange="showSourceFields()"') . $tm->addMsgTip('SourceType') . '</td></tr>' . '<tr id="authors_row"><td align=right>Authors:<br/><font size=\\"-1\\"><i>one per line<br/>surname, given</i></font></td>' . "<td align=left><textarea tabindex=\"1\" name=\"authors\" rows=\"3\" cols=\"60\">{$authors}</textarea></td></tr>" . "<tr id=\"source_title_row\"><td align=right>Title:</td><td align=left><input tabindex=\"1\" name=\"source_title\" value=\"{$sourceTitle}\" size=\"60\"/></td></tr>" . "<tr id=\"subtitle_row\"><td align=right>Subtitle:</td><td align=left><input tabindex=\"1\" name=\"subtitle\" value=\"{$subtitle}\" size=\"60\"/></td></tr>" . "<tr id=\"publisher_row\"><td align=right>Publisher:</td><td align=left><input tabindex=\"1\" name=\"publisher\" value=\"{$publisher}\" size=\"60\"/></td></tr>" . "<tr id=\"date_issued_row\"><td align=right>Date issued:</td><td align=left><input tabindex=\"1\" name=\"date_issued\" value=\"{$dateIssued}\" size=\"20\"/></td></tr>" . "<tr id=\"place_issued_row\"><td align=right>Place issued:</td><td align=left><input tabindex=\"1\" name=\"place_issued\" value=\"{$placeIssued}\" size=\"60\"/></td></tr>" . "<tr id=\"series_name_row\"><td align=right>Periodical/Series name:</td><td align=left><input tabindex=\"1\" class=\"source_input\" name=\"series_name\" value=\"{$seriesName}\" size=\"60\"/></td></tr>" . "<tr id=\"volumes_row\"><td align=right>Number of volumes:</td><td align=left><input tabindex=\"1\" name=\"volumes\" value=\"{$volumes}\" size=\"10\"/></td></tr>" . "<tr id=\"pages_row\"><td align=right>Volume/Film#/Pages:</td><td align=left><input tabindex=\"1\" name=\"pages\" value=\"{$pages}\" size=\"20\"/></td></tr>" . "<tr id=\"references_row\"><td align=right>References/Cites:</td><td align=left><input tabindex=\"1\" name=\"references\" value=\"{$references}\" size=\"60\"/></td></tr>" . "</table>"; $result .= '<h2>Coverage</h2><table>' . "<tr><td align=right>Surnames covered:<br/><i>one per line</i></td><td align=left><textarea tabindex=\"1\" name=\"surnames\" rows=\"3\" cols=\"60\">{$surnames}</textarea></td></tr>" . "<tr><td align=right>Places covered:<br/><i>one per line</i></td><td align=left><textarea class=\"place_input\" tabindex=\"1\" name=\"places\" rows=\"3\" cols=\"60\">{$places}</textarea></td></tr>" . "<tr><td align=right>Year range:</td><td align=left><input tabindex=\"1\" name=\"fromYear\" value=\"{$fromYear}\" size=\"5\"{$fromYearStyle}/>" . " - <input tabindex=\"1\" name=\"toYear\" value=\"{$toYear}\" size=\"5\"{$toYearStyle}/></td></tr>" . "<tr><td align=right>Subject:</td><td align=left>" . StructuredData::addSelectToHtml(1, 'subject', self::$SOURCE_SUBJECT_OPTIONS, $subjects, 'multiple="multiple"') . "</td></tr>" . "<tr id=\"ethnicity_row\"><td align=right>Ethnicity/Culture:</td><td align=left>" . StructuredData::addSelectToHtml(1, 'ethnicity', self::$ETHNICITY_OPTIONS, $ethnicity) . "</td></tr>" . "<tr id=\"religion_row\"><td align=right>Religion:</td><td align=left>" . StructuredData::addSelectToHtml(1, 'religion', self::$RELIGION_OPTIONS, $religion) . "</td></tr>" . "<tr id=\"occupation_row\"><td align=right>Occupation:</td><td align=left>" . StructuredData::addSelectToHtml(1, 'occupation', self::$OCCUPATION_OPTIONS, $occupation) . "</td></tr>" . "</table>"; $rows = ''; $i = 0; if (isset($this->xml)) { foreach ($this->xml->repository as $repository) { $rows .= $this->addRepositoryInput($i, htmlspecialchars((string) $repository['title']), htmlspecialchars((string) $repository['source_location']), htmlspecialchars((string) $repository['availability']), (string) $repository['availability'] ? '' : $invalidStyle); $i++; } if ($url) { $rows .= $this->addRepositoryInput($i, '', $url, '', $invalidStyle); $i++; } if ($callNumber || $repoName) { $rows .= $this->addRepositoryInput($i, $repoName, $callNumber, '', $invalidStyle); $i++; } } if ($i == 0) { $rows .= $this->addRepositoryInput($i, '', '', '', ''); $i++; } $result .= '<h2>Repositories</h2>'; $result .= '<table id="repository_table" border="0" width="500px" style="display:block">'; $result .= '<tr><th></th><th>Repository name</th><th>Location (call#, URL) of source within repository</th><th>Availability</th></tr>'; $result .= "{$rows}</table><a href=\"javascript:void(0)\" onClick=\"addRepository('" . implode(',', self::$SOURCE_AVAILABILITY_OPTIONS) . "'); return preventDefaultAction(event);\">Add Repository</a>"; $result .= $tm->getTipTexts(); $result .= "<br><br>Text:<br>"; return $result; }