/**
     * Translation@status
     */
    public function status()
    {
        global $WT_TREE;
        $table_id = \Rhumsaa\Uuid\Uuid::uuid4();
        Theme::theme(new AdministrationTheme())->init($WT_TREE);
        $ctrl = new PageController();
        $ctrl->restrictAccess(Auth::isAdmin())->setPageTitle(I18N::translate('Translations status'))->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addInlineJavascript('
                //Datatable initialisation
				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.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);};
				jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);};
	
				jQuery("#table_missing_' . $table_id . '").DataTable({
					' . I18N::datatablesI18N() . ',			
					sorting: [[0, "asc"]],                    
					pageLength: 15,
                    columns: [
						/* 0 Message	 	*/ null,
                        /* 1 Reference      */ null
					],
				});
                
                jQuery("#table_nonused_' . $table_id . '").DataTable({
					' . I18N::datatablesI18N() . ',			
					sorting: [[0, "asc"]],                    
					pageLength: 15,
                    columns: [
						/* 0 Message	 	*/ null,
                        /* 1 Reference      */ null
					],
				});
            ');
        $source_code_paths = array(WT_ROOT . 'vendor/jon48/webtrees-lib/src', WT_ROOT . 'vendor/jon48/webtrees-tools/src/app');
        $analyzer = new TranslationsAnalyzer($source_code_paths);
        $analyzer->load();
        $locale = $analyzer->getLocale();
        $view_bag = new ViewBag();
        $view_bag->set('table_id', $table_id);
        $view_bag->set('module', $this->module);
        $view_bag->set('source_code_paths', $source_code_paths);
        $view_bag->set('title', $ctrl->getPageTitle() . ' - ' . I18N::languageName($locale->languageTag()));
        $view_bag->set('missing_translations', $analyzer->getMissingTranslations());
        $view_bag->set('non_used_translations', $analyzer->getMajNonUsedTranslations());
        $view_bag->set('loading_stats', $analyzer->getLoadingStatistics());
        ViewFactory::make('TranslationStatus', $this, $ctrl, $view_bag)->render();
    }
示例#2
0
	<?php 
        break;
    case 'cleanup2':
        foreach (User::all() as $user) {
            if (Filter::post('del_' . $user->getUserId()) == '1') {
                Log::addAuthenticationLog('Deleted user: '******'The user %s has been deleted.', Filter::escapeHtml($user->getUserName()));
            }
        }
        header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME);
        break;
    default:
        $controller->setPageTitle(I18N::translate('User administration'))->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addInlineJavascript('
			jQuery(".table-user-list").dataTable({
				' . I18N::datatablesI18N() . ',
				stateSave: true,
				stateDuration: 300,
				processing: true,
				serverSide: true,
				ajax: {
					"url": "' . WT_SCRIPT_NAME . '?action=load_json",
					"type": "POST"
				},
				search: {
					search: "' . Filter::escapeJs(Filter::get('filter')) . '"
				},
				autoWidth: false,
				pageLength: ' . Auth::user()->getPreference('admin_users_page_size', 10) . ',
				sorting: [[2, "asc"]],
				columns: [
示例#3
0
            $datum[7] = Filter::escapeHtml($datum[7]);
        }
        // Total filtered/unfiltered rows
        $recordsFiltered = (int) Database::prepare("SELECT FOUND_ROWS()")->fetchOne();
        $recordsTotal = (int) Database::prepare("SELECT COUNT(*) FROM `##change`")->fetchOne();
        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) . ',
			columns: [
			/* change_id   */ { visible: false },
			/* Timestamp   */ { sort: 0 },
			/* Status      */ { },
			/* Record      */ { },
			/* Old data    */ { sortable: false },
			/* New data    */ { sortable: false },
			/* User        */ { },
			/* Family tree */ { }
			]
		});
		jQuery("#from,#to").parent("div").datetimepicker({
			format: "YYYY-MM-DD",
示例#4
0
    /**
     * Render the Ajax response for the sortable table of Sosa family
     * @param AjaxController $controller
     */
    protected function renderFamSosaListIndi(AjaxController $controller)
    {
        global $WT_TREE;
        $listFamSosa = $this->sosa_provider->getFamilySosaListAtGeneration($this->generation);
        $this->view_bag->set('has_sosa', false);
        if (count($listFamSosa) > 0) {
            $this->view_bag->set('has_sosa', true);
            $table_id = 'table-sosa-fam-' . Uuid::uuid4();
            $this->view_bag->set('table_id', $table_id);
            $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.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);};
				jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);};
        
                jQuery("#' . $table_id . '").dataTable( {
					dom: \'<"H"<"filtersH_' . $table_id . '"><"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\',
                    ' . I18N::datatablesI18N(array(16, 32, 64, 128, -1)) . ',
					jQueryUI: true,
					autoWidth: false,
					processing: true,
					retrieve: true,
					columns: [
						/* 0-Sosa */  	   { dataSort: 1, class: "center"},
		                /* 1-SOSA */ 	   { type: "num", visible: false },
						/* 2-Husb Givn */  { dataSort: 4},
						/* 3-Husb Surn */  { dataSort: 5},
						/* 4-GIVN,SURN */  { type: "unicode", visible: false},
						/* 5-SURN,GIVN */  { type: "unicode", visible: false},
						/* 6-Husb Age  */  { dataSort: 7, class: "center"},
						/* 7-AGE       */  { type: "num", visible: false},
						/* 8-Wife Givn */  { dataSort: 10},
						/* 9-Wife Surn */  { dataSort: 11},
						/* 10-GIVN,SURN */ { type: "unicode", visible: false},
						/* 11-SURN,GIVN */ { type: "unicode", visible: false},
						/* 12-Wife Age  */ { dataSort: 13, class: "center"},
						/* 13-AGE       */ { type: "num", visible: false},
						/* 14-Marr Date */ { dataSort: 15, class: "center"},
						/* 15-MARR:DATE */ { visible: false},
						/* 16-Marr Plac */ { type: "unicode", class: "center"},
						/* 17-Marr Sour */ { dataSort : 18, class: "center", visible: ' . (ModuleManager::getInstance()->isOperational(Constants::MODULE_MAJ_ISSOURCED_NAME) ? 'true' : 'false') . ' },
						/* 18-Sort Sour */ { visible: false},
						/* 19-Children  */ { dataSort: 20, class: "center"},
						/* 20-NCHI      */ { type: "num", visible: false},
						/* 21-MARR      */ { visible: false},
						/* 22-DEAT      */ { visible: false},
						/* 23-TREE      */ { visible: false}
					],
					sorting: [[0, "asc"]],
					displayLength: 16,
					pagingType: "full_numbers"
			   });
					
				jQuery("#' . $table_id . '")
				/* Hide/show parents */
				.on("click", ".btn-toggle-parents", function() {
					jQuery(this).toggleClass("ui-state-active");
					jQuery(".parents", jQuery(this).closest("table").DataTable().rows().nodes()).slideToggle();
				})
				/* Hide/show statistics */
				.on("click",  ".btn-toggle-statistics", function() {
					jQuery(this).toggleClass("ui-state-active");
					jQuery("#fam_list_table-charts_' . $table_id . '").slideToggle();
				})
				/* Filter buttons in table header */
				.on("click", "button[data-filter-column]", function() {
					var btn = $(this);
					// De-activate the other buttons in this button group
					btn.siblings().removeClass("ui-state-active");
					// Apply (or clear) this filter
					var col = jQuery("#' . $table_id . '").DataTable().column(btn.data("filter-column"));
					if (btn.hasClass("ui-state-active")) {
						btn.removeClass("ui-state-active");
						col.search("").draw();
					} else {
						btn.addClass("ui-state-active");
						col.search(btn.data("filter-value")).draw();
					}
				});					
				
				jQuery("#sosa-fam-list").css("visibility", "visible");
				
				jQuery("#btn-toggle-statistics-' . $table_id . '").click();
           ');
            $stats = new Stats($WT_TREE);
            $max_age = max($stats->oldestMarriageMaleAge(), $stats->oldestMarriageFemaleAge()) + 1;
            //-- init chart data
            $marr_by_age = array();
            for ($age = 0; $age <= $max_age; $age++) {
                $marr_by_age[$age] = '';
            }
            $birt_by_decade = array();
            $marr_by_decade = array();
            for ($year = 1550; $year < 2030; $year += 10) {
                $birt_by_decade[$year] = '';
                $marr_by_decade[$year] = '';
            }
            foreach ($listFamSosa as $sosa => $fid) {
                $sfamily = Family::getInstance($fid, $WT_TREE);
                if (!$sfamily || !$sfamily->canShow()) {
                    unset($sfamily[$sosa]);
                    continue;
                }
                $mdate = $sfamily->getMarriageDate();
                if (($husb = $sfamily->getHusband()) && ($hdate = $husb->getBirthDate()) && $hdate->isOK() && $mdate->isOK()) {
                    if (FunctionsPrint::isDateWithinChartsRange($hdate)) {
                        $birt_by_decade[(int) ($hdate->gregorianYear() / 10) * 10] .= $husb->getSex();
                    }
                    $hage = Date::getAge($hdate, $mdate, 0);
                    if ($hage >= 0 && $hage <= $max_age) {
                        $marr_by_age[$hage] .= $husb->getSex();
                    }
                }
                if (($wife = $sfamily->getWife()) && ($wdate = $wife->getBirthDate()) && $wdate->isOK() && $mdate->isOK()) {
                    if (FunctionsPrint::isDateWithinChartsRange($wdate)) {
                        $birt_by_decade[(int) ($wdate->gregorianYear() / 10) * 10] .= $wife->getSex();
                    }
                    $wage = Date::getAge($wdate, $mdate, 0);
                    if ($wage >= 0 && $wage <= $max_age) {
                        $marr_by_age[$wage] .= $wife->getSex();
                    }
                }
                if ($mdate->isOK() && FunctionsPrint::isDateWithinChartsRange($mdate) && $husb && $wife) {
                    $marr_by_decade[(int) ($mdate->gregorianYear() / 10) * 10] .= $husb->getSex() . $wife->getSex();
                }
                $listFamSosa[$sosa] = $sfamily;
            }
            $this->view_bag->set('sosa_list', $listFamSosa);
            $this->view_bag->set('chart_births', FunctionsPrintLists::chartByDecade($birt_by_decade, I18N::translate('Decade of birth')));
            $this->view_bag->set('chart_marriages', FunctionsPrintLists::chartByDecade($marr_by_decade, I18N::translate('Decade of marriage')));
            $this->view_bag->set('chart_ages', FunctionsPrintLists::chartByAge($marr_by_age, I18N::translate('Age in year of marriage')));
        }
        ViewFactory::make('SosaListFam', $this, $controller, $this->view_bag)->render();
    }
示例#5
0
    /**
     * Format a table of events
     *
     * @param GedcomRecord[] $records
     * @param string         $sort
     * @param bool           $show_user
     *
     * @return string
     */
    private function changesTable($records, $sort, $show_user)
    {
        global $controller;
        $table_id = 'table-chan-' . Uuid::uuid4();
        // lists requires a unique ID in case there are multiple lists per page
        switch ($sort) {
            case 'name':
            default:
                $aaSorting = "[2,'asc'], [4,'desc']";
                break;
            case 'date_asc':
                $aaSorting = "[4,'asc'], [2,'asc']";
                break;
            case 'date_desc':
                $aaSorting = "[4,'desc'], [2,'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: 2 },
						/* 2-SORTNAME */ { type: "unicode" },
						/* 3-Change */   { dataSort: 4 },
						/* 4-DATE */     null
						' . ($show_user ? ',/* 5-By */      null' : '') . '
					]
				});
			');
        $html .= '<table id="' . $table_id . '" class="width100">';
        $html .= '<thead><tr>';
        $html .= '<th></th>';
        $html .= '<th>' . I18N::translate('Record') . '</th>';
        $html .= '<th hidden>SORTNAME</th>';
        $html .= '<th>' . GedcomTag::getLabel('CHAN') . '</th>';
        $html .= '<th hidden>DATE</th>';
        if ($show_user) {
            $html .= '<th>' . GedcomTag::getLabel('_WT_USER') . '</th>';
        }
        $html .= '</tr></thead><tbody>';
        foreach ($records as $record) {
            $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 = '&nbsp;';
                    break;
            }
            $html .= '<a href="' . $record->getHtmlUrl() . '">' . $icon . '</a>';
            $html .= '</td>';
            $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>';
            $html .= '<td hidden>' . $record->getSortName() . '</td>';
            $html .= '<td class="wrap">' . $record->lastChangeTimestamp() . '</td>';
            $html .= '<td hidden>' . $record->lastChangeTimestamp(true) . '</td>';
            if ($show_user) {
                $html .= '<td class="wrap">' . Filter::escapeHtml($record->lastChangeUser()) . '</td>';
            }
            $html .= '</tr>';
        }
        $html .= '</tbody></table>';
        return $html;
    }
示例#6
0
    /**
     * 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;
        $days = $this->getBlockSetting($block_id, 'days', '7');
        $infoStyle = $this->getBlockSetting($block_id, 'infoStyle', 'table');
        $calendar = $this->getBlockSetting($block_id, 'calendar', 'jewish');
        $block = $this->getBlockSetting($block_id, 'block', '1');
        foreach (array('days', 'infoStyle', 'block') as $name) {
            if (array_key_exists($name, $cfg)) {
                ${$name} = $cfg[$name];
            }
        }
        $startjd = WT_CLIENT_JD;
        $endjd = WT_CLIENT_JD + $days - 1;
        $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 . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;ctype=' . $ctype . '"></a>';
        } else {
            $title = '';
        }
        $title .= $this->getTitle();
        $content = '';
        // The standard anniversary rules cover most of the Yahrzeit rules, we just
        // need to handle a few special cases.
        // Fetch normal anniversaries...
        $yahrzeits = array();
        for ($jd = $startjd - 1; $jd <= $endjd + $days; ++$jd) {
            foreach (FunctionsDb::getAnniversaryEvents($jd, 'DEAT _YART', $WT_TREE) as $fact) {
                // Exact hebrew dates only
                $date = $fact->getDate();
                if ($date->minimumDate() instanceof JewishDate && $date->minimumJulianDay() === $date->maximumJulianDay()) {
                    $fact->jd = $jd;
                    $yahrzeits[] = $fact;
                }
            }
        }
        // ...then adjust dates
        $jewish_calendar = new JewishCalendar();
        foreach ($yahrzeits as $yahrzeit) {
            if ($yahrzeit->getTag() === 'DEAT') {
                $today = new JewishDate($yahrzeit->jd);
                $hd = $yahrzeit->getDate()->minimumDate();
                $hd1 = new JewishDate($hd);
                $hd1->y += 1;
                $hd1->setJdFromYmd();
                // Special rules. See http://www.hebcal.com/help/anniv.html
                // Everything else is taken care of by our standard anniversary rules.
                if ($hd->d == 30 && $hd->m == 2 && $hd->y != 0 && $hd1->daysInMonth() < 30) {
                    // 30 CSH - Last day in CSH
                    $yahrzeit->jd = $jewish_calendar->ymdToJd($today->y, 3, 1) - 1;
                } elseif ($hd->d == 30 && $hd->m == 3 && $hd->y != 0 && $hd1->daysInMonth() < 30) {
                    // 30 KSL - Last day in KSL
                    $yahrzeit->jd = $jewish_calendar->ymdToJd($today->y, 4, 1) - 1;
                } elseif ($hd->d == 30 && $hd->m == 6 && $hd->y != 0 && $today->daysInMonth() < 30 && !$today->isLeapYear()) {
                    // 30 ADR - Last day in SHV
                    $yahrzeit->jd = $jewish_calendar->ymdToJd($today->y, 6, 1) - 1;
                }
            }
        }
        switch ($infoStyle) {
            case 'list':
                foreach ($yahrzeits as $yahrzeit) {
                    if ($yahrzeit->jd >= $startjd && $yahrzeit->jd < $startjd + $days) {
                        $ind = $yahrzeit->getParent();
                        $content .= "<a href=\"" . $ind->getHtmlUrl() . "\" class=\"list_item name2\">" . $ind->getFullName() . "</a>" . $ind->getSexImage();
                        $content .= "<div class=\"indent\">";
                        $content .= $yahrzeit->getDate()->display(true);
                        $content .= ', ' . I18N::translate('%s year anniversary', $yahrzeit->anniv);
                        $content .= "</div>";
                    }
                }
                break;
            case 'table':
            default:
                $table_id = Uuid::uuid4();
                // table requires 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,
						sorting: [[5,"asc"]],
						columns: [
							/* 0-name */ { dataSort: 1 },
							/* 1-NAME */ { visible: false },
							/* 2-date */ { dataSort: 3 },
							/* 3-DATE */ { visible: false },
							/* 4-Aniv */ { class: "center"},
							/* 5-yart */ { dataSort: 6 },
							/* 6-YART */ { visible: false }
						]
					});
					jQuery("#' . $table_id . '").css("visibility", "visible");
					jQuery(".loading-image").css("display", "none");
				');
                $content = '';
                $content .= '<div class="loading-image">&nbsp;</div>';
                $content .= '<table id="' . $table_id . '" class="width100" style="visibility:hidden;">';
                $content .= '<thead><tr>';
                $content .= '<th>' . GedcomTag::getLabel('NAME') . '</th>';
                $content .= '<th>' . GedcomTag::getLabel('NAME') . '</th>';
                $content .= '<th>' . GedcomTag::getLabel('DEAT') . '</th>';
                $content .= '<th>DEAT</th>';
                $content .= '<th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th>';
                $content .= '<th>' . GedcomTag::getLabel('_YART') . '</th>';
                $content .= '<th>_YART</th>';
                $content .= '</tr></thead><tbody>';
                foreach ($yahrzeits as $yahrzeit) {
                    if ($yahrzeit->jd >= $startjd && $yahrzeit->jd < $startjd + $days) {
                        $content .= '<tr>';
                        $ind = $yahrzeit->getParent();
                        // Individual name(s)
                        $name = $ind->getFullName();
                        $url = $ind->getHtmlUrl();
                        $content .= '<td>';
                        $content .= '<a href="' . $url . '">' . $name . '</a>';
                        $content .= $ind->getSexImage();
                        $addname = $ind->getAddName();
                        if ($addname) {
                            $content .= '<br><a href="' . $url . '">' . $addname . '</a>';
                        }
                        $content .= '</td>';
                        $content .= '<td>' . $ind->getSortName() . '</td>';
                        // death/yahrzeit event date
                        $content .= '<td>' . $yahrzeit->getDate()->display() . '</td>';
                        $content .= '<td>' . $yahrzeit->getDate()->julianDay() . '</td>';
                        // sortable date
                        // Anniversary
                        $content .= '<td>' . $yahrzeit->anniv . '</td>';
                        // upcomming yahrzeit dates
                        switch ($calendar) {
                            case 'gregorian':
                                $today = new GregorianDate($yahrzeit->jd);
                                break;
                            case 'jewish':
                            default:
                                $today = new JewishDate($yahrzeit->jd);
                                break;
                        }
                        $td = new Date($today->format('%@ %A %O %E'));
                        $content .= '<td>' . $td->display() . '</td>';
                        $content .= '<td>' . $td->julianDay() . '</td>';
                        // sortable date
                        $content .= '</tr>';
                    }
                }
                $content .= '</tbody></table>';
                break;
        }
        if ($template) {
            if ($block) {
                $class .= ' small_inner_block';
            }
            return Theme::theme()->formatBlock($id, $title, $class, $content);
        } else {
            return $content;
        }
    }
示例#7
0
    /**
     * Show the list of stories
     */
    private function showList()
    {
        global $controller, $WT_TREE;
        $controller = new PageController();
        $controller->setPageTitle($this->getTitle())->pageHeader()->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript('
				jQuery("#story_table").dataTable({
					dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
					' . I18N::datatablesI18N() . ',
					autoWidth: false,
					paging: true,
					pagingType: "full_numbers",
					lengthChange: true,
					filter: true,
					info: true,
					jQueryUI: true,
					sorting: [[0,"asc"]],
					columns: [
						/* 0-name */ null,
						/* 1-NAME */ null
					]
				});
			');
        $stories = Database::prepare("SELECT block_id, xref" . " FROM `##block` b" . " WHERE module_name=?" . " AND gedcom_id=?" . " ORDER BY xref")->execute(array($this->getName(), $WT_TREE->getTreeId()))->fetchAll();
        echo '<h2 class="center">', I18N::translate('Stories'), '</h2>';
        if (count($stories) > 0) {
            echo '<table id="story_table" class="width100">';
            echo '<thead><tr>
				<th>', I18N::translate('Story title'), '</th>
				<th>', I18N::translate('Individual'), '</th>
				</tr></thead>
				<tbody>';
            foreach ($stories as $story) {
                $indi = Individual::getInstance($story->xref, $WT_TREE);
                $story_title = $this->getBlockSetting($story->block_id, 'title');
                $languages = $this->getBlockSetting($story->block_id, 'languages');
                if (!$languages || in_array(WT_LOCALE, explode(',', $languages))) {
                    if ($indi) {
                        if ($indi->canShow()) {
                            echo '<tr><td><a href="' . $indi->getHtmlUrl() . '#stories">' . $story_title . '</a></td><td><a href="' . $indi->getHtmlUrl() . '#stories">' . $indi->getFullName() . '</a></td></tr>';
                        }
                    } else {
                        echo '<tr><td>', $story_title, '</td><td class="error">', $story->xref, '</td></tr>';
                    }
                }
            }
            echo '</tbody></table>';
        }
    }
    /**
     * Format a table of events
     *
     * @param GedcomRecord[] $records
     * @param string         $sort
     * @param bool           $show_user
     *
     * @return string
     */
    private function changesTable($records, $sort, $show_user)
    {
        global $controller;
        $table_id = 'table-chan-' . Uuid::uuid4();
        // lists requires a unique ID in case there are multiple lists per page
        switch ($sort) {
            case 'name':
            default:
                $aaSorting = "[1,'asc'], [2,'desc']";
                break;
            case 'date_asc':
                $aaSorting = "[2,'asc'], [1,'asc']";
                break;
            case 'date_desc':
                $aaSorting = "[2,'desc'], [1,'asc']";
                break;
        }
        $html = '';
        $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript('
				jQuery("#' . $table_id . '").dataTable({
					dom: \'t\',
					paging: false,
					autoWidth:false,
					lengthChange: false,
					filter: false,
					' . I18N::datatablesI18N() . ',
					jQueryUI: true,
					sorting: [' . $aaSorting . '],
					columns: [
						{ sortable: false, class: "center" },
						null,
						null,
						{ visible: ' . ($show_user ? 'true' : 'false') . ' }
					]
				});
			');
        $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 .= '</tr></thead><tbody>';
        foreach ($records as $record) {
            $html .= '<tr><td>';
            switch ($record::RECORD_TYPE) {
                case 'INDI':
                    $html .= $record->getSexImage('small');
                    break;
                case 'FAM':
                    $html .= '<i class="icon-button_family"></i>';
                    break;
                case 'OBJE':
                    $html .= '<i class="icon-button_media"></i>';
                    break;
                case 'NOTE':
                    $html .= '<i class="icon-button_note"></i>';
                    break;
                case 'SOUR':
                    $html .= '<i class="icon-button_source"></i>';
                    break;
                case 'REPO':
                    $html .= '<i class="icon-button_repository"></i>';
                    break;
            }
            $html .= '</td>';
            $html .= '<td data-sort="' . Filter::escapeHtml($record->getSortName()) . '">';
            $html .= '<a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a>';
            $addname = $record->getAddName();
            if ($addname) {
                $html .= '<div class="indent"><a href="' . $record->getHtmlUrl() . '">' . $addname . '</a></div>';
            }
            $html .= '</td>';
            $html .= '<td data-sort="' . $record->lastChangeTimestamp(true) . '">' . $record->lastChangeTimestamp() . '</td>';
            $html .= '<td>' . Filter::escapeHtml($record->lastChangeUser()) . '</td>';
            $html .= '</tr>';
        }
        $html .= '</tbody></table>';
        return $html;
    }
    /**
     * AdminConfig@index
     */
    public function index()
    {
        global $WT_TREE;
        HookProvider::getInstance()->updateHooks();
        $action = Filter::post('action');
        if ($action == 'update' && Filter::checkCsrf()) {
            $this->update();
        }
        Theme::theme(new AdministrationTheme())->init($WT_TREE);
        $ctrl = new PageController();
        $ctrl->restrictAccess(Auth::isAdmin())->setPageTitle($this->module->getTitle());
        $table_id = 'table-installedhooks-' . Uuid::uuid4();
        $view_bag = new ViewBag();
        $view_bag->set('title', $ctrl->getPageTitle());
        $view_bag->set('table_id', $table_id);
        $view_bag->set('hook_list', HookProvider::getInstance()->getRawInstalledHooks());
        $ctrl->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addInlineJavascript('
		  	jQuery(document).ready(function() {
				jQuery("#' . $table_id . '").dataTable( {
					' . I18N::datatablesI18N() . ',		
					sorting: [[ 2, "asc" ], [ 3, "asc" ]],
					displayLength: 10,
					pagingType: "full_numbers",
					columns: [
						/* 0 Enabled 		*/	{ dataSort: 1, class: "center" },
						/* 1 Enabled sort	*/	{ visible: false},
						/* 2 Hook function	*/	null,
						/* 3 Hook context	*/	null,
						/* 4 Module name	*/	null,
						/* 5 Priority		*/	{ dataSort: 6, class: "center" },
						/* 6 Priority sort	*/	{ type: "num", visible: false}
					]
			  });
			});
		');
        ViewFactory::make('AdminConfig', $this, $ctrl, $view_bag)->render();
    }
示例#10
0
    /**
     * 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 . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;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">&nbsp;</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;
        }
    }
示例#11
0
    /**
     * Print a table of events
     *
     * @param int $startjd
     * @param int $endjd
     * @param string $events
     * @param bool $only_living
     * @param string $sort_by
     *
     * @return string
     */
    public static function eventsTable($startjd, $endjd, $events = 'BIRT MARR DEAT', $only_living = false, $sort_by = 'anniv')
    {
        global $controller, $WT_TREE;
        $html = '';
        $table_id = 'table-even-' . Uuid::uuid4();
        // lists requires a unique ID in case there are multiple lists per page
        $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript('
				jQuery("#' . $table_id . '").dataTable({
					dom: \'t\',
					' . I18N::datatablesI18N() . ',
					autoWidth: false,
					paging: false,
					lengthChange: false,
					filter: false,
					info: true,
					jQueryUI: true,
					sorting: [[ ' . ($sort_by == 'alpha' ? 1 : 3) . ', "asc"]],
					columns: [
						/* 0-Record */ { dataSort: 1 },
						/* 1-NAME */   { visible: false },
						/* 2-Date */   { dataSort: 3 },
						/* 3-DATE */   { visible: false },
						/* 4-Anniv. */ { dataSort: 5, class: "center" },
						/* 5-ANNIV  */ { type: "num", visible: false },
						/* 6-Event */  { class: "center" }
					]
				});
			');
        // Did we have any output?  Did we skip anything?
        $output = 0;
        $filter = 0;
        $filtered_events = array();
        foreach (FunctionsDb::getEventsList($startjd, $endjd, $events, $WT_TREE) as $fact) {
            $record = $fact->getParent();
            //-- only living people ?
            if ($only_living) {
                if ($record instanceof Individual && $record->isDead()) {
                    $filter++;
                    continue;
                }
                if ($record instanceof Family) {
                    $husb = $record->getHusband();
                    if (is_null($husb) || $husb->isDead()) {
                        $filter++;
                        continue;
                    }
                    $wife = $record->getWife();
                    if (is_null($wife) || $wife->isDead()) {
                        $filter++;
                        continue;
                    }
                }
            }
            //-- Counter
            $output++;
            if ($output == 1) {
                //-- table body
                $html .= '<table id="' . $table_id . '" class="width100">';
                $html .= '<thead><tr>';
                $html .= '<th>' . I18N::translate('Record') . '</th>';
                $html .= '<th>NAME</th>';
                //hidden by datatables code
                $html .= '<th>' . GedcomTag::getLabel('DATE') . '</th>';
                $html .= '<th>DATE</th>';
                //hidden by datatables code
                $html .= '<th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th>';
                $html .= '<th>ANNIV</th>';
                $html .= '<th>' . GedcomTag::getLabel('EVEN') . '</th>';
                $html .= '</tr></thead><tbody>';
            }
            $filtered_events[] = $fact;
        }
        foreach ($filtered_events as $n => $fact) {
            $record = $fact->getParent();
            $html .= '<tr>';
            $html .= '<td>';
            $html .= '<a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a>';
            if ($record instanceof Individual) {
                $html .= $record->getSexImage();
            }
            $html .= '</td>';
            $html .= '<td>' . $record->getSortName() . '</td>';
            $html .= '<td>' . $fact->getDate()->display() . '</td>';
            $html .= '<td>' . $n . '</td>';
            $html .= '<td>' . ($fact->anniv ? I18N::number($fact->anniv) : '') . '</td>';
            $html .= '<td>' . $fact->anniv . '</td>';
            $html .= '<td>' . $fact->getLabel() . '</td>';
            $html .= '</tr>';
        }
        if ($output != 0) {
            $html .= '</tbody></table>';
        }
        // Print a final summary message about restricted/filtered facts
        $summary = '';
        if ($endjd == WT_CLIENT_JD) {
            // We're dealing with the Today’s Events block
            if ($output == 0) {
                if ($filter == 0) {
                    $summary = I18N::translate('No events exist for today.');
                } else {
                    $summary = I18N::translate('No events for living individuals exist for today.');
                }
            }
        } else {
            // We're dealing with the Upcoming Events block
            if ($output == 0) {
                if ($filter == 0) {
                    if ($endjd == $startjd) {
                        $summary = I18N::translate('No events exist for tomorrow.');
                    } else {
                        // I18N: translation for %s==1 is unused; it is translated separately as “tomorrow”
                        $summary = I18N::plural('No events exist for the next %s day.', 'No events exist for the next %s days.', $endjd - $startjd + 1, I18N::number($endjd - $startjd + 1));
                    }
                } else {
                    if ($endjd == $startjd) {
                        $summary = I18N::translate('No events for living individuals exist for tomorrow.');
                    } else {
                        // I18N: translation for %s==1 is unused; it is translated separately as “tomorrow”
                        $summary = I18N::plural('No events for living people exist for the next %s day.', 'No events for living people exist for the next %s days.', $endjd - $startjd + 1, I18N::number($endjd - $startjd + 1));
                    }
                }
            }
        }
        if ($summary != "") {
            $html .= '<strong>' . $summary . '</strong>';
        }
        return $html;
    }
 /**
  * Certificate@listAll
  */
 public function listAll()
 {
     global $WT_TREE;
     $controller = new PageController();
     $controller->setPageTitle(I18N::translate('Certificates'))->restrictAccess($this->module->getSetting('MAJ_SHOW_CERT', Auth::PRIV_HIDE) >= Auth::accessLevel($WT_TREE));
     $city = Filter::get('city');
     if (!empty($city) && strlen($city) > 22) {
         $city = Functions::decryptFromSafeBase64($city);
         $controller->setPageTitle(I18N::translate('Certificates for %s', $city));
     }
     $data = new ViewBag();
     $data->set('title', $controller->getPageTitle());
     $data->set('url_module', $this->module->getName());
     $data->set('url_action', 'Certificate@listAll');
     $data->set('url_ged', $WT_TREE->getNameUrl());
     $data->set('cities', $this->provider->getCitiesList());
     $data->set('selected_city', $city);
     $data->set('has_list', false);
     if (!empty($city)) {
         $table_id = 'table-certiflist-' . Uuid::uuid4();
         $certif_list = $this->provider->getCertificatesList($city);
         if (!empty($certif_list)) {
             $data->set('has_list', true);
             $data->set('table_id', $table_id);
             $data->set('certificate_list', $certif_list);
             $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript('
                     /* Initialise datatables */
     				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.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);};
     				jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);};
                     
                     jQuery("#' . $table_id . '").dataTable( {
     					dom: \'<"H"<"filtersH_' . $table_id . '">T<"dt-clear">pf<"dt-clear">irl>t<"F"pl<"dt-clear"><"filtersF_' . $table_id . '">>\',
 					    ' . I18N::datatablesI18N() . ',
 					    jQueryUI: true,
     					autoWidth: false,
     					processing: true,
     					columns: [
     		                    /* 0-Date */  			{ dataSort: 1, width: "15%", class: "center" },
     							/* 1-DateSort */		{ type: "unicode", visible : false },
     		                    /* 2-Type */ 			{ width: "5%", searchable: false, class: "center"},
     		                    /* 3-CertificateSort */ { type: "unicode", visible : false },
     		                    /* 4-Certificate */     { dataSort: 3, class: "left" }
     		                ],
     		            sorting: [[0,"asc"], [2,"asc"]],
     					displayLength: 20,
     					pagingType: "full_numbers"
     			   });
     				jQuery(".certificate-list").css("visibility", "visible");
     				jQuery(".loading-image").css("display", "none");
                 ');
         }
     }
     ViewFactory::make('CertificatesList', $this, $controller, $data)->render();
 }
    /**
     * 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', '1');
        $show_unassigned = $this->getBlockSetting($block_id, 'show_unassigned', '1');
        $show_future = $this->getBlockSetting($block_id, 'show_future', '1');
        $block = $this->getBlockSetting($block_id, 'block', '1');
        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('Configure') . '" href="block_edit.php?block_id=' . $block_id . '&amp;ged=' . $WT_TREE->getNameHtml() . '&amp;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: [
					/* 0-DATE */     { visible: false },
					/* 1-Date */     { dataSort: 0 },
					/* 1-Record */   null,
					/* 2-Username */ null,
					/* 3-Text */     null
				]
			});
			jQuery("#' . $table_id . '").css("visibility", "visible");
			jQuery(".loading-image").css("display", "none");
		');
        $content = '';
        $content .= '<div class="loading-image">&nbsp;</div>';
        $content .= '<table id="' . $table_id . '" style="visibility:hidden;">';
        $content .= '<thead><tr>';
        $content .= '<th>DATE</th>';
        //hidden by datables code
        $content .= '<th>' . GedcomTag::getLabel('DATE') . '</th>';
        $content .= '<th>' . I18N::translate('Record') . '</th>';
        if ($show_unassigned || $show_other) {
            $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;
        foreach (FunctionsDb::getCalendarEvents(0, $end_jd, '_TODO', $WT_TREE) 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>';
                //-- Event date (sortable)
                $content .= '<td>';
                //hidden by datables code
                $content .= $fact->getDate()->julianDay();
                $content .= '</td>';
                $content .= '<td class="wrap">' . $fact->getDate()->display() . '</td>';
                $content .= '<td class="wrap"><a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a></td>';
                if ($show_unassigned || $show_other) {
                    $content .= '<td class="wrap">' . $user_name . '</td>';
                }
                $text = $fact->getValue();
                $content .= '<td class="wrap">' . $text . '</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;
        }
    }
    /**
     * AdminConfig@index
     */
    public function index()
    {
        global $WT_TREE;
        Theme::theme(new AdministrationTheme())->init($WT_TREE);
        $controller = new PageController();
        $controller->restrictAccess(Auth::isAdmin())->setPageTitle($this->module->getTitle());
        $token = $this->module->getSetting('MAJ_AT_FORCE_EXEC_TOKEN');
        if (is_null($token)) {
            $token = Functions::generateRandomToken();
            $this->module->setSetting('PAT_FORCE_EXEC_TOKEN', $token);
        }
        $data = new ViewBag();
        $data->set('title', $controller->getPageTitle());
        $table_id = 'table-admintasks-' . Uuid::uuid4();
        $data->set('table_id', $table_id);
        $data->set('trigger_url_root', WT_BASE_URL . 'module.php?mod=' . $this->module->getName() . '&mod_action=Task@trigger');
        $token = $this->module->getSetting('MAJ_AT_FORCE_EXEC_TOKEN');
        if (is_null($token)) {
            $token = Functions::generateRandomToken();
            $this->module->setSetting('MAJ_AT_FORCE_EXEC_TOKEN', $token);
        }
        $data->set('trigger_token', $token);
        $this->provider->getInstalledTasks();
        $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addInlineJavascript('
                //Datatable initialisation
				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.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);};
				jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);};
	
				var adminTasksTable = jQuery("#' . $table_id . '").DataTable({
					' . I18N::datatablesI18N() . ',			
					sorting: [[3, "asc"]],
					pageLength: 10,
                    processing: true,
                    serverSide : true,
					ajax : {
						url : "module.php?mod=' . $this->module->getName() . '&mod_action=AdminConfig@jsonTasksList&ged=' . $WT_TREE->getNameUrl() . '",
                        type : "POST"
					},
                    columns: [
						/* 0 Edit		 	*/ { sortable: false, className: "text-center"},
                        /* 1 task_name      */ { visible: false },
						/* 2 Enabled 		*/ { sortable: false, className: "text-center"  },
						/* 3 Task Title		*/ null,
						/* 4 Last Run		*/ null,
						/* 5 Last status 	*/ { className: "text-center" },
						/* 6 Frequency      */ { sortable: false, className: "text-center" },
						/* 7 Nb Occcurrences*/ { sortable: false, className: "text-center" },
						/* 8 Is Running    	*/ { sortable: false, className: "text-center" },					
						/* 9 Run task		*/ { sortable: false, className: "text-center" }
					],
				});
                
                ')->addInlineJavascript('					
					function generate_force_token() {
						jQuery("#bt_genforcetoken").attr("disabled", "disabled");
						jQuery("#bt_tokentext").empty().html("<i class=\\"fa fa-spinner fa-pulse fa-fw\\"></i>");
						jQuery("#token_url").load(
							"module.php?mod=' . $this->module->getName() . '&mod_action=AdminConfig@generateToken",
							function() {
								jQuery("#bt_genforcetoken").removeAttr("disabled");
								jQuery("#bt_tokentext").empty().html("' . I18N::translate('Regenerate token') . '");
                                adminTasksTable.ajax.reload();
							}
						);
					}
				
                    function set_admintask_status(task, status) {
                		jQuery.ajax({
                            url: "module.php", 
                            type: "GET",
                            data: {
                			    mod: "' . $this->module->getName() . '",
                                mod_action:  "Task@setStatus",
                			    task: task,
                                status: status
                            },
                            error: function(result, stat, error) {
                                var err = typeof result.responseJSON === "undefined" ? error : result.responseJSON.error;
                                alert("' . I18N::translate('An error occured while editing this task:') . '" + err);
                            },
                            complete: function(result, stat) {
                                adminTasksTable.ajax.reload(null, false);
                            }                            
                		});
                    } 
                    
                    function run_admintask(taskname) {
                        jQuery("#bt_runtask_" + taskname).attr("disabled", "disabled");
				        jQuery("#bt_runtasktext_" + taskname).empty().html("<i class=\\"fa fa-cog fa-spin fa-fw\\"></i><span class=\\"sr-only\\">' . I18N::translate('Running') . '</span>");
				        jQuery("#bt_runtasktext_" + taskname).load(
					       "module.php?mod=' . $this->module->getName() . '&mod_action=Task@trigger&force=' . $token . '&task=" + taskname,
        					function() {
        						jQuery("#bt_runtasktext_" + taskname).empty().html("<i class=\\"fa fa-check\\"></i>' . I18N::translate('Done') . '");
        						adminTasksTable.ajax.reload();
        					}
				        );
                    
                    } 
                ');
        ViewFactory::make('AdminConfig', $this, $controller, $data)->render();
    }
    /**
     * AdminConfig@index
     */
    public function index()
    {
        global $WT_TREE;
        Theme::theme(new AdministrationTheme())->init($WT_TREE);
        $controller = new PageController();
        $controller->restrictAccess(Auth::isManager($WT_TREE))->setPageTitle($this->module->getTitle());
        $data = new ViewBag();
        $data->set('title', $controller->getPageTitle());
        $data->set('tree', $WT_TREE);
        $data->set('root_url', 'module.php?mod=' . $this->module->getName() . '&mod_action=AdminConfig');
        $table_id = 'table-geoanalysis-' . Uuid::uuid4();
        $data->set('table_id', $table_id);
        $other_trees = array();
        foreach (Tree::getAll() as $tree) {
            if ($tree->getTreeId() != $WT_TREE->getTreeId()) {
                $other_trees[] = $tree;
            }
        }
        $data->set('other_trees', $other_trees);
        $data->set('places_hierarchy', $this->provider->getPlacesHierarchy());
        $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL)->addInlineJavascript('
                //Datatable initialisation
				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.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);};
				jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);};
	
				var geoAnalysisTable = jQuery("#' . $table_id . '")
                .on("draw.dt", function ( e, settings, json, xhr ) {
                    jQuery("[data-toggle=\'tooltip\']").tooltip();
                }).DataTable({
					' . I18N::datatablesI18N() . ',			
					sorting: [[3, "asc"], [4, "asc"]],
					pageLength: 10,
                    processing: true,
                    serverSide : true,
					ajax : {
						url : "module.php?mod=' . $this->module->getName() . '&mod_action=AdminConfig@jsonGeoAnalysisList&ged=' . $WT_TREE->getNameUrl() . '",
                        type : "POST"
					},
                    columns: [
						/* 0 Edit		 	*/ { sortable: false, className: "text-center"},
                        /* 1 ID             */ { visible: false },
						/* 2 Enabled 		*/ { sortable: false, className: "text-center"  },
						/* 3 Description	*/ null,
						/* 4 Analysis Level	*/ { dataSort: 5, className: "text-center" },
						/* 5 ANAL_LEVEL_SORT*/ { visible: false },
						/* 6 Map 	        */ { sortable: false, className: "text-center" },
						/* 7 Map Top Level 	*/ { sortable: false, className: "text-center" },
						/* 8 Use Flags     	*/ { sortable: false, className: "text-center" },					
						/* 9 Place Details	*/ { sortable: false, className: "text-center" }
					],
				});
                
                ')->addInlineJavascript('				
                    function set_geoanalysis_status(ga_id, status, gedcom) {
                		jQuery.ajax({
                            url: "module.php", 
                            type: "GET",
                            data: {
                			    mod: "' . $this->module->getName() . '",
                                mod_action:  "GeoAnalysis@setStatus",
                			    ga_id: ga_id,
                			    ged: typeof gedcom === "undefined" ? WT_GEDCOM : gedcom,
                                status: status
                            },
                            error: function(result, stat, error) {
                                var err = typeof result.responseJSON === "undefined" ? error : result.responseJSON.error;
                                alert("' . I18N::translate('An error occured while editing this analysis:') . '" + err);
                            },
                            complete: function(result, stat) {
                                geoAnalysisTable.ajax.reload(null, false);
                            }                            
                		});
                    }
                    
                    function delete_geoanalysis(ga_id, status, gedcom) {
                		jQuery.ajax({
                            url: "module.php", 
                            type: "GET",
                            data: {
                			    mod: "' . $this->module->getName() . '",
                                mod_action:  "GeoAnalysis@delete",
                			    ga_id: ga_id,
                			    ged: typeof gedcom === "undefined" ? WT_GEDCOM : gedcom
                            },
                            error: function(result, stat, error) {
                                var err = typeof result.responseJSON === "undefined" ? error : result.responseJSON.error;
                                alert("' . I18N::translate('An error occured while deleting this analysis:') . '" + err);
                            },
                            complete: function(result, stat) {
                                geoAnalysisTable.ajax.reload(null, false);
                            }                            
                		});
                    }
                ');
        ViewFactory::make('AdminConfig', $this, $controller, $data)->render();
    }
    /**
     * Print a table of events
     *
     * @param int $startjd
     * @param int $endjd
     * @param string $events
     * @param bool $only_living
     * @param string $sort_by
     *
     * @return string
     */
    public static function eventsTable($startjd, $endjd, $events = 'BIRT MARR DEAT', $only_living = false, $sort_by = 'anniv')
    {
        global $controller, $WT_TREE;
        $html = '';
        $table_id = 'table-even-' . Uuid::uuid4();
        // lists requires a unique ID in case there are multiple lists per page
        $controller->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL)->addInlineJavascript('
				jQuery.fn.dataTableExt.oSort["text-asc"] = textCompareAsc;
				jQuery.fn.dataTableExt.oSort["text-desc"] = textCompareDesc;
				jQuery("#' . $table_id . '").dataTable({
					dom: "t",
					' . I18N::datatablesI18N() . ',
					autoWidth: false,
					paging: false,
					lengthChange: false,
					filter: false,
					info: true,
					jQueryUI: true,
					sorting: [[ ' . ($sort_by == 'alpha' ? 0 : 1) . ', "asc"]],
					columns: [
						/* Name        */ { type: "text" },
						/* Date        */ { type: "num" },
						/* Anniversary */ { type: "num" },
						/* Event       */ { type: "text" }
					]
				});
			');
        // Did we have any output? Did we skip anything?
        $filter = 0;
        $filtered_events = array();
        foreach (FunctionsDb::getEventsList($startjd, $endjd, $events, $WT_TREE) as $fact) {
            $record = $fact->getParent();
            // Only living people ?
            if ($only_living) {
                if ($record instanceof Individual && $record->isDead()) {
                    $filter++;
                    continue;
                }
                if ($record instanceof Family) {
                    $husb = $record->getHusband();
                    if (is_null($husb) || $husb->isDead()) {
                        $filter++;
                        continue;
                    }
                    $wife = $record->getWife();
                    if (is_null($wife) || $wife->isDead()) {
                        $filter++;
                        continue;
                    }
                }
            }
            $filtered_events[] = $fact;
        }
        if (!empty($filtered_events)) {
            $html .= '<table id="' . $table_id . '" class="width100">';
            $html .= '<thead><tr>';
            $html .= '<th>' . I18N::translate('Record') . '</th>';
            $html .= '<th>' . GedcomTag::getLabel('DATE') . '</th>';
            $html .= '<th><i class="icon-reminder" title="' . I18N::translate('Anniversary') . '"></i></th>';
            $html .= '<th>' . GedcomTag::getLabel('EVEN') . '</th>';
            $html .= '</tr></thead><tbody>';
            foreach ($filtered_events as $n => $fact) {
                $record = $fact->getParent();
                $html .= '<tr>';
                $html .= '<td data-sort="' . Filter::escapeHtml($record->getSortName()) . '">';
                $html .= '<a href="' . $record->getHtmlUrl() . '">' . $record->getFullName() . '</a>';
                if ($record instanceof Individual) {
                    $html .= $record->getSexImage();
                }
                $html .= '</td>';
                $html .= '<td data-sort="' . $fact->getDate()->minimumJulianDay() . '">';
                $html .= $fact->getDate()->display();
                $html .= '</td>';
                $html .= '<td class="center" data-sort="' . $fact->anniv . '">';
                $html .= $fact->anniv ? I18N::number($fact->anniv) : '';
                $html .= '</td>';
                $html .= '<td class="center">' . $fact->getLabel() . '</td>';
                $html .= '</tr>';
            }
            $html .= '</tbody></table>';
        } else {
            if ($endjd === WT_CLIENT_JD) {
                // We're dealing with the Today’s Events block
                if ($filter === 0) {
                    $html .= I18N::translate('No events exist for today.');
                } else {
                    $html .= I18N::translate('No events for living individuals exist for today.');
                }
            } else {
                // We're dealing with the Upcoming Events block
                if ($filter === 0) {
                    if ($endjd === $startjd) {
                        $html .= I18N::translate('No events exist for tomorrow.');
                    } else {
                        $html .= I18N::plural('No events exist for the next %s day.', 'No events exist for the next %s days.', $endjd - $startjd + 1, I18N::number($endjd - $startjd + 1));
                    }
                } else {
                    if ($endjd === $startjd) {
                        $html .= I18N::translate('No events for living individuals exist for tomorrow.');
                    } else {
                        // I18N: translation for %s==1 is unused; it is translated separately as “tomorrow”
                        $html .= I18N::plural('No events for living people exist for the next %s day.', 'No events for living people exist for the next %s days.', $endjd - $startjd + 1, I18N::number($endjd - $startjd + 1));
                    }
                }
            }
        }
        return $html;
    }