<?php // MyDMS. Document Management System // Copyright (C) 2002-2005 Markus Westphal // Copyright (C) 2006-2008 Malcolm Cowe // Copyright (C) 2010 Matteo Lucarelli // Copyright (C) 2009-2012 Uwe Steinmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. class SeedDMS_Theme_Style extends SeedDMS_View_Common { /** * @var string $extraheader extra html code inserted in the html header * of the page * * @access protected */ protected $extraheader; /** * @var array $nonces list of nonces * * @access protected */ protected $nonces; /** * @var string $footerjs js placed in footer of html page * * @access protected */ protected $footerjs; function __construct($params, $theme='bootstrap') { parent::__construct($params, $theme); $this->extraheader = array('js'=>'', 'css'=>'', 'favicon'=>'', 'logo'=>'', 'logolink'=>''); $this->footerjs = array(); $this->nonces = array(); } /** * Add javascript to an internal array which is output at the * end of the page within a document.ready() function. * * @param string $script javascript to be added */ function addFooterJS($script) { /* {{{ */ $this->footerjs[] = $script; } /* }}} */ function htmlStartPage($title="", $bodyClass="", $base="", $httpheader=array()) { /* {{{ */ if(1 || method_exists($this, 'js')) { /* We still need unsafe-eval, because printDocumentChooserHtml and * printFolderChooserHtml will include a javascript file with ajax * which is evaluated by jquery * worker-src blob: is needed for cytoscape * X-WebKit-CSP is deprecated, Chrome understands Content-Security-Policy * since version 25+ * X-Content-Security-Policy is deprecated, Firefox understands * Content-Security-Policy since version 23+ * 'worker-src blob:' is needed for cytoscape * 'unsafe-inline' is needed for jquery 3.6.1 when loading the remote * content of a modal box */ $csp_rules = []; $csp_rule = "script-src 'self' 'unsafe-eval' 'unsafe-inline'"; if($this->nonces) { $csp_rule .= " 'nonce-".implode("' 'nonce-", $this->nonces)."'"; } $csp_rules[] = $csp_rule; $csp_rules[] = "worker-src blob:"; //$csp_rules[] = "style-src 'self'"; /* Do not allow to embed myself into frames on foreigns pages */ $csp_rules[] = "frame-ancestors 'self'"; if($this->hasHook('getCspRules')) { $csp_rules = $this->callHook('getCspRules', $csp_rules); } foreach (array("X-WebKit-CSP", "X-Content-Security-Policy", "Content-Security-Policy") as $csp) { header($csp . ": " . implode('; ', $csp_rules).';'); } } header('X-Content-Type-Options: nosniff'); header('Strict-Transport-Security: max-age=15768000; includeSubDomains; preload'); if($httpheader) { foreach($httpheader as $name=>$value) { header($name . ": " . $value); } } if($this->hasHook('startPage')) $this->callHook('startPage'); echo "<!DOCTYPE html>\n"; echo "<html lang=\""; if(!empty($this->params['session']) && ($slang = $this->params['session']->getLanguage())) { echo str_replace('_', '-', $slang); } else { echo str_replace('_', '-', $this->params['settings']->_language); } echo "\">\n<head>\n"; echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; echo '<meta name="viewport" content="width=device-width, initial-scale=1.0" />'."\n"; if($base) echo '<base href="'.$base.'">'."\n"; elseif($this->baseurl) echo '<base href="'.$this->baseurl.'">'."\n"; $sitename = trim(strip_tags($this->params['sitename'])); if(!empty($this->params['session'])) echo '<link rel="search" type="application/opensearchdescription+xml" href="'.$this->params['settings']->_httpRoot.'out/out.OpensearchDesc.php" title="'.(strlen($sitename)>0 ? $sitename : "").'"/>'."\n"; $parenttheme = 'bootstrap'; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/styles/seeddms.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootstrap-datepicker/css/bootstrap-datepicker.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'styles/'.$parenttheme.'/chosen/css/chosen.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/select2/css/select2.min.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/select2-bootstrap4-theme/select2-bootstrap4.min.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/jqtree/jqtree.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/styles/application.css" rel="stylesheet"/>'."\n"; echo '<link href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/styles/styles.css" rel="stylesheet"/>'."\n"; if($this->extraheader['css']) echo $this->extraheader['css']; if(method_exists($this, 'css')) echo '<link href="'.$this->params['absbaseprefix'].'out/out.'.$this->params['class'].'.php?action=css'.(!empty($_SERVER['QUERY_STRING']) ? '&'.$_SERVER['QUERY_STRING'] : '').'" rel="stylesheet"/>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/jquery/jquery.min.js"></script>'."\n"; if($this->extraheader['js']) echo $this->extraheader['js']; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'styles/'.$parenttheme.'/passwordstrength/jquery.passwordstrength.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/noty/jquery.noty.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/noty/layouts/topRight.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/noty/layouts/topCenter.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/noty/themes/default.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/jqtree/tree.jquery.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootbox/bootbox.min.js"></script>'."\n"; echo '<script type="text/javascript" src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootbox/bootbox.locales.min.js"></script>'."\n"; if(!empty($this->extraheader['favicon'])) echo $this->extraheader['favicon']; else { echo '<link rel="icon" href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/images/favicon.svg" type="image/svg+xml"/>'."\n"; echo '<link rel="apple-touch-icon" sizes="180x180" href="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/images/apple-touch-icon.png">'."\n"; } if(!empty($this->params['session']) && $this->params['session']->getSu()) { ?> <style type="text/css"> nav.navbar.fixed-top { background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#882222), to(#111111)); background-image: webkit-linear-gradient(top, #882222, #111111); background-image: linear-gradient(to bottom, #882222, #111111);; } </style> <?php } echo "<title>".(strlen($sitename)>0 ? $sitename : "SeedDMS").(strlen($title)>0 ? ": " : "").htmlspecialchars($title)."</title>\n"; echo "</head>\n"; echo "<body".(strlen($bodyClass)>0 ? " class=\"".$bodyClass."\"" : "").">\n"; if(!empty($this->params['session']) && $flashmsg = $this->params['session']->getSplashMsg()) { $this->params['session']->clearSplashMsg(); echo "<div class=\"splash\" data-type=\"".$flashmsg['type']."\"".(!empty($flashmsg['timeout']) ? ' data-timeout="'.$flashmsg['timeout'].'"': '').">".$flashmsg['msg']."</div>\n"; } echo "<div class=\"statusbar-container\"><h1>".getMLText('recent_uploads')."</h1></div>\n"; if($this->hasHook('startBody')) $this->callHook('startBody'); } /* }}} */ function htmlAddHeader($head, $type='js') { /* {{{ */ if($type == 'logo' || $type == 'favicon' || $type == 'logolink') $this->extraheader[$type] = $head; else $this->extraheader[$type] .= $head; } /* }}} */ function htmlAddJsHeader($script) { /* {{{ */ $nonce = createNonce(); $this->nonces[] = $nonce; $this->extraheader['js'] .= '<script type="text/javascript" src="'.$script.'" nonce="'.$nonce.'"></script>'."\n"; } /* }}} */ function htmlEndPage($nofooter=false) { /* {{{ */ if(!$nofooter) { $html = $this->footNote(); if($this->hasHook('footNote')) $html = $this->callHook('footNote', $html); echo $html; if($this->params['showmissingtranslations']) { $this->missingLanguageKeys(); } } $parenttheme = 'bootstrap'; echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/popper/popper.min.js"></script>'."\n"; //echo '<script src="'.$this->params['settings']->_httpRoot.'styles/bootstrap/popper.js-1.14.3/dist/umd/popper.js"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootstrap/bootstrap.min.js"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'styles/'.$parenttheme.'/bootstrap/js/bootstrap-typeahead.js"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>'."\n"; foreach(array('de', 'es', 'ar', 'el', 'bg', 'ru', 'hr', 'hu', 'ko', 'pl', 'ro', 'sk', 'tr', 'uk', 'ca', 'nl', 'fi', 'cs', 'it', 'fr', 'sv', 'sl', 'pt-BR', 'zh-CN', 'zh-TW') as $lang) echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/bootstrap-datepicker/locales/bootstrap-datepicker.'.$lang.'.min.js"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'styles/'.$parenttheme.'/chosen/js/chosen.jquery.min.js"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/vendors/select2/js/select2.min.js"></script>'."\n"; parse_str($_SERVER['QUERY_STRING'], $tmp); $tmp['action'] = 'webrootjs'; if(isset($tmp['formtoken'])) unset($tmp['formtoken']); if(isset($tmp['referuri'])) unset($tmp['referuri']); if(!empty($this->params['class'])) echo '<script src="'.$this->params['absbaseprefix'].'out/out.'.$this->params['class'].'.php?'.htmlentities(http_build_query($tmp)).'"></script>'."\n"; echo '<script src="'.$this->params['settings']->_httpRoot.'views/'.$this->theme.'/styles/application.js"></script>'."\n"; if($this->params['enablemenutasks'] && isset($this->params['user']) && $this->params['user']) { $this->addFooterJS('SeedDMSTask.run();'); } if($this->params['enabledropfolderlist'] && isset($this->params['user']) && $this->params['user']) { $this->addFooterJS("SeedDMSTask.add({name: 'dropfolder', interval: 30, func: function(){\$('#menu-dropfolder > div.ajax').trigger('update', {folderid: seeddms_folder});}});"); } if($this->footerjs) { $jscode = "$(document).ready(function () {\n"; foreach($this->footerjs as $script) { $jscode .= $script."\n"; } $jscode .= "});\n"; $hashjs = md5($jscode); if(!is_dir($this->params['cachedir'].'/js')) { SeedDMS_Core_File::makeDir($this->params['cachedir'].'/js'); } if(is_dir($this->params['cachedir'].'/js')) { file_put_contents($this->params['cachedir'].'/js/'.$hashjs.'.js', $jscode); } $tmp['action'] = 'footerjs'; $tmp['hashjs'] = $hashjs; echo '<script src="'.$this->params['absbaseprefix'].'out/out.'.$this->params['class'].'.php?'.htmlentities(http_build_query($tmp)).'"></script>'."\n"; } if(method_exists($this, 'js')) { parse_str($_SERVER['QUERY_STRING'], $tmp); $tmp['action'] = 'js'; echo '<script src="'.$this->params['absbaseprefix'].'out/out.'.$this->params['class'].'.php?'.htmlentities(http_build_query($tmp)).'"></script>'."\n"; } echo "</body>\n</html>\n"; } /* }}} */ function webrootjs() { /* {{{ */ header('Content-Type: application/javascript; charset=UTF-8'); echo "var seeddms_absbaseprefix=\"".$this->params['absbaseprefix']."\";\n"; echo "var seeddms_webroot=\"".$this->params['settings']->_httpRoot."\";\n"; /* Place the current folder id in a js variable, just in case some js code * needs it, e.g. for reloading parts of the page via ajax. */ if(!empty($_REQUEST['folderid'])) echo "var seeddms_folder=".(int) $_REQUEST['folderid'].";\n"; else echo "var seeddms_folder=0;\n"; } /* }}} */ function footerjs() { /* {{{ */ header('Content-Type: application/javascript'); if(file_exists($this->params['cachedir'].'/js/'.$_GET['hashjs'].'.js')) { readfile($this->params['cachedir'].'/js/'.$_GET['hashjs'].'.js'); } } /* }}} */ function missingLanguageKeys() { /* {{{ */ global $MISSING_LANG, $LANG; if($MISSING_LANG) { echo '<div class="container-fluid">'."\n"; $this->rowStart(); $this->columnStart(12); echo $this->errorMsg("This page contains missing translations in the selected language. Please help to improve SeedDMS and provide the translation."); echo "<table class=\"table table-sm\">"; echo "<tr><th>Key</th><th>engl. Text</th><th>Your translation</th></tr>\n"; foreach($MISSING_LANG as $key=>$lang) { echo "<tr><td>".htmlspecialchars($key)."</td><td>".(isset($LANG['en_GB'][$key]) ? $LANG['en_GB'][$key] : '')."</td><td><div class=\"input-group send-missing-translation\"><input name=\"missing-lang-key\" type=\"hidden\" value=\"".$key."\" /><input name=\"missing-lang-lang\" type=\"hidden\" value=\"".$lang."\" /><input type=\"text\" class=\"form-control\" name=\"missing-lang-translation\" placeholder=\"Your translation in '".$lang."'\"/><div class=\"input-group-append\"><button class=\"btn btn-secondary\">Submit</button></div></div></td></tr>"; } echo "</table>"; echo "<div class=\"splash\" data-type=\"error\" data-timeout=\"5500\"><b>There are missing translations on this page!</b><br />Please check the bottom of the page.</div>\n"; echo "</div>\n"; $this->columnEnd(); $this->rowEnd(); } } /* }}} */ function footNote() { /* {{{ */ $html = "<footer class=\"footer border-top\">\n"; $html .= '<div class="container">'."\n"; if ($this->params['printdisclaimer']){ $html .= "<div class=\"disclaimer\">".getMLText("disclaimer")."</div>"; } if (isset($this->params['footnote']) && strlen((string)$this->params['footnote'])>0) { $html .= "<div class=\"footNote\">".(string)$this->params['footnote']."</div>"; } $html .= "</div>\n"; $html .= "</footer>\n"; return $html; } /* }}} */ function contentStart() { /* {{{ */ /* echo "<div class=\"container-fluid\">\n"; echo "<div class=\"row\">\n"; echo "<nav class=\"_col-md-2 d-none d-md-block bg-light sidebar\">\n"; echo "<div class=\"sidebar-sticky\">\n"; echo "lsajdlf"; echo "</div>\n"; echo "</nav>\n"; echo "<main role=\"main\" class=\"_col-md-10 _ml-sm-auto pb-3 px-4\">\n"; */ echo "<main role=\"main\" class=\"container-fluid mt-3 pb-3\">\n"; echo " <div class=\"row-fluid\">\n"; } /* }}} */ function contentEnd() { /* {{{ */ echo " </div>\n"; echo "</main>\n"; /* echo "</div>\n"; echo "</div>\n"; */ } /* }}} */ function globalBanner() { /* {{{ */ echo "<nav class=\"navbar navbar-expand-lg navbar-dark bg-dark fixed-top\">\n"; echo " <a class=\"navbar-brand\" href=\"".(!empty($this->extraheader['logolink']) ? $this->extraheader['logolink'] : $this->params['settings']->_httpRoot."out/out.ViewFolder.php")."\">".(!empty($this->extraheader['logo']) ? '<img id="navbar-logo" src="'.$this->extraheader['logo'].'"/>' : '<img id="navbar-logo" src="'.$this->params['settings']->_httpRoot.'views/bootstrap4/images/seeddms-logo.svg"/>')." <span class=\"d-none d-md-inline-block ml-4\">".(strlen($this->params['sitename'])>0 ? $this->params['sitename'] : "")."</span></a>\n"; echo "</nav>\n"; } /* }}} */ function globalNavigation($folder=null) { /* {{{ */ $dms = $this->params['dms']; $accessobject = $this->params['accessobject']; echo "<nav class=\"navbar navbar-expand-lg navbar-dark bg-dark border-bottom fixed-top\">\n"; echo " <a class=\"navbar-brand\" href=\"".(!empty($this->extraheader['logolink']) ? $this->extraheader['logolink'] : $this->params['settings']->_httpRoot."out/out.ViewFolder.php")."\">".(!empty($this->extraheader['logo']) ? '<img id="navbar-logo" src="'.$this->extraheader['logo'].'">' : '<img id="navbar-logo" src="'.$this->params['settings']->_httpRoot.'views/bootstrap4/images/seeddms-logo.svg">')." <span class=\"d-none d-md-inline-block ml-4\">".(strlen($this->params['sitename'])>0 ? $this->params['sitename'] : "")."</span></a>\n"; if(isset($this->params['user']) && $this->params['user']) { /* search form {{{ */ echo " <form action=\"".$this->params['settings']->_httpRoot."out/out.Search.php\" class=\"form-inline ml-4 mr-auto\" autocomplete=\"off\">"; if ($folder!=null && is_object($folder) && !strcasecmp(get_class($folder), $dms->getClassname('folder'))) { echo " <input type=\"hidden\" name=\"folderid\" value=\"".$folder->getID()."\" />"; } echo " <input type=\"hidden\" name=\"navBar\" value=\"1\" />"; echo " <input name=\"query\" class=\"form-control mr-sm-2 search-query\" ".($this->params['defaultsearchmethod'] == 'fulltext_' ? "id=\"searchfield\"" : "id=\"searchfield\"")." data-provide=\"typeahead\" type=\"search\" style=\"width: 150px;\" placeholder=\"".getMLText("search")."\" aria-label=\"".getMLText("search")."\"/>"; if($this->params['defaultsearchmethod'] == 'fulltext') echo " <input type=\"hidden\" name=\"fullsearch\" value=\"1\" />"; echo "</form>\n"; /* }}} End of search form */ echo " <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarMain\" aria-controls=\"navbarMain\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n"; echo " <span class=\"navbar-toggler-icon\"></span>\n"; echo " </button>\n"; echo " <div class=\"collapse navbar-collapse\" id=\"navbarMain\">\n"; echo " <ul class=\"navbar-nav\">\n"; $menuitems = array(); /* calendar {{{ */ if ($this->params['enablecalendar'] && $accessobject->check_view_access('Calendar')) $menuitems['calendar'] = array('link'=>$this->params['settings']->_httpRoot.'out/out.Calendar.php?mode='.$this->params['calendardefaultview'], 'label'=>getMLText("calendar")); if ($this->params['user']->isAdmin()) $menuitems['admintools'] = array('link'=>$this->params['settings']->_httpRoot.'out/out.AdminTools.php', 'label'=>getMLText("admin_tools")); if($this->params['enablehelp']) { $tmp = explode('.', basename($_SERVER['SCRIPT_FILENAME'])); $menuitems['help'] = array('link'=>$this->params['settings']->_httpRoot.'out/out.Help.php?context='.$tmp[1], 'label'=>getMLText("help")); } /* }}} End of calendar */ /* Check if hook exists because otherwise callHook() will override $menuitems */ if($this->hasHook('globalNavigationBar')) $menuitems = $this->callHook('globalNavigationBar', $menuitems); foreach($menuitems as $menuitem) { if(!empty($menuitem['children'])) { echo " <li class=\"nav-item dropdown\">\n"; echo " <a class=\"nav-link dropdown-toggle\" data-toggle=\"dropdown\">".$menuitem['label']."</a>\n"; echo " <div class=\"dropdown-menu dropdown-menu-left\">\n"; foreach($menuitem['children'] as $submenuitem) { echo " <a class=\"dropdown-item\" href=\"".$submenuitem['link']."\"".(isset($submenuitem['target']) ? ' target="'.$submenuitem['target'].'"' : '').">".$submenuitem['label']."</a>\n"; } echo " </div>\n"; } else { echo "<li class=\"nav-item\"><a class=\"nav-link\" href=\"".$menuitem['link']."\"".(isset($menuitem['target']) ? ' target="'.$menuitem['target'].'"' : '').">".$menuitem['label']."</a></li>"; } } echo " </ul>\n"; /* menu tasks {{{ */ if($this->params['enablemenutasks'] && !$this->params['user']->isGuest()) { if($accessobject->check_view_access('Tasks', array('action'=>'menuTasks'))) { echo " <div id=\"menu-tasks\" class=\"ml-auto\">"; echo " <div class=\"ajax\" data-no-spinner=\"true\" data-view=\"Tasks\" data-action=\"menuTasks\"></div>"; echo " </div>"; } } /* }}} End of menu tasks */ /* drop folder dir {{{ */ if($this->params['dropfolderdir'] && $this->params['enabledropfolderlist']) { echo " <div id=\"menu-dropfolder\">"; echo " <div class=\"ajax\" data-no-spinner=\"true\" data-view=\"DropFolderChooser\" data-action=\"menuList\""; $query = 'recursive=1'; if ($folder!=null && is_object($folder) && $folder->isType('folder')) $query .= "&folderid=".$folder->getID(); echo " data-query=\"".$query."\""; echo "></div>"; echo " </div>"; } /* }}} End of drop folder dir */ /* session list {{{ */ if($this->params['enablesessionlist']) { echo " <div id=\"menu-session\">"; echo " <div class=\"ajax\" data-no-spinner=\"true\" data-view=\"Session\" data-action=\"menuSessions\"></div>"; echo " </div>"; } /* }}} End of session list */ /* clipboard {{{ */ if($this->params['enableclipboard']) { echo " <div id=\"menu-clipboard\">"; echo " <div class=\"ajax add-clipboard-area\" data-no-spinner=\"true\" data-view=\"Clipboard\" data-action=\"menuClipboard\" data-query=\"folderid=".($folder != null ? $folder->getID() : 0)."\"></div>"; echo " </div>"; } /* }}} End of clipboard */ /* user profile menu {{{ */ echo " <ul class=\"navbar-nav ml-auto\">\n"; echo " <li class=\"nav-item dropdown\">\n"; echo " <a href=\"#\" class=\"nav-link dropdown-toggle\" data-toggle=\"dropdown\" id=\"navbarMainUser\" aria-haspopup=\"true\" aria-expanded=\"false\">".($this->params['session']->getSu() ? getMLText("switched_to") : getMLText("signed_in_as"))." '".htmlspecialchars($this->params['user']->getFullName())."'</a>\n"; echo " <div class=\"dropdown-menu dropdown-menu-right\" aria-labelledby=\"navbarMainUser\">\n"; if (!$this->params['user']->isGuest()) { $menuitems = array(); if ($accessobject->check_view_access('Dashboard')) $menuitems['dashboard'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Dashboard.php", 'label'=>getMLText('dashboard')); if ($accessobject->check_view_access('MyDocuments')) $menuitems['my_documents'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MyDocuments.php?inProcess=1", 'label'=>getMLText('my_documents')); if ($accessobject->check_view_access('MyAccount')) $menuitems['my_account'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MyAccount.php", 'label'=>getMLText('my_account')); if($this->hasHook('userMenuItems')) $menuitems = $this->callHook('userMenuItems', $menuitems); if($menuitems) { foreach($menuitems as $menuitem) { echo " <a class=\"dropdown-item\" href=\"".$menuitem['link']."\">".$menuitem['label']."</a>\n"; } echo " <div class=\"dropdown-divider\"></div>\n"; } } $showdivider = false; if($this->params['enablelanguageselector']) { $showdivider = true; echo " <div class=\"dropdown-submenu\">\n"; echo " <a href=\"#\" class=\"dropdown-item dropdown-toggle\" data-toggle=\"dropdown\">".getMLText("language")."</a>\n"; echo " <div class=\"dropdown-menu dropdown-submenu-left\">\n"; $languages = getLanguages(); foreach ($languages as $currLang) { if($this->params['session']->getLanguage() == $currLang) echo " <a class=\"dropdown-item active\""; else echo " <a class=\"dropdown-item\""; echo " href=\"".$this->params['settings']->_httpRoot."op/op.SetLanguage.php?lang=".$currLang."&referer=".$_SERVER["REQUEST_URI"]."\">"; echo getMLText($currLang)."</a>\n"; } echo " </div>\n"; echo " </div>\n"; } if(!$this->params['session']->getSu()) { if($this->params['user']->isAdmin()) { $showdivider = true; echo " <a class=\"dropdown-item\" href=\"".$this->params['settings']->_httpRoot."out/out.SubstituteUser.php\">".getMLText("substitute_user")."</a>\n"; } } if($showdivider) echo " <div class=\"dropdown-divider\"></div>\n"; if($this->params['session']->getSu()) { echo " <a class=\"dropdown-item\" href=\"".$this->params['settings']->_httpRoot."op/op.ResetSu.php\">".getMLText("sign_out_user")."</a>\n"; } else { echo " <a class=\"dropdown-item\" href=\"".$this->params['settings']->_httpRoot."op/op.Logout.php\">".getMLText("sign_out")."</a>\n"; } echo " </div>\n"; echo " </li>\n"; echo " </ul>\n"; /* }}} End of user profile menu */ echo " </div>\n"; } // echo " </div>\n"; // echo " </div>\n"; echo "</nav>\n"; return; } /* }}} */ function getFolderPathHTML($folder, $tagAll=false, $document=null) { /* {{{ */ $path = $folder->getPath(); $txtpath = ""; for ($i = 0; $i < count($path); $i++) { $txtpath .= "<li class=\"breadcrumb-item\">"; if ($i+1 < count($path)) { $txtpath .= "<a href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=".$path[$i]->getID()."&showtree=".showtree()."\" data-droptarget=\"folder_".$path[$i]->getID()."\" rel=\"folder_".$path[$i]->getID()."\" data-name=\"".htmlspecialchars($path[$i]->getName())."\" class=\"table-row-folder droptarget\" data-uploadformtoken=\"".createFormKey('')."\" formtoken=\"".createFormKey('')."\">". htmlspecialchars($path[$i]->getName())."</a>"; } else { $txtpath .= ($tagAll ? "<a href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=".$path[$i]->getID()."&showtree=".showtree()."\" data-droptarget=\"folder_".$path[$i]->getID()."\" rel=\"folder_".$path[$i]->getID()."\" data-name=\"".htmlspecialchars($path[$i]->getName())."\" class=\"table-row-folder droptarget\" data-uploadformtoken=\"".createFormKey('')."\" formtoken=\"".createFormKey('')."\">".htmlspecialchars($path[$i]->getName())."</a>" : htmlspecialchars($path[$i]->getName())); } } if($document) $txtpath .= "<li class=\"breadcrumb-item active table-row-document\" aria-current=\"page\"><a href=\"".$this->params['settings']->_httpRoot."out/out.ViewDocument.php?documentid=".$document->getId()."\" class=\"table-document-row\" rel=\"document_".$document->getId()."\" data-name=\"".htmlspecialchars($document->getName())."\" formtoken=\"".createFormKey('')."\">".htmlspecialchars($document->getName())."</a></li>"; return '<nav aria-label="breadcrumb"><ol class="breadcrumb">'.$txtpath.'</ol></nav>'; } /* }}} */ function pageNavigation($pageTitle, $pageType=null, $extra=null) { /* {{{ */ if ($pageType!=null && strcasecmp($pageType, "noNav")) { // echo "<div class=\"fixed-top\" style=\"z-index: 1029; margin-top: 51px;\">"; echo "<nav class=\"navbar navbar-expand-lg mb-4 bg-light navbar-light\">\n"; echo '<a class="navbar-brand">'.getMLText('nav_brand_'.$pageType).'</a>'; echo "<button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarPageContent\" aria-controls=\"navbarMain\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\n"; echo " <span class=\"navbar-toggler-icon\"></span>\n"; echo "</button>\n"; echo "<div class=\"collapse navbar-collapse\" id=\"navbarPageContent\">\n"; switch ($pageType) { case "view_folder": $this->folderNavigationBar($extra); break; case "view_document": $this->documentNavigationBar($extra); break; case "my_documents": $this->myDocumentsNavigationBar(); break; case "my_account": $this->accountNavigationBar(); break; case "admin_tools": $this->adminToolsNavigationBar(); break; case "calendarold"; $this->calendarOldNavigationBar($extra); break; case "calendar"; $this->calendarNavigationBar($extra); break; default: if($this->hasHook('pageNavigationBar')) { $menubar = $this->callHook('pageNavigationBar', $pageType, $extra); if(is_string($menubar)) echo $menubar; } } echo " </div>\n"; echo "</nav>\n"; if($pageType == "view_folder" || $pageType == "view_document") echo $pageTitle."\n"; // echo "</div>"; } else { echo "<legend>".$pageTitle."</legend>\n"; } return; } /* }}} */ protected function showNavigationBar($menuitems, $options=array()) { /* {{{ */ $content = ''; $content .= "<ul".(isset($options['id']) ? ' id="'.$options['id'].'"' : '')." class=\"navbar-nav".(isset($options['right']) ? ' ml-auto' : '')."\">\n"; foreach($menuitems as $menuitem) { if(!empty($menuitem['children'])) { $content .= " <li class=\"nav-item dropdown\">\n"; $content .= " <a href=\"#\" class=\"nav-link dropdown-toggle\" data-toggle=\"dropdown\">".$menuitem['label']."</a>\n"; $content .= " <div class=\"dropdown-menu\">\n"; foreach($menuitem['children'] as $submenuitem) { if(!empty($submenuitem['children'])) { $content .= " <div class=\"dropdown-submenu\">\n"; $content .= " <a href=\"#\" class=\"dropdown-item dropdown-toggle\" data-toggle=\"dropdown\">".$submenuitem['label']."</a>\n"; $content .= " <div class=\"dropdown-menu dropdown-submenu-left\">\n"; foreach($submenuitem['children'] as $subsubmenuitem) { if(!empty($submenuitem['divider'])) { $content .= " <div class=\"dropdown-divider\"></div>\n"; } else { $content .= " <a href=\"".$subsubmenuitem['link']."\" class=\"dropdown-item".(isset($subsubmenuitem['class']) ? " ".$subsubmenuitem['class'] : "")."\"".(isset($subsubmenuitem['rel']) ? " rel=\"".$subsubmenuitem['rel']."\"" : ""); if(!empty($subsubmenuitem['attributes'])) foreach($subsubmenuitem['attributes'] as $attr) $content .= ' '.$attr[0].'="'.$attr[1].'"'; $content .= ">".$subsubmenuitem['label']."</a>"; } } $content .= " </div>\n"; $content .= " </div>\n"; } else { if(!empty($submenuitem['divider'])) { $content .= " <div class=\"dropdown-divider\"></div>\n"; } else { $content .= " <a class=\"dropdown-item".(isset($submenuitem['class']) ? " ".$submenuitem['class'] : "")."\"".(isset($submenuitem['link']) ? " href=\"".$submenuitem['link']."\"" : "").(isset($submenuitem['target']) ? ' target="'.$submenuitem['target'].'"' : ''); if(!empty($submenuitem['attributes'])) foreach($submenuitem['attributes'] as $attr) $content .= ' '.$attr[0].'="'.$attr[1].'"'; $content .= ">".$submenuitem['label']."</a>\n"; } } } $content .= " </div>\n"; } else { if(!empty($menuitem['divider'])) { $content .= " <div class=\"dropdown-divider\"></div>\n"; } else { $content .= " <li class=\"nav-item\">\n"; $content .= "<a class=\"nav-link".(isset($menuitem['class']) ? " ".$menuitem['class'] : "")."\"".(isset($menuitem['link']) ? " href=\"".$menuitem['link']."\"" : "").(isset($menuitem['target']) ? ' target="'.$menuitem['target'].'"' : ''); if(!empty($menuitem['attributes'])) foreach($menuitem['attributes'] as $attr) $content .= ' '.$attr[0].'="'.$attr[1].'"'; $content .= ">".$menuitem['label']."</a>"; $content .= "</li>"; } } } $content .= "</ul>\n"; echo $content; } /* }}} */ protected function showNavigationListWithBadges($menuitems, $options=array()) { /* {{{ */ $content = ''; $content .= "<ul".(isset($options['id']) ? ' id="'.$options['id'].'"' : '')." class=\"list-group sidenav\">\n"; foreach($menuitems as $menuitem) { $content .= " <li class=\"list-group-item d-flex justify-content-between align-items-center".(!empty($menuitem['active']) ? ' active' : '')."\">\n"; $content .= ' <a'; $content .= !empty($menuitem['link']) ? ' href="'.$menuitem['link'].'"' : ''; if(!empty($menuitem['attributes'])) foreach($menuitem['attributes'] as $attr) $content .= ' '.$attr[0].'="'.$attr[1].'"'; $content .= '>'; $content .= $menuitem['label']; $content .= ' </a>'."\n"; if(!empty($menuitem['badge'])) $content .= '<span class="badge badge-primary badge-pill">'.$menuitem['badge']."</span>"; $content .= " </li>\n"; } $content .= "</ul>\n"; echo $content; } /* }}} */ protected function showButtonwithMenu($button, $options=array()) { /* {{{ */ $content = ''; $content .= ' <div class="btn-group" role="group"> <div class="btn-group" role="group"> <button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" href="#"> '.$button['label'].' </button> '; if($button['menuitems']) { $content .= ' <div class="dropdown-menu"> '; foreach($button['menuitems'] as $menuitem) { $content .= ' <a class="dropdown-item" href="'.$menuitem['link'].'">'.$menuitem['label'].'</a> '; } $content .= ' </div> '; } $content .= ' </div> '; echo $content; } /* }}} */ protected function showPaneHeader($name, $title, $isactive) { /* {{{ */ echo '<li class="nav-item '.($isactive ? 'active' : '').'"><a class="nav-link '.($isactive ? 'active' : '').'" data-target="#'.$name.'" data-toggle="tab" role="button">'.$title.'</a></li>'."\n"; } /* }}} */ protected function showStartPaneContent($name, $isactive) { /* {{{ */ echo '<div class="tab-pane'.($isactive ? ' active' : '').'" id="'.$name.'" role="tabpanel">'; } /* }}} */ protected function showEndPaneContent($name, $currentab) { /* {{{ */ echo '</div>'; } /* }}} */ private function folderNavigationBar($folder) { /* {{{ */ $dms = $this->params['dms']; $enableClipboard = $this->params['enableclipboard']; $accessobject = $this->params['accessobject']; if (!is_object($folder) || !$folder->isType('folder')) { self::showNavigationBar(array()); return; } $accessMode = $folder->getAccessMode($this->params['user']); $folderID = $folder->getID(); $menuitems = array(); if ($accessMode == M_READ && !$this->params['user']->isGuest()) { if ($accessobject->check_view_access('FolderNotify')) $menuitems['edit_folder_notify'] = array('link'=>$this->params['settings']->_httpRoot."out/out.FolderNotify.php?folderid=".$folderID."&showtree=".showtree(), 'label'=>getMLText('edit_folder_notify')); } else if ($accessMode >= M_READWRITE) { if ($accessobject->check_view_access('AddSubFolder')) $menuitems['add_subfolder'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AddSubFolder.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('add_subfolder')); if ($accessobject->check_view_access('AddDocument')) $menuitems['add_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AddDocument.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('add_document')); if(0 && $this->params['enablelargefileupload']) $menuitems['add_multiple_documents'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AddMultiDocument.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('add_multiple_documents')); $menuitems['edit_folder_props'] = array('link'=>$this->params['settings']->_httpRoot."out/out.EditFolder.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('edit_folder_props')); if ($folderID != $this->params['rootfolderid'] && $folder->getParent()) $menuitems['move_folder'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MoveFolder.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('move_folder')); if ($accessMode == M_ALL) { if ($folderID != $this->params['rootfolderid'] && $folder->getParent()) if ($accessobject->check_view_access('RemoveFolder')) $menuitems['rm_folder'] = array('link'=>$this->params['settings']->_httpRoot."out/out.RemoveFolder.php?folderid=". $folderID ."&showtree=".showtree(), 'label'=>getMLText('rm_folder')); } if ($accessMode == M_ALL) { if ($accessobject->check_view_access('FolderAccess')) $menuitems['edit_folder_access'] = array('link'=>$this->params['settings']->_httpRoot."out/out.FolderAccess.php?folderid=".$folderID."&showtree=".showtree(), 'label'=>getMLText('edit_folder_access')); } if ($accessobject->check_view_access('FolderNotify')) $menuitems['edit_folder_notify'] = array('link'=>$this->params['settings']->_httpRoot."out/out.FolderNotify.php?folderid=". $folderID ."&showtree=". showtree(), 'label'=>getMLText('edit_folder_notify')); } if($enableClipboard) { $menuitems['add_to_clipboard'] = array('class'=>'addtoclipboard', 'attributes'=>array(['rel', 'F'.$folder->getId()], ['msg', getMLText('splash_added_to_clipboard')], ['title', getMLText("add_to_clipboard")]), 'label'=>getMLText("add_to_clipboard")); } if ($this->params['user']->isAdmin() && $this->params['enablefullsearch']) { $menuitems['index_folder'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Indexer.php?folderid=". $folderID."&showtree=".showtree(), 'label'=>getMLText('index_folder')); } /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'folderNavigationBar')) { $menuitems = $hookObj->folderNavigationBar($this, $folder, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ private function documentNavigationBar($document) { /* {{{ */ $accessobject = $this->params['accessobject']; $enableClipboard = $this->params['enableclipboard']; $accessMode = $document->getAccessMode($this->params['user']); $docid=".php?documentid=" . $document->getID(); $menuitems = array(); if ($accessMode >= M_READWRITE) { if (!$document->isLocked()) { if($accessobject->check_controller_access('UpdateDocument')) $menuitems['update_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UpdateDocument".$docid, 'label'=>getMLText('update_document')); if($accessobject->check_controller_access('LockDocument')) $menuitems['lock_document'] = array('link'=>$this->params['settings']->_httpRoot."op/op.LockDocument".$docid."&formtoken=".createFormKey('lockdocument'), 'label'=>getMLText('lock_document')); if($accessobject->check_controller_access('EditDocument')) $menuitems['edit_document_props'] = array('link'=>$this->params['settings']->_httpRoot."out/out.EditDocument".$docid , 'label'=>getMLText('edit_document_props')); $menuitems['move_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MoveDocument".$docid, 'label'=>getMLText('move_document')); } else { $lockingUser = $document->getLockingUser(); if (($lockingUser->getID() == $this->params['user']->getID()) || ($document->getAccessMode($this->params['user']) == M_ALL)) { if($accessobject->check_controller_access('UpdateDocument')) $menuitems['update_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UpdateDocument".$docid, 'label'=>getMLText('update_document')); if($accessobject->check_controller_access('UnlockDocument')) $menuitems['unlock_document'] = array('link'=>$this->params['settings']->_httpRoot."op/op.UnlockDocument".$docid."&formtoken=".createFormKey('unlockdocument'), 'label'=>getMLText('unlock_document')); if($accessobject->check_controller_access('EditDocument')) $menuitems['edit_document_props'] = array('link'=>$this->params['settings']->_httpRoot."out/out.EditDocument".$docid, 'label'=>getMLText('edit_document_props')); $menuitems['move_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MoveDocument".$docid, 'label'=>getMLText('move_document')); } } if($accessobject->maySetExpires()) { if ($accessobject->check_view_access('SetExpires')) $menuitems['expires'] = array('link'=>$this->params['settings']->_httpRoot."out/out.SetExpires".$docid, 'label'=>getMLText('expires')); } } if ($document->getAccessMode($this->params['user'], 'removeDocument') == M_ALL) { if ($accessobject->check_view_access('RemoveDocument')) $menuitems['rm_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.RemoveDocument".$docid, 'label'=>getMLText('rm_document')); } if($accessMode == M_ALL) { if ($accessobject->check_view_access('DocumentAccess')) $menuitems['edit_document_access'] = array('link'=>$this->params['settings']->_httpRoot."out/out.DocumentAccess". $docid, 'label'=>getMLText('edit_document_access')); } if ($accessMode >= M_READ && !$this->params['user']->isGuest()) { if ($accessobject->check_view_access('DocumentNotify')) $menuitems['edit_document_notify'] = array('link'=>$this->params['settings']->_httpRoot."out/out.DocumentNotify". $docid, 'label'=>getMLText('edit_document_notify')); } if($enableClipboard) { $menuitems['add_to_clipboard'] = array('class'=>'addtoclipboard', 'attributes'=>array(['rel', 'D'.$document->getId()], ['msg', getMLText('splash_added_to_clipboard')], ['title', getMLText("add_to_clipboard")]), 'label'=>getMLText("add_to_clipboard")); } if ($accessobject->check_view_access('TransferDocument')) { $menuitems['transfer_document'] = array('link'=>$this->params['settings']->_httpRoot."out/out.TransferDocument". $docid, 'label'=>getMLText('transfer_document')); } /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'documentNavigationBar')) { $menuitems = $hookObj->documentNavigationBar($this, $document, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ private function accountNavigationBar() { /* {{{ */ $accessobject = $this->params['accessobject']; $menuitems = array(); if ($this->params['user']->isAdmin() || !$this->params['disableselfedit']) $menuitems['edit_user_details'] = array('link'=>$this->params['settings']->_httpRoot."out/out.EditUserData.php", 'label'=>getMLText('edit_user_details')); if (!$this->params['user']->isAdmin()) $menuitems['edit_default_keywords'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UserDefaultKeywords.php", 'label'=>getMLText('edit_default_keywords')); if ($accessobject->check_view_access('ManageNotify')) $menuitems['edit_notify'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ManageNotify.php", 'label'=>getMLText('edit_existing_notify')); if ($this->params['enableusersview']){ if ($accessobject->check_view_access('UsrView')) $menuitems['users'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UsrView.php", 'label'=>getMLText('users')); if ($accessobject->check_view_access('GroupView')) $menuitems['groups'] = array('link'=>$this->params['settings']->_httpRoot."out/out.GroupView.php", 'label'=>getMLText('groups')); } /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'accountNavigationBar')) { $menuitems = $hookObj->accountNavigationBar($this, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ private function myDocumentsNavigationBar() { /* {{{ */ $accessobject = $this->params['accessobject']; $menuitems = array(); if ($accessobject->check_view_access('MyDocuments')) { $menuitems['inprocess'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MyDocuments.php?inProcess=1", 'label'=>getMLText('documents_in_process')); $menuitems['all_documents'] = array('link'=>$this->params['settings']->_httpRoot."out/out.MyDocuments.php", 'label'=>getMLText('all_documents')); } if($this->params['workflowmode'] == 'traditional' || $this->params['workflowmode'] == 'traditional_only_approval') { if ($accessobject->check_view_access('ReviewSummary')) $menuitems['review_summary'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ReviewSummary.php", 'label'=>getMLText('review_summary')); if ($accessobject->check_view_access('ApprovalSummary')) $menuitems['approval_summary'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ApprovalSummary.php", 'label'=>getMLText('approval_summary')); } else { if ($accessobject->check_view_access('WorkflowSummary')) $menuitems['workflow_summary'] = array('link'=>$this->params['settings']->_httpRoot."out/out.WorkflowSummary.php", 'label'=>getMLText('workflow_summary')); } /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'mydocumentsNavigationBar')) { $menuitems = $hookObj->mydocumentsNavigationBar($this, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ private function adminToolsNavigationBar() { /* {{{ */ $accessobject = $this->params['accessobject']; $settings = $this->params['settings']; $menuitems = array(); if($accessobject->check_view_access(array('UsrMgr', 'GroupMgr', 'UserList'))) { $menuitems['user_group_management'] = array('link'=>"#", 'label'=>getMLText('user_group_management')); if ($accessobject->check_view_access('UsrMgr')) $menuitems['user_group_management']['children']['user_management'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UsrMgr.php", 'label'=>getMLText('user_management')); if ($accessobject->check_view_access('GroupMgr')) $menuitems['user_group_management']['children']['group_management'] = array('link'=>$this->params['settings']->_httpRoot."out/out.GroupMgr.php", 'label'=>getMLText('group_management')); if ($accessobject->check_view_access('UserList')) $menuitems['user_group_management']['children']['user_list'] = array('link'=>$this->params['settings']->_httpRoot."out/out.UserList.php", 'label'=>getMLText('user_list')); } if($accessobject->check_view_access(array('DefaultKeywords', 'Categories', 'AttributeMgr', 'WorkflowMgr', 'WorkflowStatesMgr', 'WorkflowActionsMgr'))) { $menuitems['definitions'] = array('link'=>"#", 'label'=>getMLText('definitions')); if ($accessobject->check_view_access('DefaultKeywords')) $menuitems['definitions']['children']['default_keywords'] = array('link'=>$this->params['settings']->_httpRoot."out/out.DefaultKeywords.php", 'label'=>getMLText('global_default_keywords')); if ($accessobject->check_view_access('Categories')) $menuitems['definitions']['children']['document_categories'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Categories.php", 'label'=>getMLText('global_document_categories')); if ($accessobject->check_view_access('AttributeMgr')) $menuitems['definitions']['children']['attribute_definitions'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AttributeMgr.php", 'label'=>getMLText('global_attributedefinitions')); if($this->params['workflowmode'] == 'advanced') { if ($accessobject->check_view_access('WorkflowMgr')) $menuitems['definitions']['children']['workflows'] = array('link'=>$this->params['settings']->_httpRoot."out/out.WorkflowMgr.php", 'label'=>getMLText('global_workflows')); if ($accessobject->check_view_access('WorkflowStatesMgr')) $menuitems['definitions']['children']['workflow_states'] = array('link'=>$this->params['settings']->_httpRoot."out/out.WorkflowStatesMgr.php", 'label'=>getMLText('global_workflow_states')); if ($accessobject->check_view_access('WorkflowActionsMgr')) $menuitems['definitions']['children']['workflow_actions'] = array('link'=>$this->params['settings']->_httpRoot."out/out.WorkflowActionsMgr.php", 'label'=>getMLText('global_workflow_actions')); } } if($this->params['enablefullsearch']) { if($accessobject->check_view_access(array('Indexer', 'CreateIndex', 'IndexInfo'))) { $menuitems['fulltext'] = array('link'=>"#", 'label'=>getMLText('fullsearch')); if ($accessobject->check_view_access('Indexer')) $menuitems['fulltext']['children']['update_fulltext_index'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Indexer.php", 'label'=>getMLText('update_fulltext_index')); if ($accessobject->check_view_access('CreateIndex')) $menuitems['fulltext']['children']['create_fulltext_index'] = array('link'=>$this->params['settings']->_httpRoot."out/out.CreateIndex.php", 'label'=>getMLText('create_fulltext_index')); if ($accessobject->check_view_access('IndexInfo')) $menuitems['fulltext']['children']['fulltext_info'] = array('link'=>$this->params['settings']->_httpRoot."out/out.IndexInfo.php", 'label'=>getMLText('fulltext_info')); } } if($accessobject->check_view_access(array('BackupTools', 'LogManagement'))) { $menuitems['backup_log_management'] = array('link'=>"#", 'label'=>getMLText('backup_log_management')); if ($accessobject->check_view_access('BackupTools')) $menuitems['backup_log_management']['children'][] = array('link'=>$this->params['settings']->_httpRoot."out/out.BackupTools.php", 'label'=>getMLText('backup_tools')); if ($this->params['logfileenable']) if ($accessobject->check_view_access('LogManagement')) $menuitems['backup_log_management']['children'][] = array('link'=>$this->params['settings']->_httpRoot."out/out.LogManagement.php", 'label'=>getMLText('log_management')); } if($accessobject->check_view_access(array('ImportFS', 'ImportUsers', 'Statistic', 'Charts', 'Timeline', 'ObjectCheck', 'ExtensionMgr', 'Info'))) { $menuitems['misc'] = array('link'=>"#", 'label'=>getMLText('misc')); if ($accessobject->check_view_access('ImportFS')) $menuitems['misc']['children']['import_fs'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ImportFS.php", 'label'=>getMLText('import_fs')); if ($accessobject->check_view_access('ImportUsers')) $menuitems['misc']['children']['import_users'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ImportUsers.php", 'label'=>getMLText('import_users')); if ($accessobject->check_view_access('Statistic')) $menuitems['misc']['children']['folders_and_documents_statistic'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Statistic.php", 'label'=>getMLText('folders_and_documents_statistic')); if ($accessobject->check_view_access('Charts')) $menuitems['misc']['children']['charts'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Charts.php", 'label'=>getMLText('charts')); if ($accessobject->check_view_access('Timeline')) $menuitems['misc']['children']['timeline'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Timeline.php", 'label'=>getMLText('timeline')); if ($accessobject->check_view_access('ObjectCheck')) $menuitems['misc']['children']['objectcheck'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ObjectCheck.php", 'label'=>getMLText('objectcheck')); if ($accessobject->check_view_access('ExpiredDocuments')) $menuitems['misc']['children']['documents_expired'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ExpiredDocuments.php", 'label'=>getMLText('documents_expired')); if ($accessobject->check_view_access('ExtensionMgr')) $menuitems['misc']['children']['extension_manager'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ExtensionMgr.php", 'label'=>getMLText('extension_manager')); if ($accessobject->check_view_access('ClearCache')) $menuitems['misc']['children']['clear_cache'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ClearCache.php", 'label'=>getMLText('clear_cache')); if ($accessobject->check_view_access('Info')) $menuitems['misc']['children']['version_info'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Info.php", 'label'=>getMLText('version_info')); } if ($settings->_enableDebugMode) { if($accessobject->check_view_access(array('Hooks', 'NotificationServices'))) { $menuitems['debug'] = array('link'=>"#", 'label'=>getMLText('debug')); if ($accessobject->check_view_access('Hooks')) $menuitems['debug']['children']['hooks'] = array('link'=>$this->params['settings']->_httpRoot."out/out.Hooks.php", 'label'=>getMLText('list_hooks')); if ($accessobject->check_view_access('NotificationServices')) $menuitems['debug']['children']['notification_services'] = array('link'=>$this->params['settings']->_httpRoot."out/out.NotificationServices.php", 'label'=>getMLText('list_notification_services')); if ($accessobject->check_view_access('SendNotification')) $menuitems['debug']['children']['send_notification'] = array('link'=>$this->params['settings']->_httpRoot."out/out.SendNotification.php", 'label'=>getMLText('send_notification')); if ($accessobject->check_view_access('ConversionServices')) $menuitems['debug']['children']['conversion_services'] = array('link'=>$this->params['settings']->_httpRoot."out/out.ConversionServices.php", 'label'=>getMLText('list_conversion_services')); } } /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'admintoolsNavigationBar')) { $menuitems = $hookObj->admintoolsNavigationBar($this, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ private function calendarOldNavigationBar($d){ /* {{{ */ $accessobject = $this->params['accessobject']; $ds="&day=".$d[0]."&month=".$d[1]."&year=".$d[2]; echo "<id=\"first\"><a href=\"".$this->params['settings']->_httpRoot."out/out.CalendarOld.php?mode=y\" class=\"brand\">".getMLText("calendar")."</a>\n"; echo "<div class=\"nav-collapse col2\">\n"; echo "<ul class=\"nav\">\n"; echo "<li><a href=\"".$this->params['settings']->_httpRoot."out/out.CalendarOld.php?mode=w".$ds."\">".getMLText("week_view")."</a></li>\n"; echo "<li><a href=\"".$this->params['settings']->_httpRoot."out/out.CalendarOld.php?mode=m".$ds."\">".getMLText("month_view")."</a></li>\n"; echo "<li><a href=\"".$this->params['settings']->_httpRoot."out/out.CalendarOld.php?mode=y".$ds."\">".getMLText("year_view")."</a></li>\n"; if (!$this->params['user']->isGuest()) echo "<li><a href=\"".$this->params['settings']->_httpRoot."out/out.AddEvent.php\">".getMLText("add_event")."</a></li>\n"; echo "</ul>\n"; echo "</div>\n"; return; } /* }}} */ private function calendarNavigationBar($d){ /* {{{ */ $accessobject = $this->params['accessobject']; $menuitems = array(); if (!$this->params['user']->isGuest()) $menuitems['addevent'] = array('link'=>$this->params['settings']->_httpRoot."out/out.AddEvent.php", 'label'=>getMLText('add_event')); /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'calendarNavigationBar')) { $menuitems = $hookObj->calendarNavigationBar($this, $menuitems); } } self::showNavigationBar($menuitems); } /* }}} */ function pageList($pageNumber, $totalPages, $baseURI, $params, $dataparams=[]) { /* {{{ */ $maxpages = 25; // skip pages when more than this is shown $range = 2; // pages left and right of current page if (!is_numeric($pageNumber) || !is_numeric($totalPages) || $totalPages<2) { return; } // Construct the basic URI based on the $_GET array. One could use a // regular expression to strip out the pg (page number) variable to // achieve the same effect. This seems to be less haphazard though... $resultsURI = $baseURI; unset($params['pg']); $first=true; if($params) { $resultsURI .= '?'.http_build_query($params); $first=false; } $datastr = ''; if($dataparams) { $datastr .= ' '; foreach($dataparams as $k=>$v) $datastr .= 'data-'.$k.'="'.$v.'"'; } echo "<nav aria-label=\"pagination\">"; echo "<ul class=\"pagination pagination-sm\">"; if($totalPages <= $maxpages) { for ($i = 1; $i <= $totalPages; $i++) { echo "<li class=\"page-item".($i == $pageNumber ? ' active' : "" )."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=".$i."\" data-page=\"".$i."\"".$datastr.">".$i."</a></li>"; } } else { if($pageNumber-$range > 1) $start = $pageNumber-$range; else $start = 2; if($pageNumber+$range < $totalPages) $end = $pageNumber+$range; else $end = $totalPages-1; /* Move start or end to always show 2*$range items */ $diff = $end-$start-2*$range; if($diff < 0) { if($start > 2) $start += $diff; if($end < $totalPages-1) $end -= $diff; } // if($pageNumber > 1) echo "<li class=\"page-item".($pageNumber == 1 ? " disabled" : "")."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=".($pageNumber-1)."\" data-page=\"".($pageNumber-1)."\"".$datastr.">«</a></li>"; echo "<li class=\"page-item".(1 == $pageNumber ? ' active' : "" )."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=1\" data-page=\"1\"".$datastr.">1</a></li>"; if($start > 2) echo "<li class=\"page-item disabled\"><a class=\"page-link\">...</a></li>"; for($j=$start; $j<=$end; $j++) echo "<li class=\"page-item".($j == $pageNumber ? ' active' : "" )."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=".$j."\" data-page=\"".$j."\"".$datastr.">".$j."</a></li>"; if($end < $totalPages-1) echo "<li class=\"page-item disabled\"><a class=\"page-link\">...</a></li>"; if($end < $totalPages) echo "<li class=\"page-item".($totalPages == $pageNumber ? ' active' : "" )."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=".$totalPages."\" data-page=\"".$totalPages."\"".$datastr.">".$totalPages."</a></li>"; if($pageNumber < $totalPages) echo "<li class=\"page-item\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=".($pageNumber+1)."\" data-page=\"".($pageNumber+1)."\"".$datastr.">»</a></li>"; } if ($totalPages>1) { echo "<li class=\"page-item".(0 == $pageNumber ? ' active' : "" )."\"><a class=\"page-link\" href=\"".$resultsURI.($first ? "?" : "&")."pg=all\" data-page=\"all\"".$datastr.">".getMLText("all_pages")."</a></li>"; } echo "</ul>"; echo "</nav>"; return; } /* }}} */ function contentContainer($content) { /* {{{ */ echo "<div class=\"border\">\n"; echo $content; echo "</div>\n"; return; } /* }}} */ function contentContainerStart($class='', $id='') { /* {{{ */ echo "<div class=\"p-3 _border mb-4 bg-light _rounded".($class ? " ".$class : "")."\"".($id ? " id=\"".$id."\"" : "").">\n"; return; } /* }}} */ function contentContainerEnd() { /* {{{ */ echo "</div>\n"; return; } /* }}} */ function contentHeading($heading, $noescape=false) { /* {{{ */ if($noescape) echo "<legend class=\"border-bottom\">".$heading."</legend>\n"; else echo "<legend class=\"border-bottom\">".htmlspecialchars($heading)."</legend>\n"; return; } /* }}} */ function contentSubHeading($heading, $first=false) { /* {{{ */ // echo "<div class=\"contentSubHeading\"".($first ? " id=\"first\"" : "").">".htmlspecialchars($heading)."</div>\n"; echo "<h5>".$heading."</h5>"; return; } /* }}} */ function rowStart() { /* {{{ */ echo "<div class=\"row\">\n"; return; } /* }}} */ function rowEnd() { /* {{{ */ echo "</div>\n"; return; } /* }}} */ function columnStart($width=6) { /* {{{ */ echo "<div class=\"col-lg-".$width." col-sm-12\">\n"; return; } /* }}} */ function columnEnd() { /* {{{ */ echo "</div>\n"; return; } /* }}} */ function formField($title, $value, $params=array()) { /* {{{ */ if($title !== null) { echo "<div class=\"form-group row\">"; echo " <label class=\"col-sm-4 col-lg-4 pt-0 col-form-label\"".(!empty($params['help']) ? " title=\"".$params['help']."\" style=\"cursor: help;\"" : "").(!empty($value['id']) ? ' for="'.$value['id'].'"' : '').">".$title.":</label>"; echo " <div class=\"col-sm-8 col-lg-8\">"; } if(isset($params['field_wrap'][0])) echo $params['field_wrap'][0]; if(is_string($value)) { echo $value; } elseif(is_array($value)) { switch($value['element']) { case 'select': $allowempty = empty($value['allow_empty']) ? false : $value['allow_empty']; echo '<select'. (!empty($value['id']) ? ' id="'.$value['id'].'"' : ''). (!empty($value['name']) ? ' name="'.$value['name'].'"' : ''). (empty($value['class']) ? ' class="form-control"' : ' class="form-control '.$value['class'].'"'). (!empty($value['placeholder']) ? ' data-placeholder="'.$value['placeholder'].'"' : ''). (!empty($value['required']) ? ' required="required"' : ''). ($allowempty ? ' data-allow-clear="true"' : ''). (!empty($value['multiple']) ? ' multiple' : ''); if(!empty($value['attributes']) && is_array($value['attributes'])) foreach($value['attributes'] as $a) echo ' '.$a[0].'="'.$a[1].'"'; echo ">"; if(isset($value['options']) && is_array($value['options'])) { if($allowempty) echo "<option value=\"\"></option>"; foreach($value['options'] as $val) { if(is_string($val)) { echo '<optgroup label="'.$val.'">'; } elseif(is_array($val)) { echo '<option value="'.$val[0].'"'.(!empty($val[2]) ? ' selected' : ''); if(!empty($val[3]) && is_array($val[3])) foreach($val[3] as $a) echo ' '.$a[0].'="'.$a[1].'"'; echo '>'.$val[1].'</option>'; } } } echo '</select>'; break; case 'textarea': echo '<textarea'. (!empty($value['id']) ? ' id="'.$value['id'].'"' : ''). (!empty($value['name']) ? ' name="'.$value['name'].'"' : ''). (empty($value['class']) ? ' class="form-control"' : ' class="form-control '.$value['class'].'"'). (!empty($value['rows']) ? ' rows="'.$value['rows'].'"' : ''). (!empty($value['cols']) ? ' cols="'.$value['cols'].'"' : ''). (!empty($value['placeholder']) ? ' placeholder="'.$value['placeholder'].'"' : ''). (!empty($value['required']) ? ' required="required"' : '').">".(!empty($value['value']) ? $value['value'] : '')."</textarea>"; break; case 'plain': echo $value['value']; break; case 'input': default: switch($value['type']) { case 'checkbox': if(isset($value['default']) && !empty($value['name'])) echo '<input type="hidden" name="'.$value['name'].'" value="'.$value['default'].'" />'; echo '<div class="form-check">'; echo '<input'. (!empty($value['type']) ? ' type="'.$value['type'].'"' : ''). (!empty($value['id']) ? ' id="'.$value['id'].'"' : ''). (!empty($value['name']) ? ' name="'.$value['name'].'"' : ''). (empty($value['class']) ? ' class="form-check-input"' : ' class="form-check-input '.$value['class'].'"'). ((isset($value['value']) && is_string($value['value'])) || !empty($value['value']) ? ' value="'.$value['value'].'"' : ''). (!empty($value['placeholder']) ? ' placeholder="'.$value['placeholder'].'"' : ''). (!empty($value['autocomplete']) ? ' autocomplete="'.$value['autocomplete'].'"' : ''). (!empty($value['checked']) ? ' checked' : ''). (!empty($value['required']) ? ' required="required"' : ''); if(!empty($value['attributes']) && is_array($value['attributes'])) foreach($value['attributes'] as $a) echo ' '.$a[0].'="'.$a[1].'"'; echo ">"; echo '<label class="form-check-label" '.(!empty($value['id']) ?? 'for="'.$value['id'].'"').'>'.(!empty($value['label']) ?? $value['label']).'</label>'; echo "</div>"; break; default: if(!empty($value['addon'])) echo '<div class="input-group date">'; echo '<input'. (!empty($value['type']) ? ' type="'.$value['type'].'"' : ''). (!empty($value['id']) ? ' id="'.$value['id'].'"' : ''). (!empty($value['name']) ? ' name="'.$value['name'].'"' : ''). (empty($value['class']) ? ' class="form-control"' : ' class="form-control '.$value['class'].'"'). ((isset($value['value']) && is_string($value['value'])) || !empty($value['value']) ? ' value="'.$value['value'].'"' : ''). (!empty($value['placeholder']) ? ' placeholder="'.$value['placeholder'].'"' : ''). (!empty($value['autocomplete']) ? ' autocomplete="'.$value['autocomplete'].'"' : ''). (isset($value['min']) ? ' min="'.$value['min'].'"' : ''). (!empty($value['checked']) ? ' checked' : ''). (!empty($value['required']) ? ' required="required"' : ''); if(!empty($value['attributes']) && is_array($value['attributes'])) foreach($value['attributes'] as $a) echo ' '.$a[0].'="'.$a[1].'"'; echo "/>"; if(!empty($value['addon'])) { echo '<div class="input-group-append">'; echo '<span class="input-group-text">'.$value['addon'].'</span>'; echo '</div>'; echo '</div>'; } break; } break; } } if(isset($params['field_wrap'][1])) echo $params['field_wrap'][1]; if($title !== null) { echo "</div>"; echo "</div>"; } return; } /* }}} */ function formSubmit($value, $name='', $target='', $type='primary') { /* {{{ */ switch($type) { case 'danger': $class = 'btn-danger'; break; case 'secondary': $class = 'btn-secondary'; break; case 'neutral': $class = ''; break; case 'primary': default: $class = 'btn-primary'; } // echo "<div class=\"controls\">\n"; if(is_string($value)) { echo "<button type=\"submit\" class=\"btn ".$class."\"".($name ? ' name="'.$name.'" id="'.$name.'"' : '').($target ? ' formtarget="'.$target.'"' : '').">".$value."</button>\n"; } else { if(is_array($value)) { foreach($value as $i=>$v) echo "<button type=\"submit\" class=\"btn ".$class."\"".(!empty($name[$i]) ? ' name="'.$name[$i].'" id="'.$name[$i].'"' : '').(!empty($target[$i]) ? ' formtarget="'.$name[$i].'"' : '').">".$v."</button>\n"; } } // echo "</div>\n"; } /* }}} */ function getMimeIcon($fileType) { /* {{{ */ // for extension use LOWER CASE only $icons = array(); $icons["txt"] = "text-x-preview.svg"; $icons["text"] = "text-x-preview.svg"; $icons["tex"] = "text-x-preview.svg"; $icons["doc"] = "office-document.svg"; $icons["dot"] = "office-document.svg"; $icons["docx"] = "office-document.svg"; $icons["dotx"] = "office-document.svg"; $icons["rtf"] = "office-document.svg"; $icons["xls"] = "office-spreadsheet.svg"; $icons["xlt"] = "office-spreadsheet.svg"; $icons["xlsx"] = "office-spreadsheet.svg"; $icons["xltx"] = "office-spreadsheet.svg"; $icons["ppt"] = "office-presentation.svg"; $icons["pot"] = "office-presentation.svg"; $icons["pptx"] = "office-presentation.svg"; $icons["potx"] = "office-presentation.svg"; $icons["exe"] = "executable.svg"; $icons["html"] = "web.svg"; $icons["htm"] = "web.svg"; $icons["gif"] = "image.svg"; $icons["jpg"] = "image.svg"; $icons["jpeg"] = "image.svg"; $icons["bmp"] = "image.svg"; $icons["png"] = "image.svg"; $icons["tif"] = "image.svg"; $icons["tiff"] = "image.svg"; $icons["log"] = "text-x-preview.svg"; $icons["midi"] = "audio.svg"; $icons["pdf"] = "gnome-mime-application-pdf.svg"; $icons["wav"] = "audio.svg"; $icons["mp3"] = "audio.svg"; $icons["m4a"] = "audio.svg"; $icons["ogg"] = "audio.svg"; $icons["opus"] = "audio.svg"; $icons["c"] = "text-x-preview.svg"; $icons["cpp"] = "text-x-preview.svg"; $icons["h"] = "text-x-preview.svg"; $icons["java"] = "text-x-preview.svg"; $icons["py"] = "text-x-preview.svg"; $icons["tar"] = "package.svg"; $icons["gz"] = "package.svg"; $icons["7z"] = "package.svg"; $icons["bz"] = "package.svg"; $icons["bz2"] = "package.svg"; $icons["tgz"] = "package.svg"; $icons["zip"] = "package.svg"; $icons["rar"] = "package.svg"; $icons["mpg"] = "video.svg"; $icons["mp4"] = "video.svg"; $icons["avi"] = "video.svg"; $icons["webm"] = "video.svg"; $icons["mkv"] = "video.svg"; $icons["ods"] = "office-spreadsheet.svg"; $icons["ots"] = "office-spreadsheet.svg"; $icons["sxc"] = "office-spreadsheet.svg"; $icons["stc"] = "office-spreadsheet.svg"; $icons["odt"] = "office-document.svg"; $icons["ott"] = "office-document.svg"; $icons["sxw"] = "office-document.svg"; $icons["stw"] = "office-document.svg"; $icons["odp"] = "office-presentation.svg"; $icons["otp"] = "office-presentation.svg"; $icons["sxi"] = "office-presentation.svg"; $icons["sti"] = "office-presentation.svg"; $icons["odg"] = "office-drawing.svg"; $icons["otg"] = "office-drawing.svg"; $icons["sxd"] = "office-drawing.svg"; $icons["std"] = "office-drawing.svg"; $icons["odf"] = "ooo_formula.png"; $icons["sxm"] = "ooo_formula.png"; $icons["smf"] = "ooo_formula.png"; $icons["mml"] = "ooo_formula.png"; $icons["folder"] = "folder.svg"; $icons["default"] = "text-x-preview.svg"; //"default.png"; $ext = strtolower(substr($fileType, 1)); if (isset($icons[$ext])) { return $this->imgpath.$icons[$ext]; } else { return $this->imgpath.$icons["default"]; } } /* }}} */ function getOverallStatusIcon($status) { /* {{{ */ if (is_null($status)) { return ''; } else { $icon = ''; $color = ''; switch($status) { case S_IN_WORKFLOW: $icon = 'fa fa-circle in-workflow'; break; case S_DRAFT_REV: $icon = 'fa fa-circle in-workflow'; break; case S_DRAFT_APP: $icon = 'fa fa-circle in-workflow'; break; case S_RELEASED: $icon = 'fa-circle released'; break; case S_REJECTED: $icon = 'fa-circle rejected'; break; case S_OBSOLETE: $icon = 'fa-circle obsolete'; break; case S_EXPIRED: $icon = 'fa-circle expired'; break; default: $icon = 'fa fa-question'; break; } return '<div style="display: inline-block; white-space: nowrap;"><i class="fa '.$icon.'"'.($color ? ' style="color: '.$color.';"' : '').' title="'.getOverallStatusText($status).'"></i> <span class="d-none d-md-inline-block">'.getOverallStatusText($status).'</span></div>'; } } /* }}} */ /** * Get attributes for a button opening a modal box * * @param array $config contains elements * target: id of modal box * remote: URL of data to be loaded into box * @return string */ function getModalBoxLinkAttributes($config) { /* {{{ */ $attrs = array(); $attrs[] = array('data-target', '#'.$config['target']); if(isset($config['remote'])) { $attrs[] = array('href', $config['remote']); $attrs[] = array('data-remote', $config['remote']); } $attrs[] = array('data-toggle', 'modal'); $attrs[] = array('role', 'button'); if(isset($config['class'])) { if($config['class']) $attrs[] = array('class', $config['class']); } else $attrs[] = array('class', 'btn'); return $attrs; } /* }}} */ /** * Get html for button opening a modal box * * @param array $config contains elements * target: id of modal box * remote: URL of data to be loaded into box * title: text on button * @return string */ function getModalBoxLink($config) { /* {{{ */ // $content = ''; // $content .= "<a data-target=\"#".$config['target']."\"".(isset($config['remote']) ? " href=\"".$config['remote']."\"" : "")." role=\"button\" class=\"".(isset($config['class']) ? $config['class'] : "btn btn-secondary")."\" data-toggle=\"modal\""; $attrs = self::getModalBoxLinkAttributes($config); $content = '<a'; if($attrs) { foreach($attrs as $attr) $content .= ' '.$attr[0].'="'.$attr[1].'"'; } if(!empty($config['attributes'])) { foreach($config['attributes'] as $attrname=>$attrval) $content .= ' '.$attrname.'="'.$attrval.'"'; } $content .= ">".$config['title']."</a>\n"; return $content; } /* }}} */ /** * Get html for a modal box with buttons * * @param array $config contains elements * id: id of modal box (must match target of getModalBoxLink()) * title: title of modal box * content: content to be shown in the body of the box. Can be left * empty if the body is loaded from the remote link passed to the button * to open this box. * buttons: array of buttons, each having a title and an optional id * @return string */ function getModalBox($config) { /* {{{ */ $content = ''; $content .= ' <div class="modal fade" id="'.$config['id'].'" tabindex="-1" role="dialog" aria-labelledby="'.$config['id'].'Label" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="modal-header"> <h3 id="'.$config['id'].'Label">'.$config['title'].'</h3> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> </div> <div class="modal-body"> '; if(!empty($config['content'])) $content .= $config['content']; else $content .= '<p>'.getMLText('data_loading').'</p>'; $content .= ' </div> <div class="modal-footer"> '; if($config['buttons']) { foreach($config['buttons'] as $button) $content .= '<button class="btn'.(!empty($button['id']) ? ' btn-primary" id="'.$button['id'].'"': ' btn-secondary" ').' data-dismiss="modal" aria-hidden="true">'.$button['title'].'</button>'; } $content .= ' </div> </div> </div> </div> '; return $content; } /* }}} */ function printFileChooserJs() { /* {{{ */ $maxfilesize = $this->getParam('maxfilesize'); ?> $(document).ready(function() { /* do not use bootstrap4 custom form element because it is difficult to localize $(document).on('change', '.custom-file-input',function(){ //get the file name var fileName = $(this).val().replace(/\\/g, '/').replace(/.*\//, ''); //replace the "Choose a file" label $(this).next('.custom-file-label').html(fileName); }) */ /* Triggered after the file has been selected */ $(document).on('change', '.btn-file :file', function() { var input = $(this), numFiles = input.get(0).files ? input.get(0).files.length : 1, label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); <?php if($maxfilesize): ?> if(input.get(0).files[0].size > <?= $maxfilesize ?>) { noty({ text: "<?= getMLText('uploading_maxsize') ?>", type: 'error', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 1500, }); return; } <?php endif; ?> input.trigger('fileselect', [numFiles, label]); }); $(document).on('fileselect', '.upload-file .btn-file :file', function(event, numFiles, label) { var input = $(this).parents('.input-group').find(':text'), log = numFiles > 1 ? numFiles + ' files selected' : label; if( input.length ) { input.val(log); } else { // if( log ) alert(log); } }); }); <?php } /* }}} */ function getFileChooserHtml($varname='userfile', $multiple=false, $accept='') { /* {{{ */ $id = preg_replace('/[^A-Za-z]/', '', $varname); /* do not use bootstrap4 custom form element because it is difficult to localize $html = ' <div class="custom-file"> <input type="file" class="custom-file-input" id="'.$id.'" name="'.$varname.'"> <label class="custom-file-label" for="'.$id.'">'.getMLText("browse").'…'.'</label> </div> '; return $html; */ $html = ' <div id="'.$id.'-upload-files"> <div id="'.$id.'-upload-file" class="upload-file"> <div class="input-group"> <input type="text" class="form-control fileupload-group" id="kkll'.$id.'" readonly> <div class="input-group-append"> <a class="btn btn-secondary btn-file"> '.getMLText("browse").'… <input id="'.$id.'" type="file" name="'.$varname.'"'.($multiple ? " multiple" : "").($accept ? ' accept="'.$accept.'"' : "").' data-target-highlight="kkll'.$id.'"> </a> </div> </div> </div> </div> '; return $html; } /* }}} */ function printFileChooser($varname='userfile', $multiple=false, $accept='') { /* {{{ */ echo self::getFileChooserHtml($varname, $multiple, $accept); } /* }}} */ function printDateChooser($defDate, $varName, $lang='', $dateformat='', $startdate='', $enddate='', $weekstart=null) { /* {{{ */ echo self::getDateChooser($defDate, $varName, $lang, $dateformat, $startdate, $enddate, $weekstart); } /* }}} */ function getDateChooser($defDate, $varName, $lang='', $dateformat='', $startdate='', $enddate='', $weekstart=null, $placeholder='', $nogroup=false) { /* {{{ */ if(!$dateformat) $dateformat = getConvertDateFormat($this->params['settings']->_dateformat); $content = ''; if(!$nogroup) $content .= '<div class="input-group date" id="'.$varName.'date">'; $content .= '<input type="text" class="form-control datepicker" autocomplete="off" placeholder="'.htmlspecialchars($placeholder).'" name="'.$varName.'" id="'.$varName.'" value="'.$defDate. '" data-date-calendar-weeks="true" '.($weekstart == null ? '' : 'data-date-week-start="'.intval($weekstart).'" ').'data-date="'.$defDate.'" data-selectmenu="presetexpdate" data-date-format="'.$dateformat.'"'.($lang ? 'data-date-language="'.str_replace('_', '-', $lang).'"' : '').($startdate ? ' data-date-start-date="'.$startdate.'"' : '').($enddate ? ' data-date-end-date="'.$enddate.'"' : '').' data-date-autoclose="true" data-provide="datepicker">'; if(!$nogroup) { $content .= '<div class="input-group-append"> <span class="input-group-text"><i class="fa fa-calendar"></i></span> </div>'; $content .= '</div>'; } return $content; } /* }}} */ function __printDateChooser($defDate, $varName) { /* {{{ */ if ($defDate == -1) $defDate = mktime(); $day = date("d", $defDate); $month = date("m", $defDate); $year = date("Y", $defDate); print "<select name=\"" . $varName . "day\">\n"; for ($i = 1; $i <= 31; $i++) { print "<option value=\"" . $i . "\""; if (intval($day) == $i) print " selected"; print ">" . $i . "</option>\n"; } print "</select> \n"; print "<select name=\"" . $varName . "month\">\n"; for ($i = 1; $i <= 12; $i++) { print "<option value=\"" . $i . "\""; if (intval($month) == $i) print " selected"; print ">" . $i . "</option>\n"; } print "</select> \n"; print "<select name=\"" . $varName . "year\">\n"; for ($i = $year-5 ; $i <= $year+5 ; $i++) { print "<option value=\"" . $i . "\""; if (intval($year) == $i) print " selected"; print ">" . $i . "</option>\n"; } print "</select>"; } /* }}} */ function printSequenceChooser($parent, $type, $keepID = -1) { /* {{{ */ echo $this->getSequenceChooser($parent, $type, $keepID); } /* }}} */ /** * Return html code for sequence chooser * * This method will return the html code of the ѕelect menu for setting * the ѕequence number of a document or folder. The select menu will contain * a list of all siblings to select to positon relative to a sibling. * For performance reasons the select menu will not contain any siblings * if the number of siblings is greater than 50. * * @param $parent object parent folder of new or updated document/folder * @param $type string type of new object 'f'=folder, 'd'=document * @param $keepID integer id of current object */ function getSequenceChooser($parent, $type, $keepID = -1) { /* {{{ */ $objArr = []; if($type == 'd') { if(($c = $parent->hasDocuments()) < 200) $objArr = $parent->getDocuments('s'); $minmax = $parent->getDocumentsMinMax(); } elseif($type = 'f') { if(($c = $parent->hasSubFolders()) < 200) $objArr = $parent->getSubFolders('s'); $minmax = $parent->getFoldersMinMax(); } else return ''; if ($objArr) { $min = $minmax['min']-1.0; $max = $minmax['max']+1.0; } else { $min = (float) $minmax['min']; $max = $minmax['max']+1.0; } $content = "<select class=\"form-control chzn-select\" data-allow-clear=\"false\" name=\"sequence\">\n"; if ($keepID != -1) { $content .= " <option value=\"keep\">" . getMLText("seq_keep"); } if($this->params['defaultposition'] != 'start') $content .= " <option value=\"".$max."\">" . getMLText("seq_end"); if ($c > 0) { $content .= " <option value=\"".$min."\">" . getMLText("seq_start"); } if($this->params['defaultposition'] == 'start') $content .= " <option value=\"".$max."\">" . getMLText("seq_end"); for ($i = 0; $i < count($objArr) - 1; $i++) { if (($objArr[$i]->getID() == $keepID) || (($i + 1 < count($objArr)) && ($objArr[$i+1]->getID() == $keepID))) { continue; } $index = ($objArr[$i]->getSequence() + $objArr[$i+1]->getSequence()) / 2; $content .= " <option value=\"".$index."\">" . getMLText("seq_after", array("prevname" => htmlspecialchars($objArr[$i]->getName()))); } $content .= "</select>"; return $content; } /* }}} */ function getDocumentChooserHtml($form, $default=false, $formname='', $skiptree=false) { /* {{{ */ if(!$formname) $formname = "docid"; $formid = md5($formname.$form); $content = ''; $content .= "<input type=\"hidden\" class=\"fileupload-group\" id=\"".$formid."\" name=\"".$formname."\" data-target-highlight=\"choosedocsearch".$formid."\" value=\"". ($default ? $default->getID() : "") ."\">"; $content .= "<div class=\"input-group\">\n"; $content .= "<input class=\"form-control\" type=\"text\" id=\"choosedocsearch".$formid."\" data-target=\"".$formid."\" data-provide=\"typeahead\" name=\"docname".$formid."\"value=\"" . (($default) ? htmlspecialchars($default->getName()) : "") ."\" placeholder=\"".getMLText('type_to_search')."\" autocomplete=\"off\" />"; $content .= '<div class="input-group-append">'; $content .= "<button type=\"button\" class=\"btn btn-secondary\" id=\"cleardocument".$form."\" data-target=\"".$formid."\"><i class=\"fa fa-remove\"></i></button>"; if(!$skiptree) $content .= $this->getModalBoxLink( array( 'target' => 'docChooser'.$formid, 'remote' => $this->params['settings']->_httpRoot."out/out.DocumentChooser.php?form=".$formid."&folderid=".$this->params['dms']->getRootFolder()->getId(), 'class' => 'btn btn-secondary', 'title' => getMLText('document').'…' )); $content .= "</div>\n"; $content .= "</div>\n"; if(!$skiptree) $content .= $this->getModalBox( array( 'id' => 'docChooser'.$formid, 'title' => getMLText('choose_target_document'), 'buttons' => array( array('title'=>getMLText('close')) ) )); return $content; } /* }}} */ function printDocumentChooserHtml($formName) { /* {{{ */ echo self::getDocumentChooserHtml($formName); } /* }}} */ /** * This function is deprecated. Don't use it anymore. There is a generic * folderSelected and documentSelected function in application.js * If you extra functions to be called then define them in your own js code */ function printDocumentChooserJs($form, $formname='') { /* {{{ */ if(!$formname) $formname = "docid"; $formid = md5($formname.$form); ?> function documentSelected<?php echo $formid ?>(id, name) { $('#<?php echo $formid ?>').val(id); $('#choosedocsearch<?php echo $formid ?>').val(name); $('#docChooser<?php echo $formid ?>').modal('hide'); } function folderSelected<?php echo $formid ?>(id, name) { } <?php } /* }}} */ function printDocumentChooser($form) { /* {{{ */ $this->printDocumentChooserHtml($form); ?> <script language="JavaScript"> <?php $this->printDocumentChooserJs($form); ?> </script> <?php } /* }}} */ function getFolderChooserHtml($form, $accessMode, $exclude = -1, $default = false, $formname = '', $skiptree = false) { /* {{{ */ if(!$formname) $formname = "targetid"; $formid = md5($formname.$form); $content = ''; $content .= "<input type=\"hidden\" id=\"".$formid."\" name=\"".$formname."\" value=\"". ($default ? $default->getID() : "") ."\" data-target-highlight=\"choosefoldersearch".$formid."\">"; $content .= "<div class=\"input-group\">\n"; $content .= "<input class=\"form-control\" type=\"text\" id=\"choosefoldersearch".$formid."\" data-target=\"".$formid."\" data-provide=\"typeahead\" name=\"targetname".$formid."\" value=\"". (($default) ? htmlspecialchars($default->getName()) : "") ."\" placeholder=\"".getMLText('type_to_search')."\" autocomplete=\"off\" target=\"".$formid."\"/>"; $content .= '<div class="input-group-append">'; $content .= "<button type=\"button\" class=\"btn btn-secondary\" id=\"clearfolder".$form."\" data-target=\"".$formid."\"><i class=\"fa fa-remove\"></i></button>"; if(!$skiptree) { $content .= $this->getModalBoxLink( array( 'target' => 'folderChooser'.$formid, 'remote' => $this->params['settings']->_httpRoot."out/out.FolderChooser.php?form=".$formid."&mode=".$accessMode."&exclude=".$exclude, 'class' => 'btn btn-secondary', 'title' => getMLText('folder').'…' )); } $content .= "</div>\n"; $content .= "</div>\n"; if(!$skiptree) { $content .= $this->getModalBox( array( 'id' => 'folderChooser'.$formid, 'title' => getMLText('choose_target_folder'), 'buttons' => array( array('title'=>getMLText('close')) ) )); } return $content; } /* }}} */ function printFolderChooserHtml($form, $accessMode, $exclude = -1, $default = false, $formname = '') { /* {{{ */ echo self::getFolderChooserHtml($form, $accessMode, $exclude, $default, $formname); } /* }}} */ /** * This function is deprecated. Don't use it anymore. There is a generic * folderSelected and documentSelected function in application.js * If you extra functions to be called then define them in your own js code */ function printFolderChooserJs($form, $formname='') { /* {{{ */ if(!$formname) $formname = "targetid"; $formid = md5($formname.$form); ?> function folderSelected<?php echo $formid ?>(id, name) { $('#<?php echo $formid ?>').val(id); $('#choosefoldersearch<?php echo $formid ?>').val(name); $('#folderChooser<?php echo $formid ?>').modal('hide'); } /* $(document).ready(function() { $('#clearfolder<?php print $formid ?>').click(function(ev) { $('#choosefoldersearch<?php echo $formid ?>').val(''); $('#<?php echo $formid ?>').val(''); }); }); */ <?php } /* }}} */ function printFolderChooser($form, $accessMode, $exclude = -1, $default = false, $formname='') { /* {{{ */ $this->printFolderChooserHtml($form, $accessMode, $exclude, $default, $formname); ?> <script language="JavaScript"> <?php $this->printFolderChooserJs($form, $formname); ?> </script> <?php } /* }}} */ function printKeywordChooserHtml($formName, $keywords='', $fieldname='keywords') { /* {{{ */ echo self::getKeywordChooserHtml($formName, $keywords, $fieldname); } /* }}} */ function getKeywordChooserHtml($formName, $keywords='', $fieldname='keywords') { /* {{{ */ $strictformcheck = $this->params['strictformcheck']; $content = ''; $content .= ' <div class="input-group"> <input class="form-control" type="text" name="'.$fieldname.'" id="'.$fieldname.'" value="'.htmlspecialchars($keywords).'"'.($strictformcheck ? ' required="required"' : '').' /> <div class="input-group-append">'; $content .= $this->getModalBoxLink( array( 'target' => 'keywordChooser', 'remote' => $this->params['settings']->_httpRoot."out/out.KeywordChooser.php?target=".$formName, 'class' => 'btn btn-secondary', 'title' => getMLText('keywords').'…' )); $content .= ' </div> </div> '; $content .= $this->getModalBox( array( 'id' => 'keywordChooser', 'title' => getMLText('use_default_keywords'), 'buttons' => array( array('id'=>'acceptkeywords', 'title'=>getMLText('save')), array('title'=>getMLText('close')), ) )); return $content; } /* }}} */ function printKeywordChooserJs($formName) { /* {{{ */ ?> $(document).ready(function() { $('#acceptkeywords').click(function(ev) { acceptKeywords(); }); }); <?php } /* }}} */ function printKeywordChooser($formName, $keywords='', $fieldname='keywords') { /* {{{ */ $this->printKeywordChooserHtml($formName, $keywords, $fieldname); ?> <script language="JavaScript"> <?php $this->printKeywordChooserJs($formName); ?> </script> <?php } /* }}} */ /** * Output a single attribute in the document info section * * @param object $attribute attribute */ protected function printAttributeValue($attribute) { /* {{{ */ echo self::getAttributeValue($attribute); } /* }}} */ function getAttributeValue($attribute) { /* {{{ */ $dms = $this->params['dms']; $attrdef = $attribute->getAttributeDefinition(); switch($attrdef->getType()) { case SeedDMS_Core_AttributeDefinition::type_url: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $attr) { $tmp[] = '<a href="'.htmlspecialchars($attr).'">'.htmlspecialchars($attr).'</a>'; } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_email: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $attr) { $tmp[] = '<a mailto="'.htmlspecialchars($attr).'">'.htmlspecialchars($attr).'</a>'; } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_folder: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $targetfolder) { $tmp[] = '<a href="'.$this->params['settings']->_httpRoot.'out/out.ViewFolder.php?folderid='.$targetfolder->getId().'">'.htmlspecialchars($targetfolder->getName()).'</a>'; } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_document: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $targetdoc) { $tmp[] = '<a href="'.$this->params['settings']->_httpRoot.'out/out.ViewDocument.php?documentid='.$targetdoc->getId().'">'.htmlspecialchars($targetdoc->getName()).'</a>'; } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_user: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $curuser) { $tmp[] = htmlspecialchars($curuser->getFullname()." (".$curuser->getLogin().")"); } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_group: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $curgroup) { $tmp[] = htmlspecialchars($curgroup->getName()); } return implode('<br />', $tmp); break; case SeedDMS_Core_AttributeDefinition::type_date: $attrs = $attribute->getValueAsArray(); $tmp = array(); foreach($attrs as $attr) { $tmp[] = getReadableDate($attr); } return implode(', ', $tmp); break; default: return htmlspecialchars(implode(', ', $attribute->getValueAsArray())); } } /* }}} */ function printAttributeEditField($attrdef, $attribute, $fieldname='attributes', $norequire=false, $namepostfix='', $alwaysmultiple=false) { /* {{{ */ echo self::getAttributeEditField($attrdef, $attribute, $fieldname, $norequire, $namepostfix, $alwaysmultiple); } /* }}} */ function getAttributeEditField($attrdef, $attribute, $fieldname='attributes', $norequire=false, $namepostfix='', $alwaysmultiple=false) { /* {{{ */ $dms = $this->params['dms']; $attr_id = $fieldname.'_'.$attrdef->getId().($namepostfix ? '_'.$namepostfix : ''); $attr_name = $fieldname.'['.$attrdef->getId().']'.($namepostfix ? '['.$namepostfix.']' : ''); $content = ''; switch($attrdef->getType()) { case SeedDMS_Core_AttributeDefinition::type_boolean: $objvalue = $attribute ? (is_object($attribute) ? $attribute->getValue() : $attribute) : ''; $content .= "<input type=\"hidden\" name=\"".$attr_name."\" value=\"\" />"; $content .= "<input type=\"checkbox\" id=\"".$attr_id."\" name=\"".$attr_name."\" value=\"1\" ".($objvalue ? 'checked' : '')." />"; $content .= '<label class="form-check-label" for="'.$attr_id.'"></label>'; break; case SeedDMS_Core_AttributeDefinition::type_date: $objvalue = $attribute ? getReadableDate((is_object($attribute) ? $attribute->getValue() : $attribute)) : ''; $dateformat = getConvertDateFormat($this->params['settings']->_dateformat); $content = ' <div class="input-group date"> <input type="text" class="form-control" id="'.$attr_id.'" name="'.$attr_name.'" value="'.($objvalue ? $objvalue : '').'" data-date="'.getReadableDate().'" data-date-format="'.$dateformat.'" data-date-language="'.str_replace('_', '-', $this->params['session']->getLanguage()).'" data-date-autoclose="true" data-provide="datepicker"> <div class="input-group-append"> <span class="input-group-text"><i class="fa fa-calendar"></i></span> </div> </div> '; break; case SeedDMS_Core_AttributeDefinition::type_email: $objvalue = $attribute ? (is_object($attribute) ? $attribute->getValue() : $attribute) : ''; $content .= "<input type=\"text\" class=\"form-control\" id=\"".$attr_id."\" name=\"".$attr_name."\" value=\"".htmlspecialchars($objvalue)."\"".((!$norequire && $attrdef->getMinValues() > 0) ? ' required="required"' : '').' data-rule-email="true"'." />"; break; /* case SeedDMS_Core_AttributeDefinition::type_float: $objvalue = $attribute ? (is_object($attribute) ? $attribute->getValue() : $attribute) : ''; $content .= "<input type=\"text\" class=\"form-control\" id=\"".$attr_id."\" name=\"".$attr_name."\" value=\"".htmlspecialchars($objvalue)."\"".((!$norequire && $attrdef->getMinValues() > 0) ? ' required="required"' : '')." data-rule-number=\"true\"/>"; break; */ case SeedDMS_Core_AttributeDefinition::type_folder: $target = $attribute ? $attribute->getValue() : null; $content .= $this->getFolderChooserHtml("attr".$attrdef->getId(), M_READWRITE, -1, $target, $attr_name, false); break; case SeedDMS_Core_AttributeDefinition::type_document: $target = $attribute ? $attribute->getValue() : null; $content .= $this->getDocumentChooserHtml("attr".$attrdef->getId(), $target, $attr_name); break; case SeedDMS_Core_AttributeDefinition::type_user: $target = $attribute ? $attribute->getValueAsArray() : []; $objvalue = []; foreach($target as $t) $objvalue[] = $t->getId(); $users = $dms->getAllUsers(); if($users) { $allowempty = $attrdef->getMinValues() == 0; $allowmultiple = $attrdef->getMultipleValues() || $alwaysmultiple; $content .= "<select class=\"form-control chzn-select\"".($allowempty ? " data-allow-clear=\"true\"" : "")."\" id=\"".$attr_id."\" name=\"".$attr_name.($allowmultiple ? '[]' : '')."\"".($allowmultiple ? " multiple" : "")." data-placeholder=\"".getMLText("select_user")."\">"; if($allowempty) $content .= "<option value=\"\"></option>"; foreach($users as $curuser) { $content .= "<option value=\"".$curuser->getID()."\""; if(in_array($curuser->getID(), $objvalue)) $content .= " selected"; $content .= ">".htmlspecialchars($curuser->getLogin()." - ".$curuser->getFullName())."</option>"; } $content .= "</select>"; } else { $content .= getMLText('no_users'); } break; case SeedDMS_Core_AttributeDefinition::type_group: $target = $attribute ? $attribute->getValueAsArray() : []; $objvalue = []; foreach($target as $t) $objvalue[] = $t->getId(); $groups = $dms->getAllGroups(); if($groups) { $allowempty = $attrdef->getMinValues() == 0; $allowmultiple = $attrdef->getMultipleValues() || $alwaysmultiple; $content .= "<select class=\"form-control chzn-select\"".($allowempty ? " data-allow-clear=\"true\"" : "")."\" id=\"".$attr_id."\" name=\"".$attr_name.($allowmultiple ? '[]' : '')."\"".($allowmultiple ? " multiple" : "")." data-placeholder=\"".getMLText("select_group")."\">"; if($allowempty) $content .= "<option value=\"\"></option>"; foreach($groups as $curgroup) { $content .= "<option value=\"".$curgroup->getID()."\""; if(in_array($curgroup->getID(), $objvalue)) $content .= " selected"; $content .= ">".htmlspecialchars($curgroup->getName())."</option>"; } $content .= "</select>"; } else { $content .= getMLText('no_groups'); } break; default: if($valueset = $attrdef->getValueSetAsArray()) { $content .= "<input type=\"hidden\" name=\"".$attr_name."\" value=\"\"/>"; $content .= "<select id=\"".$attr_id."\" name=\"".$attr_name; if($attrdef->getMultipleValues() || $alwaysmultiple) { $content .= "[]\" multiple"; } else { $content .= "\" data-allow-clear=\"true\""; } $content .= "".((!$norequire && $attrdef->getMinValues() > 0) ? ' required="required"' : '')." class=\"form-control chzn-select\" data-placeholder=\"".getMLText("select_value")."\">"; if(!$attrdef->getMultipleValues() && !$alwaysmultiple) { $content .= "<option value=\"\"></option>"; } $objvalue = $attribute ? (is_object($attribute) ? $attribute->getValueAsArray() : $attribute) : array(); foreach($valueset as $value) { if($value) { $content .= "<option value=\"".htmlspecialchars($value)."\""; if(is_array($objvalue) && in_array($value, $objvalue)) $content .= " selected"; elseif($value == $objvalue) $content .= " selected"; $content .= ">".htmlspecialchars($value)."</option>"; } } $content .= "</select>"; } else { $objvalue = $attribute ? (is_object($attribute) ? $attribute->getValue() : $attribute) : ''; if(strlen($objvalue) > 80) { $content .= "<textarea class=\"form-control\" id=\"".$attr_id."\" class=\"input-xxlarge\" name=\"".$attr_name."\"".((!$norequire && $attrdef->getMinValues() > 0) ? ' required="required"' : '').">".htmlspecialchars($objvalue)."</textarea>"; } else { $content .= "<input type=\"text\" class=\"form-control\" id=\"".$attr_id."\" name=\"".$attr_name."\" value=\"".htmlspecialchars($objvalue)."\"".((!$norequire && $attrdef->getMinValues() > 0) ? ' required="required"' : '').(in_array($attrdef->getType(), [SeedDMS_Core_AttributeDefinition::type_int, SeedDMS_Core_AttributeDefinition::type_float]) ? ' data-rule-digits="true"' : '')." />"; } } break; } return $content; } /* }}} */ function printDropFolderChooserHtml($formName, $dropfolderfile="", $showfolders=0, $recursive=1) { /* {{{ */ echo self::getDropFolderChooserHtml($formName, $dropfolderfile, $showfolders, $recursive); } /* }}} */ function getDropFolderChooserHtml($formName, $dropfolderfile="", $showfolders=0, $recursive=1) { /* {{{ */ $content = "<div class=\"input-group\">\n"; $content .= "<input class=\"form-control fileupload-group\" readonly type=\"text\" id=\"dropfolderfile".$formName."\" name=\"dropfolderfile".$formName."\" value=\"".htmlspecialchars($dropfolderfile)."\">"; $content .= '<div class="input-group-append">'; $content .= "<button type=\"button\" class=\"btn btn-secondary\" id=\"clearfilename".$formName."\"><i class=\"fa fa-remove\"></i></button>"; $content .= $this->getModalBoxLink( array( 'target' => 'dropfolderChooser', 'remote' => $this->params['settings']->_httpRoot."out/out.DropFolderChooser.php?form=".$formName."&dropfolderfile=".urlencode($dropfolderfile)."&showfolders=".$showfolders."&recursive=".$recursive, 'class' => 'btn btn-secondary', 'title' => ($showfolders ? getMLText("choose_target_folder"): getMLText("choose_target_file")).'…' )); $content .= "</div>\n"; $content .= "</div>\n"; $content .= $this->getModalBox( array( 'id' => 'dropfolderChooser', 'title' => ($showfolders ? getMLText("choose_target_folder"): getMLText("choose_target_file")), 'buttons' => array( array('title'=>getMLText('close')), ) )); return $content; } /* }}} */ function printDropFolderChooserJs($formName, $showfolders=0) { /* {{{ */ ?> /* Set up a callback which is called when a folder in the tree is selected */ modalDropfolderChooser = $('#dropfolderChooser'); function fileSelected(name, form) { // $('#dropfolderfile<?php echo $formName ?>').val(name); $('#dropfolderfile'+form).val(name); modalDropfolderChooser.modal('hide'); } <?php if($showfolders) { ?> function folderSelected(name, form) { // $('#dropfolderfile<?php echo $formName ?>').val(name); $('#dropfolderfile'+form).val(name); modalDropfolderChooser.modal('hide'); } <?php } ?> $(document).ready(function() { $('#clearfilename<?php print $formName ?>').click(function(ev) { $('#dropfolderfile<?php echo $formName ?>').val(''); }); }); <?php } /* }}} */ function printDropFolderChooser($formName, $dropfolderfile="", $showfolders=0, $recursive=1) { /* {{{ */ $this->printDropFolderChooserHtml($formName, $dropfolderfile, $showfolders, $recursive); ?> <script language="JavaScript"> <?php $this->printDropFolderChooserJs($formName, $showfolders); ?> </script> <?php } /* }}} */ function getImgPath($img) { /* {{{ */ // if ( is_file($this->imgpath.$img) ) { return $this->imgpath.$img; // } return ""; } /* }}} */ function getCountryFlag($lang) { /* {{{ */ switch($lang) { case "en_GB": return 'flags/gb.png'; break; default: return 'flags/'.substr($lang, 0, 2).'.png'; } } /* }}} */ function printImgPath($img) { /* {{{ */ print $this->getImgPath($img); } /* }}} */ function infoMsg($msg) { /* {{{ */ echo "<div class=\"alert alert-info\">\n"; echo $msg; echo "</div>\n"; } /* }}} */ function warningMsg($msg) { /* {{{ */ echo "<div class=\"alert alert-warning\">\n"; echo $msg; echo "</div>\n"; } /* }}} */ function errorMsg($msg) { /* {{{ */ echo "<div class=\"alert alert-danger\">\n"; echo $msg; echo "</div>\n"; } /* }}} */ function successMsg($msg) { /* {{{ */ echo "<div class=\"alert alert-success\">\n"; echo $msg; echo "</div>\n"; } /* }}} */ function ___exitError($pagetitle, $error, $noexit=false, $plain=false) { /* {{{ */ /* This is just a hack to prevent creation of js files in an error * case, because they will contain this error page again. It would be much * better, if there was extra error() function similar to show() and calling * $view() after setting the action to 'error'. This would also allow to * set separate error pages for each view. */ if(!$noexit && isset($_REQUEST['action'])) { if(in_array($_REQUEST['action'], array('js', 'footerjs'))) { exit; } if($_REQUEST['action'] == 'webrootjs') { $this->webrootjs(); exit; } } if(!$plain) { $this->htmlStartPage($pagetitle); $this->globalNavigation(); $this->contentStart(); } $html = ''; $html .= "<h4>".getMLText('error')."!</h4>"; $html .= htmlspecialchars($error); $this->errorMsg($html); if(!$plain) { print "<div><button class=\"btn history-back\">".getMLText('back')."</button></div>"; $this->contentEnd(); $this->htmlEndPage(); } add_log_line(" UI::exitError error=".$error." pagetitle=".$pagetitle, PEAR_LOG_ERR); if($noexit) return; exit; } /* }}} */ function printNewTreeNavigation($folderid=0, $accessmode=M_READ, $showdocs=0, $formid='form1', $expandtree=0, $orderby='') { /* {{{ */ $this->printNewTreeNavigationHtml($folderid, $accessmode, $showdocs, $formid, $expandtree, $orderby); ?> <script language="JavaScript"> <?php $this->printNewTreeNavigationJs($folderid, $accessmode, $showdocs, $formid, $expandtree, $orderby); ?> </script> <?php } /* }}} */ function printNewTreeNavigationHtml($folderid=0, $accessmode=M_READ, $showdocs=0, $formid='form1', $expandtree=0, $orderby='') { /* {{{ */ //echo "<div id=\"jqtree".$formid."\" style=\"margin-left: 10px;\" data-url=\"../op/op.Ajax.php?command=subtree&showdocs=".$showdocs."&orderby=".$orderby."\"></div>\n"; echo "<div id=\"jqtree".$formid."\" style=\"margin-left: 10px;\" data-url=\"".$_SERVER['SCRIPT_NAME']."?action=subtree\"></div>\n"; } /* }}} */ /** * Create a tree of folders using jqtree. * * The tree can contain folders only or include documents. * * @param integer $folderid current folderid. If set the tree will be * folded out and the all folders in the path will be visible * @param integer $accessmode use this access mode when retrieving folders * and documents shown in the tree * @param boolean $showdocs set to true if tree shall contain documents * as well. * @param integer $expandtree level to which the tree shall be opened * @param boolean $partialtree set to true if the given folder is the start folder */ function printNewTreeNavigationJs($folderid=0, $accessmode=M_READ, $showdocs=0, $formid='form1', $expandtree=0, $orderby='', $partialtree=false) { /* {{{ */ function jqtree($path, $folder, $user, $accessmode, $showdocs=1, $expandtree=0, $orderby='', $level=0) { /* {{{ */ $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); if($path/* || $expandtree>=$level*/) { if($path) $pathfolder = array_shift($path); $children = array(); if($expandtree) { $subfolders = $folder->getSubFolders(isset($orderby[0]) ? $orderby[0] : '', $orderdir); $subfolders = SeedDMS_Core_DMS::filterAccess($subfolders, $user, $accessmode); } else { $subfolders = array($pathfolder); } foreach($subfolders as $subfolder) { $node = array('label'=>$subfolder->getName(), 'id'=>$subfolder->getID(), 'load_on_demand'=>(1 && ($subfolder->hasSubFolders() || ($subfolder->hasDocuments() && $showdocs))) ? true : false, 'is_folder'=>true); /* if the subfolder is in the path then further unfold the tree. */ if(/*$expandtree>=$level ||*/ $path && ($path[0]->getID() == $subfolder->getID())) { $node['children'] = jqtree($path, $subfolder, $user, $accessmode, $showdocs, $expandtree, $orderby, $level+1); if($showdocs) { $documents = $subfolder->getDocuments(isset($orderby[0]) ? $orderby[0] : '', $orderdir); $documents = SeedDMS_Core_DMS::filterAccess($documents, $user, $accessmode); foreach($documents as $document) { $node2 = array('label'=>$document->getName(), 'id'=>$document->getID(), 'load_on_demand'=>false, 'is_folder'=>false); $node['children'][] = $node2; } } } $children[] = $node; } return $children; } else { $subfolders = $folder->getSubFolders(isset($orderby[0]) ? $orderby[0] : '', $orderdir); $subfolders = SeedDMS_Core_DMS::filterAccess($subfolders, $user, $accessmode); $children = array(); foreach($subfolders as $subfolder) { $node = array('label'=>$subfolder->getName(), 'id'=>$subfolder->getID(), 'load_on_demand'=>($subfolder->hasSubFolders() || ($subfolder->hasDocuments() && $showdocs)) ? true : false, 'is_folder'=>true); $children[] = $node; } return $children; } return array(); } /* }}} */ $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); if($folderid && ($folder = $this->params['dms']->getFolder($folderid))) { $path = null; if(!$partialtree) { $path = $folder->getPath(); /* Get the first folder (root folder) of path */ $folder = array_shift($path); } $node = array('label'=>$folder->getName(), 'id'=>$folder->getID(), 'load_on_demand'=>false, 'is_folder'=>true); if(!$folder->hasSubFolders()) { $node['load_on_demand'] = true; $node['children'] = array(); } else { $node['children'] = jqtree($path, $folder, $this->params['user'], $accessmode, $showdocs, 1 /*$expandtree*/, $orderby, 0); if($showdocs) { $documents = $folder->getDocuments(isset($orderby[0]) ? $orderby[0] : '', $orderdir); $documents = SeedDMS_Core_DMS::filterAccess($documents, $this->params['user'], $accessmode); foreach($documents as $document) { $node2 = array('label'=>$document->getName(), 'id'=>$document->getID(), 'load_on_demand'=>false, 'is_folder'=>false); $node['children'][] = $node2; } } } /* Nasty hack to remove the highest folder */ if(isset($this->params['remove_root_from_tree']) && $this->params['remove_root_from_tree']) { foreach($node['children'] as $n) $tree[] = $n; } else { $tree[] = $node; } } else { if($root = $this->params['dms']->getFolder($this->params['rootfolderid'])) $tree = array(array('label'=>$root->getName(), 'id'=>$root->getID(), 'load_on_demand'=>false, 'is_folder'=>true)); else $tree = array(); } ?> var data = <?php echo json_encode($tree); ?>; $(function() { const $tree = $('#jqtree<?php echo $formid ?>'); $tree.tree({ // saveState: false, selectable: false, data: data, saveState: 'jqtree<?php echo $formid; ?>', openedIcon: $('<i class="fa fa-minus-circle"></i>'), closedIcon: $('<i class="fa fa-plus-circle"></i>'), /* _onCanSelectNode: function(node) { if(node.is_folder) { folderSelected<?= $formid ?>(node.id, node.name); treeFolderSelected('<?= $formid ?>', node.id, node.name); } else { documentSelected<?= $formid ?>(node.id, node.name); treeDocumentSelected('<?= $formid ?>', node.id, node.name); } }, */ autoOpen: false, drapAndDrop: true, onCreateLi: function(node, $li) { // Add 'icon' span before title if(node.is_folder) $li.find('.jqtree-title').prepend('<i class="fa fa-folder-o"></i> ').attr('data-name', node.name).attr('rel', 'folder_' + node.id).attr('formtoken', '<?php echo createFormKey(''); ?>').attr('data-uploadformtoken', '<?php echo createFormKey(''); ?>').attr('data-droptarget', 'folder_' + node.id).addClass('droptarget'); else $li.find('.jqtree-title').prepend('<i class="fa fa-file"></i> '); } }); // Unfold node for currently selected folder $('#jqtree<?php echo $formid ?>').tree('selectNode', $('#jqtree<?php echo $formid ?>').tree('getNodeById', <?php echo $folderid ?>), false, true); $('#jqtree<?php echo $formid ?>').on( 'tree.click', function(event) { var node = event.node; if(!node) return; if(node.is_folder) { $('#jqtree<?php echo $formid ?>').tree('openNode', node); <?php if($showdocs) { ?> // event.preventDefault(); if(typeof node.fetched == 'undefined') { node.fetched = true; $(this).tree('loadDataFromUrl', node, function () { $(this).tree('openNode', node); }); } <?php } ?> /* folderSelectedXXXX() can still be set, e.g. for the main tree * to update the folder list. */ if (typeof folderSelected<?= $formid ?> === 'function') { folderSelected<?= $formid ?>(node.id, node.name); } treeFolderSelected('<?= $formid ?>', node.id, node.name); } else { <?php if($showdocs) { ?> if (typeof documentSelected<?= $formid ?> === 'function') { documentSelected<?= $formid ?>(node.id, node.name); } treeDocumentSelected('<?= $formid ?>', node.id, node.name); <?php } ?> } } ); $('#jqtree<?php echo $formid ?>').on( 'tree.contextmenu', function(event) { // The clicked node is 'event.node' var node = event.node; if(typeof node.fetched == 'undefined') { node.fetched = true; $(this).tree('loadDataFromUrl', node); } $(this).tree('openNode', node); } ); $("#jqtree").on('dragenter', function (e) { attr_rel = $(e.srcElement).attr('rel'); if(typeof attr_rel == 'undefined') return; target_type = attr_rel.split("_")[0]; target_id = attr_rel.split("_")[1]; var node = $(this).tree('getNodeById', parseInt(target_id)); if(typeof node.fetched == 'undefined') { node.fetched = true; $(this).tree('loadDataFromUrl', node, function() {$(this).tree('openNode', node);}); } }); }); <?php } /* }}} */ /** * Return json data for sub tree of navigation tree */ function printNewTreeNavigationSubtree($folderid, $showdocs=0, $orderby='') { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; $folder = $dms->getFolder($folderid); if (!is_object($folder)) return ''; $subfolders = $folder->getSubFolders($orderby); $subfolders = SeedDMS_Core_DMS::filterAccess($subfolders, $user, M_READ); $tree = array(); foreach($subfolders as $subfolder) { $loadondemand = $subfolder->hasSubFolders() || ($subfolder->hasDocuments() && $showdocs); $level = array('label'=>$subfolder->getName(), 'id'=>$subfolder->getID(), 'load_on_demand'=>$loadondemand, 'is_folder'=>true); if(!$subfolder->hasSubFolders()) $level['children'] = array(); $tree[] = $level; } if($showdocs) { $documents = $folder->getDocuments($orderby); $documents = SeedDMS_Core_DMS::filterAccess($documents, $user, M_READ); foreach($documents as $document) { $level = array('label'=>$document->getName(), 'id'=>$document->getID(), 'load_on_demand'=>false, 'is_folder'=>false); $tree[] = $level; } } header('Content-Type: application/json'); echo json_encode($tree); } /* }}} */ /** * Deprecated! */ function __printTreeNavigation($folderid, $showtree){ /* {{{ */ if ($showtree==1){ $this->contentHeading("<a href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=". $folderid."&showtree=0\"><i class=\"fa fa-minus-circle\"></i></a>", true); $this->contentContainerStart(); ?> <script language="JavaScript"> function folderSelected(id, name) { window.location = '<?= $this->params['settings']->_httpRoot ?>out/out.ViewFolder.php?folderid=' + id; } </script> <?php $this->printNewTreeNavigation($folderid, M_READ, 0, ''); $this->contentContainerEnd(); } else { $this->contentHeading("<a href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=". $folderid."&showtree=1\"><i class=\"fa fa-plus-circle\"></i></a>", true); } } /* }}} */ /** * Print clipboard in div container * * @param array clipboard */ function printClipboard($clipboard, $previewer){ /* {{{ */ echo "<div id=\"clipboard-container\" class=\"_clipboard-container\">\n"; $this->contentHeading(getMLText("clipboard").'<span id="clipboard-float"><i class="fa fa-sort"></i></span>', true); echo "<div id=\"main-clipboard\">\n"; ?> <div class="ajax" data-view="Clipboard" data-action="mainClipboard"></div> <?php echo "</div>\n"; echo "</div>\n"; } /* }}} */ /** * Wrap text in inline editing tags * * @param string text */ function printInlineEdit($text, $object){ /* {{{ */ if(!empty($this->params['settings']->_inlineEditing)) { echo "<span class=\"editable\" contenteditable=\"true\""; if($object->isType('document')) echo " data-document=\"".$object->getId()."\" data-formtoken=\"".createFormKey('setdocumentname')."\""; echo ">".$text; echo "</span>\n"; } else echo $text; } /* }}} */ /** * Print button with link for deleting a document * * This button is used in document listings (e.g. on the ViewFolder page) * for deleting a document. In seeddms version < 4.3.9 this was just a * link to the out/out.RemoveDocument.php page which asks for confirmation * an than calls op/op.RemoveDocument.php. Starting with version 4.3.9 * the button just opens a small popup asking for confirmation and than * calls the ajax command 'deletedocument'. The ajax call is called * in the click function of 'button.removedocument'. That button needs * to have two attributes: 'rel' for the id of the document, and 'msg' * for the message shown by notify if the document could be deleted. * * @param object $document document to be deleted * @param string $msg message shown in case of successful deletion * @param boolean $return return html instead of printing it * @return string html content if $return is true, otherwise an empty string */ function printDeleteDocumentButton($document, $msg, $return=false){ /* {{{ */ $docid = $document->getID(); $content = ''; $content .= '<a class="delete-document-btn" rel="'.$docid.'" msg="'.getMLText($msg).'" confirmmsg="'.htmlspecialchars(getMLText("confirm_rm_document", array ("documentname" => $document->getName())), ENT_QUOTES).'" title="'.getMLText("delete").'"><i class="fa fa-remove"></i></a>'; if($return) return $content; else echo $content; return ''; } /* }}} */ function printDeleteDocumentButtonJs(){ /* {{{ */ echo " $(document).ready(function () { // $('.delete-document-btn').click(function(ev) { $('body').on('click', 'a.delete-document-btn', function(ev){ ev.stopPropagation(); id = $(ev.currentTarget).attr('rel'); confirmmsg = $(ev.currentTarget).attr('confirmmsg'); msg = $(ev.currentTarget).attr('msg'); formtoken = '".createFormKey('removedocument')."'; bootbox.confirm({ \"message\": confirmmsg, \"buttons\": { \"confirm\": { \"label\" : \"<i class='fa fa-remove'></i> ".getMLText("rm_document")."\", \"className\" : \"btn-danger\", }, \"cancel\": { \"label\" : \"".getMLText("cancel")."\", \"className\" : \"btn-secondary\", } }, \"callback\": function(result) { if(result) { $.get('".$this->params['settings']->_httpRoot."op/op.Ajax.php', { command: 'deletedocument', id: id, formtoken: formtoken }, function(data) { if(data.success) { $('#table-row-document-'+id).hide('slow'); noty({ text: msg, type: 'success', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 1500, }); } else { noty({ text: data.message, type: 'error', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 3500, }); } }, 'json' ); } } }); }); }); "; } /* }}} */ /** * Print button with link for deleting a folder * * This button works like document delete button * {@link SeedDMS_Bootstrap_Style::printDeleteDocumentButton()} * * @param object $folder folder to be deleted * @param string $msg message shown in case of successful deletion * @param boolean $return return html instead of printing it * @return string html content if $return is true, otherwise an empty string */ function printDeleteFolderButton($folder, $msg, $return=false){ /* {{{ */ $folderid = $folder->getID(); $content = ''; $content .= '<a class="delete-folder-btn" rel="'.$folderid.'" msg="'.getMLText($msg).'" confirmmsg="'.htmlspecialchars(getMLText("confirm_rm_folder", array ("foldername" => $folder->getName())), ENT_QUOTES).'" title="'.getMLText("delete").'"><i class="fa fa-remove"></i></a>'; if($return) return $content; else echo $content; return ''; } /* }}} */ function printDeleteFolderButtonJs(){ /* {{{ */ echo " $(document).ready(function () { // $('.delete-folder-btn').click(function(ev) { $('body').on('click', 'a.delete-folder-btn', function(ev){ ev.stopPropagation(); id = $(ev.currentTarget).attr('rel'); confirmmsg = $(ev.currentTarget).attr('confirmmsg'); msg = $(ev.currentTarget).attr('msg'); formtoken = '".createFormKey('removefolder')."'; bootbox.confirm({ \"message\": confirmmsg, \"buttons\": { \"confirm\": { \"label\" : \"<i class='fa fa-remove'></i> ".getMLText("rm_folder")."\", \"className\" : \"btn-danger\", }, \"cancel\": { \"label\" : \"".getMLText("cancel")."\", \"className\" : \"btn-secondary\", } }, \"callback\": function(result) { if(result) { $.get('".$this->params['settings']->_httpRoot."op/op.Ajax.php', { command: 'deletefolder', id: id, formtoken: formtoken }, function(data) { if(data.success) { $('#table-row-folder-'+id).hide('slow'); noty({ text: msg, type: 'success', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 1500, }); } else { noty({ text: data.message, type: 'error', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 3500, }); } }, 'json' ); } } }); }); }); "; } /* }}} */ function printLockButton($document, $msglock, $msgunlock, $return=false) { /* {{{ */ $accessobject = $this->params['accessobject']; $docid = $document->getID(); if($document->isLocked()) { if(!$accessobject->check_controller_access('UnlockDocument')) return ''; $icon = 'unlock'; $msg = $msgunlock; $title = 'unlock_document'; } else { if(!$accessobject->check_controller_access('LockDocument')) return ''; $icon = 'lock'; $msg = $msglock; $title = 'lock_document'; } $content = ''; $content .= '<a class="lock-document-btn" rel="'.$docid.'" msg="'.getMLText($msg).'" title="'.getMLText($title).'" data-formtoken="'.createFormKey('tooglelockdocument').'"><i class="fa fa-'.$icon.'"></i></a>'; if($return) return $content; else echo $content; return ''; } /* }}} */ function printAccessButton($object, $return=false) { /* {{{ */ $accessobject = $this->params['accessobject']; $content = ''; $objid = $object->getId(); if($object->isType('document')) { if($accessobject->check_view_access('DocumentAccess')) $content .= '<a class="access-document-btn" href="'.$this->params['settings']->_httpRoot.'out/out.DocumentAccess.php?documentid='.$objid.'" title="'.getMLText('edit_document_access').'"><i class="fa fa-bolt"></i></a>'; } elseif($object->isType('folder')) { if($accessobject->check_view_access('FolderAccess')) $content .= '<a class="access-folder-btn" href="'.$this->params['settings']->_httpRoot.'out/out.FolderAccess.php?folderid='.$objid.'" title="'.getMLText('edit_folder_access').'"><i class="fa fa-bolt"></i></a>'; } if($return) return $content; else echo $content; return ''; } /* }}} */ /** * Output left-arrow with link which takes over a number of ids into * a select box. * * Clicking in the button will preset the comma seperated list of ids * in data-ref as options in the select box with name $name * * @param string $name id of select box * @param array $ids list of option values */ function getSelectPresetButtonHtml($name, $ids) { /* {{{ */ return '<span id="'.$name.'_btn" class="selectpreset_btn" style="cursor: pointer;" title="'.getMLText("takeOver".$name).'" data-ref="'.$name.'" data-ids="'.implode(",", $ids).'"><i class="fa fa-arrow-left"></i></span>'; } /* }}} */ /** * Output left-arrow with link which takes over a number of ids into * a select box. * * Clicking in the button will preset the comma seperated list of ids * in data-ref as options in the select box with name $name * * @param string $name id of select box * @param array $ids list of option values */ function printSelectPresetButtonHtml($name, $ids) { /* {{{ */ echo self::getSelectPresetButtonHtml($name, $ids); } /* }}} */ /** * Javascript code for select preset button */ function printSelectPresetButtonJs() { /* {{{ */ ?> $(document).ready( function() { $('.selectpreset_btn').click(function(ev){ ev.preventDefault(); if (typeof $(ev.currentTarget).data('ids') != 'undefined') { target = $(ev.currentTarget).data('ref'); // Use attr() instead of data() because data() converts to int which cannot be split items = $(ev.currentTarget).attr('data-ids'); arr = items.split(","); for(var i in arr) { $("#"+target+" option[value='"+arr[i]+"']").attr("selected", "selected"); } // $("#"+target).trigger("chosen:updated"); $("#"+target).trigger("change"); } }); }); <?php } /* }}} */ /** * Get HTML for left-arrow with link which takes over a string into * a input field. * * Clicking on the button will preset the string * in data-ref the value of the input field with name $name * * @param string $name id of select box * @param string $text text */ function getInputPresetButtonHtml($name, $text, $sep='') { /* {{{ */ return '<span id="'.$name.'_btn" class="inputpreset_btn" style="cursor: pointer;" title="'.getMLText("takeOverAttributeValue").'" data-ref="'.$name.'" data-text="'.(is_array($text) ? implode($sep, $text) : htmlspecialchars($text)).'"'.($sep ? " data-sep=\"".$sep."\"" : "").'><i class="fa fa-arrow-left"></i></span>'; } /* }}} */ /** * Output left-arrow with link which takes over a string into * a input field. * * Clicking on the button will preset the string * in data-ref the value of the input field with name $name * * @param string $name id of select box * @param string $text text */ function printInputPresetButtonHtml($name, $text, $sep='') { /* {{{ */ echo self::getInputPresetButtonHtml($name, $text, $sep); } /* }}} */ /** * Javascript code for input preset button * This code workѕ for input fields and single select fields */ function printInputPresetButtonJs() { /* {{{ */ ?> $(document).ready( function() { $('.inputpreset_btn').click(function(ev){ ev.preventDefault(); if (typeof $(ev.currentTarget).data('text') != 'undefined') { target = $(ev.currentTarget).data('ref'); value = $(ev.currentTarget).data('text'); sep = $(ev.currentTarget).data('sep'); if(sep) { // Use attr() instead of data() because data() converts to int which cannot be split arr = value.split(sep); for(var i in arr) { $("#"+target+" option[value='"+arr[i]+"']").attr("selected", "selected"); } } else { $("#"+target).val(value); } } }); }); <?php } /* }}} */ /** * Get HTML for left-arrow with link which takes over a boolean value * into a checkbox field. * * Clicking on the button will preset the checkbox * in data-ref the value of the input field with name $name * * @param string $name id of select box * @param string $text text */ function getCheckboxPresetButtonHtml($name, $text) { /* {{{ */ ?> return '<span id="'.$name.'_btn" class="checkboxpreset_btn" style="cursor: pointer;" title="'.getMLText("takeOverAttributeValue").'" data-ref="'.$name.'" data-text="'.(is_array($text) ? implode($sep, $text) : htmlspecialchars($text)).'"'.($sep ? " data-sep=\"".$sep."\"" : "").'><i class="fa fa-arrow-left"></i></span>'; <?php } /* }}} */ /** * Output left-arrow with link which takes over a boolean value * into a checkbox field. * * Clicking on the button will preset the checkbox * in data-ref the value of the input field with name $name * * @param string $name id of select box * @param string $text text */ function printCheckboxPresetButtonHtml($name, $text) { /* {{{ */ self::getCheckboxPresetButtonHtml($name, $text); } /* }}} */ /** * Javascript code for checkboxt preset button * This code workѕ for checkboxes */ function printCheckboxPresetButtonJs() { /* {{{ */ ?> $(document).ready( function() { $('.checkboxpreset_btn').click(function(ev){ ev.preventDefault(); if (typeof $(ev.currentTarget).data('text') != 'undefined') { target = $(ev.currentTarget).data('ref'); value = $(ev.currentTarget).data('text'); if(value) { $("#"+target).attr('checked', ''); } else { $("#"+target).removeAttribute('checked'); } } }); }); <?php } /* }}} */ /** * Print button with link for deleting an attribute value * * This button is used in document listings (e.g. on the ViewFolder page) * for deleting a document. In seeddms version < 4.3.9 this was just a * link to the out/out.RemoveDocument.php page which asks for confirmation * an than calls op/op.RemoveDocument.php. Starting with version 4.3.9 * the button just opens a small popup asking for confirmation and than * calls the ajax command 'deletedocument'. The ajax call is called * in the click function of 'button.removedocument'. That button needs * to have two attributes: 'rel' for the id of the document, and 'msg' * for the message shown by notify if the document could be deleted. * * @param object $document document to be deleted * @param string $msg message shown in case of successful deletion * @param boolean $return return html instead of printing it * @return string html content if $return is true, otherwise an empty string */ function printDeleteAttributeValueButton($attrdef, $value, $msg, $return=false){ /* {{{ */ $content = ''; $content .= '<a class="delete-attribute-value-btn" rel="'.$attrdef->getID().'" msg="'.getMLText($msg).'" attrvalue="'.htmlspecialchars($value, ENT_QUOTES).'" confirmmsg="'.htmlspecialchars(getMLText("confirm_rm_attr_value", array ("attrdefname" => $attrdef->getName())), ENT_QUOTES).'"><i class="fa fa-remove"></i></a>'; if($return) return $content; else echo $content; return ''; } /* }}} */ function printDeleteAttributeValueButtonJs(){ /* {{{ */ echo " $(document).ready(function () { // $('.delete-attribute-value-btn').click(function(ev) { $('body').on('click', 'a.delete-attribute-value-btn', function(ev){ id = $(ev.currentTarget).attr('rel'); confirmmsg = $(ev.currentTarget).attr('confirmmsg'); attrvalue = $(ev.currentTarget).attr('attrvalue'); msg = $(ev.currentTarget).attr('msg'); formtoken = '".createFormKey('removeattrvalue')."'; bootbox.confirm({ \"message\": confirmmsg, \"buttons\": { \"confirm\": { \"label\" : \"<i class='fa fa-remove'></i> ".getMLText("rm_attr_value")."\", \"className\" : \"btn-danger\", }, \"cancel\": { \"label\" : \"".getMLText("cancel")."\", \"className\" : \"btn-secondary\", } }, \"callback\": function(result) { if(result) { $.post('".$this->params['settings']->_httpRoot."op/op.AttributeMgr.php', { action: 'removeattrvalue', attrdefid: id, attrvalue: attrvalue, formtoken: formtoken }, function(data) { if(data.success) { $('#table-row-attrvalue-'+id).hide('slow'); noty({ text: msg, type: 'success', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 1500, }); } else { noty({ text: data.message, type: 'error', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 3500, }); } }, 'json' ); } } }); }); }); "; } /* }}} */ function printClickDocumentJs() { /* {{{ */ $onepage = $this->params['onepage']; if($onepage) { ?> /* catch click on a document row in the list folders and documents */ $('body').on('click', '[id^=\"table-row-document\"] td:nth-child(2)', function(ev) { if(ev.shiftKey) { $(ev.currentTarget).parent().toggleClass('selected'); } else { attr_id = $(ev.currentTarget).parent().attr('id').split('-')[3]; window.location = '<?= $this->params['settings']->_httpRoot ?>out/out.ViewDocument.php?documentid=' + attr_id; } }); <?php } } /* }}} */ /** * Print js code which catches clicks on folder rows * * This method will catch a click on a folder row and changes the * window.location to the out.ViewFolder.php page * This code is not needed on the out.ViewFolder.php page itself, because * a click will just reload the list of folders and documents. */ function printClickFolderJs() { /* {{{ */ $onepage = $this->params['onepage']; if($onepage) { ?> /* catch click on a document row in the list folders and documents */ $('body').on('click', '[id^=\"table-row-folder\"] td:nth-child(2)', function(ev) { if(ev.shiftKey) { $(ev.currentTarget).parent().toggleClass('selected'); } else { attr_id = $(ev.currentTarget).parent().data('target-id'); if(typeof attr_id == 'undefined') attr_id = $(ev.currentTarget).parent().attr('id').split('-')[3]; window.location = '<?= $this->params['settings']->_httpRoot ?>out/out.ViewFolder.php?folderid=' + attr_id; } }); <?php } } /* }}} */ /** * Return HTML containing the path of a document or folder * * This is used for showing the path of a document/folder below the title * in document/folder lists like on the search page. * * @param object $object * @return string */ function getListRowPath($object) { /* {{{ */ if(!$object) return ''; $belowtitle = ''; $folder = $object->getParent(); if($folder) { $belowtitle .= "<br /><span style=\"font-size: 85%;\">".getMLText('in_folder').": /"; $path = $folder->getPath(); for ($i = 1; $i < count($path); $i++) { $belowtitle .= htmlspecialchars($path[$i]->getName())."/"; } $belowtitle .= "</span>"; } return $belowtitle; } /* }}} */ public function folderListHeaderImage() { /* {{{ */ $folder = $this->getParam('folder'); $onepage = $this->params['onepage']; $parent = ($folder && $onepage) ? $folder->getParent() : null; $headcol = ($parent ? '<button class="btn btn-mini btn-secondary btn-sm" id="goto-parent" data-parentid="'.$parent->getID().'"><i class="fa fa-arrow-up"></i></button>' : '')."</th>\n"; return $headcol; } /* }}} */ public function folderListHeaderName() { /* {{{ */ $folder = $this->getParam('folder'); $headcol = getMLText("name"); if($folder) { $folderid = $folder->getId(); $orderby = $this->params['orderby']; $orderdir = (isset($orderby[1]) ? ($orderby[1] == 'd' ? 'desc' : 'asc') : 'asc'); $headcol .= " <a class=\"order-btn\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=". $folderid .($orderby=="n"||$orderby=="na"?"&orderby=nd":"&orderby=n")."\" data-orderby=\"".($orderby=="n"||$orderby=="na"?"nd":"n")."\"title=\"".getMLText("sort_by_name")."\">".($orderby=="n"||$orderby=="na"?' <i class="fa fa-sort-alpha-asc selected"></i>':($orderby=="nd"?' <i class="fa fa-sort-alpha-desc selected"></i>':' <i class="fa fa-sort-alpha-asc"></i>'))."</a>"; $headcol .= " <a class=\"order-btn\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=". $folderid .($orderby=="s"||$orderby=="sa"?"&orderby=sd":"&orderby=s")."\" data-orderby=\"".($orderby=="s"||$orderby=="sa"?"sd":"s")."\" title=\"".getMLText("sort_by_sequence")."\">".($orderby=="s"||$orderby=="sa"?' <i class="fa fa-sort-numeric-asc selected"></i>':($orderby=="sd"?' <i class="fa fa-sort-numeric-desc selected"></i>':' <i class="fa fa-sort-numeric-asc"></i>'))."</a>"; $headcol .= " <a class=\"order-btn\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=". $folderid .($orderby=="d"||$orderby=="da"?"&orderby=dd":"&orderby=d")."\" data-orderby=\"".($orderby=="d"||$orderby=="da"?"dd":"d")."\" title=\"".getMLText("sort_by_date")."\">".($orderby=="d"||$orderby=="da"?' <i class="fa fa-sort-amount-asc selected"></i>':($orderby=="dd"?' <i class="fa fa-sort-amount-desc selected"></i>':' <i class="fa fa-sort-amount-asc"></i>'))."</a>"; } return $headcol; } /* }}} */ public function folderListHeader() { /* {{{ */ $content = "<table id=\"viewfolder-table\" class=\"table table-condensed table-sm table-hover\">"; $content .= "<thead>\n<tr>\n"; $headcols = array(); $headcols['image'] = $this->folderListHeaderImage(); $headcols['name'] = $this->folderListHeaderName(); if($ec = $this->callHook('folderListHeaderExtraColumns')) $headcols = array_merge($headcols, $ec); $headcols['status'] = getMLText("status"); $headcols['action'] = getMLText("action"); foreach($headcols as $headcol) $content .= "<th>".$headcol."</th>\n"; $content .= "</tr>\n</thead>\n"; return $content; } /* }}} */ /** * Start the row for a folder in list of documents and folders * * For a detailed description see * {@link SeedDMS_Bootstrap_Style::folderListRowStart()} */ function documentListRowStart($document, $class='') { /* {{{ */ if($class) { if($class == 'error') $class = 'table-danger'; else $class = 'table-'.$class; } $docID = $document->getID(); return "<tr id=\"table-row-document-".$docID."\" data-target-id=\"".$docID."\" class=\"table-row-document droptarget ".($class ? ' '.$class : '')."\" data-droptarget=\"document_".$docID."\" rel=\"document_".$docID."\" formtoken=\"".createFormKey('')."\" data-uploadformtoken=\"".createFormKey('')."\" draggable=\"true\" data-name=\"".htmlspecialchars($document->getName(), ENT_QUOTES)."\">"; } /* }}} */ function documentListRowEnd($document) { /* {{{ */ return "</tr>\n"; } /* }}} */ function documentListRowStatus($latestContent) { /* {{{ */ $user = $this->params['user']; $workflowmode = $this->params['workflowmode']; $document = $latestContent->getDocument(); $status = $latestContent->getStatus(); $attentionstr = ''; if ( $document->isLocked() ) { $attentionstr .= "<i class=\"fa fa-lock\" title=\"". getMLText("locked_by").": ".htmlspecialchars($document->getLockingUser()->getFullName())."\"></i> "; } if($workflowmode == 'advanced') { $workflow = $latestContent->getWorkflow(); if($workflow && $latestContent->needsWorkflowAction($user)) { $attentionstr .= "<i class=\"fa fa-exclamation-triangle\" title=\"". getMLText("workflow").": ".htmlspecialchars($workflow->getName())."\"></i> "; } } $content = ''; if($attentionstr) $content .= $attentionstr."<br />"; /* Retrieve attacheѕ files */ $files = $document->getDocumentFiles($latestContent->getVersion()); $files = SeedDMS_Core_DMS::filterDocumentFiles($user, $files); /* Retrieve linked documents */ $links = $document->getDocumentLinks(); $links = SeedDMS_Core_DMS::filterDocumentLinks($user, $links); /* Retrieve reverse linked documents */ $revlinks = $document->getReverseDocumentLinks(); $revlinks = SeedDMS_Core_DMS::filterDocumentLinks($user, $revlinks); $content .= "<div style=\"font-size: 85%;\">"; if(count($files)) $content .= '<i class="fa fa-paperclip" title="'.getMLText("linked_files").'"></i> '.count($files)."<br />"; if(count($links) || count($revlinks)) $content .= '<i class="fa fa-link" title="'.getMLText("linked_documents").'"></i> '.count($links)."/".count($revlinks)."<br />"; if($status["status"] == S_IN_WORKFLOW && $workflowmode == 'advanced') { if($workflowstate = $latestContent->getWorkflowState()) $content .= '<span title="'.getOverallStatusText($status["status"]).': '.($workflow ? htmlspecialchars($workflow->getName()) : '').'">'.($workflowstate ? htmlspecialchars($workflowstate->getName()) : '').'</span>'; } else { $content .= $this->getOverallStatusIcon($status['status']); } $content .= "</div>"; return $content; } /* }}} */ function documentListRowAction($document, $previewer, $skipcont=false, $version=0, $extracontent=array()) { /* {{{ */ $user = $this->params['user']; $enableClipboard = $this->params['enableclipboard']; $accessop = $this->params['accessobject']; $onepage = $this->params['onepage']; $content = ''; $content .= "<div class=\"list-action\">"; $actions = array(); if(!empty($extracontent['begin_action_list'])) $content .= $extracontent['begin_action_list']; if($accessop->check_view_access('RemoveDocument')) { if($document->getAccessMode($user, 'removeDocument') >= M_ALL) { $actions['remove_document'] = $this->printDeleteDocumentButton($document, 'splash_rm_document', true); } else { $actions['remove_document'] = '<span style="padding: 2px; color: #CCC;"><i class="fa fa-remove"></i></span>'; } } $docID = $document->getID(); if($document->getAccessMode($user) >= M_READWRITE) { $actions['edit_document'] = '<a href="'.$this->params['settings']->_httpRoot.'out/out.EditDocument.php?documentid='.$docID.'" title="'.getMLText("edit_document_props").'"><i class="fa fa-edit"></i></a>'; } else { $actions['edit_document'] = '<span style="padding: 2px; color: #CCC;"><i class="fa fa-edit"></i></span>'; } if($document->getAccessMode($user) >= M_READWRITE) { $actions['lock_document'] = $this->printLockButton($document, 'splash_document_locked', 'splash_document_unlocked', true); } if($document->getAccessMode($user) >= M_READWRITE) { $actions['document_access'] = $this->printAccessButton($document, true); } if($enableClipboard) { $actions['add_to_clipboard'] = '<a class="addtoclipboard" rel="D'.$docID.'" msg="'.getMLText('splash_added_to_clipboard').'" title="'.getMLText("add_to_clipboard").'"><i class="fa fa-copy"></i></a>'; } if($onepage) $actions['view_document'] = '<a href="'.$this->params['settings']->_httpRoot.'out/out.ViewDocument.php?documentid='.$docID.'" title="'.getMLText("view_document").'"><i class="fa fa-eye"></i></a>'; /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'documentRowAction')) { $actions = $hookObj->documentRowAction($this, $document, $actions); } } foreach($actions as $action) { if(is_string($action)) $content .= $action; } if(!empty($extracontent['end_action_list'])) $content .= $extracontent['end_action_list']; $content .= "</div>"; return $content; } /* }}} */ /** * Return HTML of a single row in the document list table * * @param object $document * @param object $previewer * @param boolean $skipcont set to true if embrasing tr shall be skipped */ function documentListRow($document, $previewer, $skipcont=false, $version=0, $extracontent=array()) { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; $showtree = $this->params['showtree']; $workflowmode = $this->params['workflowmode']; $previewwidth = $this->params['previewWidthList']; $enableClipboard = $this->params['enableclipboard']; $accessop = $this->params['accessobject']; $onepage = $this->params['onepage']; $content = ''; $owner = $document->getOwner(); $comment = $document->getComment(); if (strlen($comment) > 150) $comment = substr($comment, 0, 147) . "..."; $docID = $document->getID(); if($version) { $latestContent = $this->callHook('documentContent', $document, $version); if($latestContent === null) $latestContent = $document->getContentByVersion($version); } else { $latestContent = $this->callHook('documentLatestContent', $document); if($latestContent === null) $latestContent = $document->getLatestContent(); } if($latestContent) { if(!$skipcont) $content .= $this->documentListRowStart($document); if($previewer) $previewer->createPreview($latestContent); $version = $latestContent->getVersion(); if($ec = $this->callHook('documentListRowExtraContent', $document, $latestContent)) $extracontent = array_merge($extracontent, $ec); $content .= "<td>"; if (file_exists($dms->contentDir . $latestContent->getPath())) { $previewhtml = $this->callHook('documentListPreview', $previewer, $document, $latestContent); if(is_string($previewhtml)) $content .= $previewhtml; else { if($accessop->check_controller_access('Download', array('action'=>'version'))) $content .= "<a draggable=\"false\" href=\"".$this->params['settings']->_httpRoot."op/op.Download.php?documentid=".$docID."&version=".$version."\">"; if($previewer && $previewer->hasPreview($latestContent)) { $content .= "<img draggable=\"false\" class=\"mimeicon\" width=\"".$previewwidth."\" src=\"".$this->params['settings']->_httpRoot."op/op.Preview.php?documentid=".$document->getID()."&version=".$latestContent->getVersion()."&width=".$previewwidth."\" title=\"".htmlspecialchars($latestContent->getMimeType())."\">"; } else { $content .= "<img draggable=\"false\" class=\"mimeicon\" width=\"".$previewwidth."\" src=\"".$this->getMimeIcon($latestContent->getFileType())."\" ".($previewwidth ? "width=\"".$previewwidth."\"" : "")."\" title=\"".htmlspecialchars($latestContent->getMimeType())."\">"; } if($accessop->check_controller_access('Download', array('action'=>'version'))) $content .= "</a>"; } } else $content .= "<img draggable=\"false\" class=\"mimeicon\" width=\"".$previewwidth."\" src=\"".$this->getMimeIcon($latestContent->getFileType())."\" title=\"".htmlspecialchars($latestContent->getMimeType())."\">"; $content .= "</td>"; $content .= "<td class=\"wordbreak\"".($onepage ? ' style="cursor: pointer;"' : '').">"; if($onepage) $content .= "<b".($onepage ? ' title="Id:'.$document->getId().'"' : '').">".htmlspecialchars($document->getName()) . "</b>"; else $content .= "<a draggable=\"false\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewDocument.php?documentid=".$docID."&showtree=".$showtree."\">" . htmlspecialchars($document->getName()) . "</a>"; if(isset($extracontent['below_title'])) $content .= $extracontent['below_title']; $content .= "<br />"; if($belowtitle = $this->callHook('documentListRowBelowTitle', $document, $latestContent)) $content .= $belowtitle; else $content .= "<span style=\"font-size: 85%; font-style: italic; color: #666; \">".getMLText('owner').": <b>".htmlspecialchars($owner->getFullName())."</b>, ".getMLText('creation_date').": <b>".getReadableDate($document->getDate())."</b>, ".getMLText('version')." <b>".$version."</b> - <b>".getReadableDate($latestContent->getDate())."</b>".($document->expires() ? ", ".getMLText('expires').": <b>".getReadableDate($document->getExpires())."</b>" : "")."</span>"; if($comment) { $content .= "<br /><span style=\"font-size: 85%;\">".htmlspecialchars($comment)."</span>"; } if($categories = $document->getCategories()) { $content .= "<br />"; foreach($categories as $category) { $color = substr(md5($category->getName()), 0, 6); $content .= "<span class=\"badge\" style=\"background-color: #".$color."; color: #".self::getContrastColor($color).";\">".$category->getName()."</span> "; } } if(!empty($extracontent['bottom_title'])) $content .= $extracontent['bottom_title']; $content .= "</td>\n"; if(!empty($extracontent['columns'])) { foreach($extracontent['columns'] as $col) $content .= '<td>'.$col.'</td>'; } $content .= "<td nowrap>"; $content .= $this->documentListRowStatus($latestContent); $content .= "</td>"; $content .= "<td>"; $content .= $this->documentListRowAction($document, $previewer, $skipcont, $version, $extracontent); $content .= "</td>"; if(!empty($extracontent['columns_last'])) { foreach($extracontent['columns_last'] as $col) $content .= '<td>'.$col.'</td>'; } if(!$skipcont) $content .= $this->documentListRowEnd($document); } return $content; } /* }}} */ /** * Start the row for a folder in list of documents and folders * * This method creates the starting tr tag for a new table row containing * a folder list entry. The tr tag contains various attributes which are * used for removing the table line and to make drap&drop work. * * id=table-row-folder-<id> : used for identifying the row when removing the table * row after deletion of the folder by clicking on the delete button in that table * row. * data-droptarget=folder_<id> : identifies the folder represented by this row * when it used as a target of the drag&drop operation. * If an element (either a file or a dragged item) is dropped on this row, the * data-droptarget will be evaluated to identify the underlying dms object. * Dropping a file on a folder will upload that file into the folder. Droping * an item (which is currently either a document or a folder) from the page will * move that item into the folder. * rel=folder_<id> : This data is put into drag data when a drag starts. When the * item is dropped on some other item this data will identify the source object. * The attributes data-droptarget and rel are usually equal. At least there is * currently no scenario where they are different. * formtoken=<token> : token made of key 'movefolder' * formtoken is also placed in the drag data just like the value of attibute 'rel'. * This is always set to a value made of 'movefolder'. * data-uploadformtoken=<token> : token made of key 'adddocument' * class=table-row-folder : The class must have a class named 'table-row-folder' in * order to be draggable and to extract the drag data from the attributes 'rel' and * 'formtoken' * * @param object $folder * @return string starting tr tag for a table */ function folderListRowStart($folder, $class='') { /* {{{ */ if($class) { if($class == 'error') $class = 'table-danger'; else $class = 'table-'.$class; } return "<tr id=\"table-row-folder-".$folder->getID()."\" draggable=\"true\" data-droptarget=\"folder_".$folder->getID()."\" rel=\"folder_".$folder->getID()."\" class=\"folder table-row-folder droptarget".($class ? ' '.$class : '')."\" data-uploadformtoken=\"".createFormKey('')."\" formtoken=\"".createFormKey('')."\" data-name=\"".htmlspecialchars($folder->getName(), ENT_QUOTES)."\">"; } /* }}} */ function folderListRowEnd($folder) { /* {{{ */ return "</tr>\n"; } /* }}} */ function folderListRowStatus($subFolder) { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; $showtree = $this->params['showtree']; $enableRecursiveCount = $this->params['enableRecursiveCount']; $maxRecursiveCount = $this->params['maxRecursiveCount']; $content = "<div style=\"font-size: 85%;\">"; if($enableRecursiveCount) { if($user->isAdmin()) { /* No need to check for access rights in countChildren() for * admin. So pass 0 as the limit. */ $cc = $subFolder->countChildren($user, 0); if($cc['folder_count']) $content .= '<i class="fa fa-folder" title="'.getMLText("folders").'"></i> '.$cc['folder_count']."<br />"; if($cc['document_count']) $content .= '<i class="fa fa-file" title="'.getMLText("documents").'"></i> '.$cc['document_count']; } else { $cc = $subFolder->countChildren($user, $maxRecursiveCount); if($maxRecursiveCount > 5000) $rr = 100.0; else $rr = 10.0; if($cc['folder_count']) $content .= '<i class="fa fa-folder" title="'.getMLText("folders").'"></i> '.(!$cc['folder_precise'] ? '~'.(round($cc['folder_count']/$rr)*$rr) : $cc['folder_count'])."<br />"; if($cc['document_count']) $content .= '<i class="fa fa-file" title="'.getMLText("documents").'"></i> '.(!$cc['document_precise'] ? '~'.(round($cc['document_count']/$rr)*$rr) : $cc['document_count']); } } else { /* FIXME: the following is very inefficient for just getting the number of * subfolders and documents. Making it more efficient is difficult, because * the access rights need to be checked. */ $subsub = $subFolder->getSubFolders(); $subsub = SeedDMS_Core_DMS::filterAccess($subsub, $user, M_READ); $subdoc = $subFolder->getDocuments(); $subdoc = SeedDMS_Core_DMS::filterAccess($subdoc, $user, M_READ); if(count($subsub)) $content .= '<i class="fa fa-folder" title="'.getMLText("folders").'"></i> '.count($subsub)."<br />"; if(count($subdoc)) $content .= '<i class="fa fa-file" title="'.getMLText("documents").'"></i> '.count($subdoc); } $content .= "</div>"; return $content; } /* }}} */ function folderListRowAction($subFolder, $skipcont=false, $extracontent=array()) { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; // $folder = $this->params['folder']; $showtree = $this->params['showtree']; $enableRecursiveCount = $this->params['enableRecursiveCount']; $maxRecursiveCount = $this->params['maxRecursiveCount']; $enableClipboard = $this->params['enableclipboard']; $accessop = $this->params['accessobject']; $onepage = $this->params['onepage']; $content = ''; $content .= "<div class=\"list-action\">"; $actions = array(); if(!empty($extracontent['begin_action_list'])) $content .= $extracontent['begin_action_list']; $subFolderAccessMode = $subFolder->getAccessMode($user); if ($accessop->check_view_access('RemoveFolder')) { if($subFolderAccessMode >= M_ALL) { $actions['remove_folder'] = $this->printDeleteFolderButton($subFolder, 'splash_rm_folder', true); } else { $actions['remove_folder'] = '<span style="padding: 2px; color: #CCC;"><i class="fa fa-remove"></i></span>'; } } if($subFolderAccessMode >= M_READWRITE) { $actions['edit_folder'] = '<a class_="btn btn-mini" href="'.$this->params['settings']->_httpRoot.'out/out.EditFolder.php?folderid='.$subFolder->getID().'" title="'.getMLText("edit_folder_props").'"><i class="fa fa-edit"></i></a>'; } else { $content .= '<span style="padding: 2px; color: #CCC;"><i class="fa fa-edit"></i></span>'; } if($subFolderAccessMode >= M_READWRITE) { $actions['folder_access'] = $this->printAccessButton($subFolder, true); } if($enableClipboard) { $actions['add_to_clipboard'] = '<a class="addtoclipboard" rel="F'.$subFolder->getID().'" msg="'.getMLText('splash_added_to_clipboard').'" title="'.getMLText("add_to_clipboard").'"><i class="fa fa-copy"></i></a>'; } if($onepage) $actions['view_folder'] = '<a href="'.$this->params['settings']->_httpRoot.'out/out.ViewFolder.php?folderid='.$subFolder->getID().'" title="'.getMLText("view_folder").'"><i class="fa fa-eye"></i></a>'; /* Do not use $this->callHook() because $menuitems must be returned by the the * first hook and passed to next hook. $this->callHook() will just pass * the menuitems to each single hook. Hence, the last hook will win. */ $hookObjs = $this->getHookObjects(); foreach($hookObjs as $hookObj) { if (method_exists($hookObj, 'folderRowAction')) { $actions = $hookObj->folderRowAction($this, $folder, $actions); } } foreach($actions as $action) { if(is_string($action)) $content .= $action; } if(!empty($extracontent['end_action_list'])) $content .= $extracontent['end_action_list']; $content .= "</div>"; return $content; } /* }}} */ function folderListRow($subFolder, $skipcont=false, $extracontent=array()) { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; // $folder = $this->params['folder']; $showtree = $this->params['showtree']; $enableRecursiveCount = $this->params['enableRecursiveCount']; $maxRecursiveCount = $this->params['maxRecursiveCount']; $enableClipboard = $this->params['enableclipboard']; $accessop = $this->params['accessobject']; $onepage = $this->params['onepage']; if(!$subFolder) return ''; $owner = $subFolder->getOwner(); $comment = $subFolder->getComment(); if (strlen($comment) > 150) $comment = substr($comment, 0, 147) . "..."; if($ec = $this->callHook('folderListRowExtraContent', $subFolder)) $extracontent = array_merge($extracontent, $ec); $content = ''; if(!$skipcont) $content .= $this->folderListRowStart($subFolder); $content .= "<td><a draggable=\"false\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=".$subFolder->getID()."&showtree=".$showtree."\"><img draggable=\"false\" src=\"".$this->getMimeIcon(".folder")."\" width=\"24\" height=\"24\" border=0></a></td>\n"; if($onepage) $content .= "<td class=\"wordbreak\" style=\"cursor: pointer;\">" . "<b title=\"Id:".$subFolder->getId()."\">".htmlspecialchars($subFolder->getName())."</b>"; else $content .= "<td class=\"wordbreak\"><a draggable=\"false\" href=\"".$this->params['settings']->_httpRoot."out/out.ViewFolder.php?folderid=".$subFolder->getID()."&showtree=".$showtree."\">" . htmlspecialchars($subFolder->getName()) . "</a>"; if(isset($extracontent['below_title'])) $content .= $extracontent['below_title']; $content .= "<br /><span style=\"font-size: 85%; font-style: italic; color: #666;\">".getMLText('owner').": <b>".htmlspecialchars($owner->getFullName())."</b>, ".getMLText('creation_date').": <b>".getReadableDate($subFolder->getDate())."</b></span>"; if($comment) { $content .= "<br /><span style=\"font-size: 85%;\">".htmlspecialchars($comment)."</span>"; } if(isset($extracontent['bottom_title'])) $content .= $extracontent['bottom_title']; $content .= "</td>\n"; // $content .= "<td>".htmlspecialchars($owner->getFullName())."</td>"; $content .= "<td colspan=\"1\" nowrap>"; $content .= $this->folderListRowStatus($subFolder); $content .= "</td>"; $content .= "<td>"; $content .= $this->folderListRowAction($subFolder, $skipcont, $extracontent); $content .= "</td>"; if(!$skipcont) $content .= $this->folderListRowEnd($subFolder); return $content; } /* }}} */ function show(){ /* {{{ */ parent::show(); } /* }}} */ function error(){ /* {{{ */ parent::error(); $dms = $this->params['dms']; $user = $this->params['user']; $pagetitle = $this->params['pagetitle']; $errormsg = $this->params['errormsg']; $plain = $this->params['plain']; $noexit = $this->params['noexit']; if(!$plain) { $this->htmlStartPage($pagetitle); $this->globalNavigation(); $this->contentStart(); } $html = ''; $html .= "<h4>".getMLText('error')."!</h4>"; $html .= htmlspecialchars($errormsg); $this->errorMsg($html); print "<div><button class=\"btn history-back\">".getMLText('back')."</button></div>"; $this->contentEnd(); $this->htmlEndPage(); add_log_line(" UI::exitError error=".$errormsg." pagetitle=".$pagetitle, PEAR_LOG_ERR); if($noexit) return; exit; } /* }}} */ /** * Return HTML Template for jumploader * * @param string $uploadurl URL where post data is send * @param integer $folderid id of folder where document is saved * @param integer $maxfiles maximum number of files allowed to upload * @param array $fields list of post fields */ function getFineUploaderTemplate() { /* {{{ */ return ' <script type="text/template" id="qq-template"> <div class="qq-uploader-selector qq-uploader" qq-drop-area-text="'.getMLText('drop_files_here').'"> <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container"> <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div> </div> <div class="input-group"> <div class="form-control qq-upload-drop-area-selector qq-upload-drop-area" _qq-hide-dropzone> <span class="qq-upload-drop-area-text-selector"></span> </div> <div class="input-group-append"> <span class="btn btn-secondary qq-upload-button-selector qq-upload-button">'.getMLText('choose_target_file').'…</span> </div> </div> <span class="qq-drop-processing-selector qq-drop-processing"> <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span> </span> <ul class="qq-upload-list-selector qq-upload-list unstyled" aria-live="polite" aria-relevant="additions removals"> <li> <div class="progress qq-progress-bar-container-selector"> <div class="bar qq-progress-bar-selector qq-progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> </div> <span class="qq-upload-spinner-selector qq-upload-spinner"></span> <img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale> <span class="qq-upload-file-selector qq-upload-file"></span> <span class="qq-upload-size-selector qq-upload-size"></span> <button class="btn btn-sm btn-danger qq-btn qq-upload-cancel-selector qq-upload-cancel">Cancel</button> <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span> </li> </ul> <dialog class="qq-alert-dialog-selector"> <div class="qq-dialog-message-selector"></div> <div class="qq-dialog-buttons"> <button class="btn btn-sm btn-secondary qq-cancel-button-selector">Cancel</button> </div> </dialog> <dialog class="qq-confirm-dialog-selector"> <div class="qq-dialog-message-selector"></div> <div class="qq-dialog-buttons"> <button class="btn btn-sm btn-secondary qq-cancel-button-selector">Cancel</button> <button class="btn btn-sm btn-primary qq-ok-button-selector">Ok</button> </div> </dialog> <dialog class="qq-prompt-dialog-selector"> <div class="qq-dialog-message-selector"></div> <input type="text"> <div class="qq-dialog-buttons"> <button class="btn qq-cancel-button-selector">Cancel</button> <button class="btn qq-ok-button-selector">Ok</button> </div> </dialog> </div> </script> '; } /* }}} */ /** * Output HTML Code for Fine Uploader * * @param string $uploadurl URL where post data is send * @param integer $folderid id of folder where document is saved * @param integer $maxfiles maximum number of files allowed to upload * @param array $fields list of post fields */ function printFineUploaderHtml($prefix='userfile') { /* {{{ */ echo self::getFineUploaderHtml($prefix); } /* }}} */ /** * Get HTML Code for Fine Uploader * * @param string $uploadurl URL where post data is send * @param integer $folderid id of folder where document is saved * @param integer $maxfiles maximum number of files allowed to upload * @param array $fields list of post fields */ function getFineUploaderHtml($prefix='userfile') { /* {{{ */ $html = '<div id="'.$prefix.'-fine-uploader"></div> <input type="hidden" '.($prefix=='userfile' ? 'class="do_validate" ' : '').'id="'.$prefix.'-fine-uploader-uuids" name="'.$prefix.'-fine-uploader-uuids" value="" /> <input type="hidden" id="'.$prefix.'-fine-uploader-names" name="'.$prefix.'-fine-uploader-names" value="" />'; return $html; } /* }}} */ /** * Output Javascript Code for fine uploader * * @param string $uploadurl URL where post data is send * @param integer $folderid id of folder where document is saved * @param integer $maxfiles maximum number of files allowed to upload * @param array $fields list of post fields */ function printFineUploaderJs($uploadurl, $partsize=0, $maxuploadsize=0, $multiple=true, $prefix='userfile', $formname='form1') { /* {{{ */ ?> $(document).ready(function() { <?php echo $prefix; ?>uploader = new qq.FineUploader({ debug: false, autoUpload: false, multiple: <?php echo ($multiple ? 'true' : 'false'); ?>, element: $('#<?php echo $prefix; ?>-fine-uploader')[0], template: 'qq-template', request: { endpoint: '<?php echo $uploadurl."?formkey=".md5($this->params['settings']->_encryptionKey.'uploadchunks'); ?>' }, <?php echo ($maxuploadsize > 0 ? ' validation: { sizeLimit: '.$maxuploadsize.' }, ' : ''); ?> chunking: { enabled: true, <?php echo $partsize ? 'partSize: '.(int)$partsize.",\n" : ''; ?> mandatory: true }, messages: { sizeError: '{file} is too large, maximum file size is {sizeLimit}.' }, callbacks: { onComplete: function(id, name, json, xhr) { }, onAllComplete: function(succeeded, failed) { var uuids = Array(); var names = Array(); for (var i = 0; i < succeeded.length; i++) { uuids.push(this.getUuid(succeeded[i])) names.push(this.getName(succeeded[i])) } $('#<?php echo $prefix; ?>-fine-uploader-uuids').val(uuids.join(';')); $('#<?php echo $prefix; ?>-fine-uploader-names').val(names.join(';')); /* Run upload only if all files could be uploaded */ if(succeeded.length > 0 && failed.length == 0) document.getElementById('<?= $formname ?>').submit(); }, onError: function(id, name, reason, xhr) { noty({ text: reason, type: 'error', dismissQueue: true, layout: 'topRight', theme: 'defaultTheme', timeout: 3500, }); } } }); }); <?php } /* }}} */ /** * Output a protocol * * @param object $attribute attribute */ protected function printProtocol($latestContent, $type="") { /* {{{ */ $dms = $this->params['dms']; $document = $latestContent->getDocument(); $accessop = $this->params['accessobject']; ?> <legend><?php printMLText($type.'_log'); ?></legend> <table class="table table-sm"> <tr><th><?php printMLText('name'); ?></th><th><?php printMLText('last_update'); ?>, <?php printMLText('comment'); ?></th><th><?php printMLText('status'); ?></th></tr> <?php switch($type) { case "review": $statusList = $latestContent->getReviewStatus(10); break; case "approval": $statusList = $latestContent->getApprovalStatus(10); break; default: $statusList = array(); } foreach($statusList as $rec) { echo "<tr>"; echo "<td>"; switch ($rec["type"]) { case 0: // individual. $required = $dms->getUser($rec["required"]); if (!is_object($required)) { $reqName = getMLText("unknown_user")." '".$rec["required"]."'"; } else { $reqName = htmlspecialchars($required->getFullName()." (".$required->getLogin().")"); } break; case 1: // Approver is a group. $required = $dms->getGroup($rec["required"]); if (!is_object($required)) { $reqName = getMLText("unknown_group")." '".$rec["required"]."'"; } else { $reqName = "<i>".htmlspecialchars($required->getName())."</i>"; } break; } echo $reqName; echo "</td>"; echo "<td>"; echo "<i style=\"font-size: 80%;\">".getLongReadableDate($rec['date'])." - "; $updateuser = $dms->getUser($rec["userID"]); if(!is_object($updateuser)) echo getMLText("unknown_user"); else echo htmlspecialchars($updateuser->getFullName()." (".$updateuser->getLogin().")"); echo "</i>"; if($rec['comment']) echo "<br />".htmlspecialchars($rec['comment']); switch($type) { case "review": if($accessop->check_controller_access('Download', array('action'=>'review'))) if($rec['file']) { echo "<br />"; echo "<a href=\"".$this->params['settings']->_httpRoot."op/op.Download.php?documentid=".$document->getID()."&reviewlogid=".$rec['reviewLogID']."\" class=\"btn btn-mini\"><i class=\"fa fa-download\"></i> ".getMLText('download')."</a>"; } break; case "approval": if($accessop->check_controller_access('Download', array('action'=>'approval'))) if($rec['file']) { echo "<br />"; echo "<a href=\"".$this->params['settings']->_httpRoot."op/op.Download.php?documentid=".$document->getID()."&approvelogid=".$rec['approveLogID']."\" class=\"btn btn-mini\"><i class=\"fa fa-download\"></i> ".getMLText('download')."</a>"; } break; } echo "</td>"; echo "<td>"; switch($type) { case "review": echo getReviewStatusText($rec["status"]); break; case "approval": echo getApprovalStatusText($rec["status"]); break; default: } echo "</td>"; echo "</tr>"; } ?> </table> <?php } /* }}} */ protected function printWorkflowLog($wkflogs) { /* {{{ */ echo "<table class=\"table table-condensed table-sm\"><thead>"; echo "<th>".getMLText('workflow')."</th><th>".getMLText('date')."</th><th>".getMLText('action')."</th><th>".getMLText('user')."</th><th>".getMLText('comment')."</th></tr>\n"; echo "</thead><tbody>"; foreach($wkflogs as $wkflog) { echo "<tr>"; echo "<td>".htmlspecialchars($wkflog->getWorkflow()->getName())."</td>"; echo "<td>".getLongReadableDate($wkflog->getDate())."</td>"; echo "<td>".htmlspecialchars(getMLText('action_'.strtolower($wkflog->getTransition()->getAction()->getName()), array(), $wkflog->getTransition()->getAction()->getName()))."</td>"; $loguser = $wkflog->getUser(); echo "<td>".htmlspecialchars($loguser->getFullName())."</td>"; echo "<td>".htmlspecialchars($wkflog->getComment())."</td>"; echo "</tr>"; } print "</tbody>\n</table>\n"; } /* }}} */ /** * Show progressbar * * @param double $value value * @param double $max 100% value */ protected function getProgressBar($value, $max=100.0) { /* {{{ */ if($max > $value) { $used = (int) ($value/$max*100.0+0.5); $free = 100-$used; } else { $free = 0; $used = 100; } $html = ' <div class="progress"> <div class="bar bar-danger bg-danger" style="width: '.$used.'%;"></div> <div class="bar bar-success bg-success" style="width: '.$free.'%;"></div> </div>'; return $html; } /* }}} */ /** * Output a timeline for a document * * @param object $document document */ protected function printTimelineJs($timelineurl, $height=300, $start='', $end='', $skip=array(), $onselect="") { /* {{{ */ if(!$timelineurl) return; ?> var timeline; var data; // specify options var options = { 'width': '100%', 'height': '100%', <?php if($start) { $tmp = explode('-', $start); echo "\t\t\t'min': new Date(".$tmp[0].", ".($tmp[1]-1).", ".$tmp[2]."),\n"; } if($end) { $tmp = explode('-', $end); echo "'\t\t\tmax': new Date(".$tmp[0].", ".($tmp[1]-1).", ".$tmp[2]."),\n"; } ?> 'editable': false, 'selectable': true, 'style': 'box', 'locale': '<?php echo $this->params['session']->getLanguage() ?>' }; $(document).ready(function () { // Instantiate our timeline object. timeline = new links.Timeline(document.getElementById('timeline'), options); <?php if($onselect): ?> links.events.addListener(timeline, 'select', <?= $onselect ?>); <?php endif; ?> $.getJSON( '<?php echo $timelineurl ?>', function(data) { $.each( data, function( key, val ) { val.start = new Date(val.start); }); timeline.draw(data); } ); }); <?php } /* }}} */ protected function printTimelineHtml($height) { /* {{{ */ ?> <div id="timeline" style="height: <?php echo $height ?>px;"></div> <?php } /* }}} */ protected function printTimeline($timelineurl, $height=300, $start='', $end='', $skip=array()) { /* {{{ */ echo "<script type=\"text/javascript\">\n"; $this->printTimelineJs($timelineurl, $height, $start, $end, $skip); echo "</script>"; $this->printTimelineHtml($height); } /* }}} */ public function printPopupBox($title, $content, $ret=false) { /* {{{ */ $id = md5(uniqid()); /* $this->addFooterJS(' $("body").on("click", "span.openpopupbox", function(e) { $(""+$(e.target).data("href")).toggle(); // $("div.popupbox").toggle(); }); '); */ $html = ' <span class="openpopupbox" data-href="#'.$id.'">'.$title.'</span> <div id="'.$id.'" class="popupbox" style="display: none;">'.$content.'<span class="closepopupbox"><i class="fa fa-remove"></i></span> </div>'; if($ret) return $html; else echo $html; } /* }}} */ public function printAccordion($title, $content, $open=false) { /* {{{ */ $id = substr(md5(uniqid()), 0, 4); ?> <div class="accordion mb-4" id="accordion<?php echo $id; ?>"> <div class="card"> <div class="card-header" id="accordionheader<?php echo $id; ?>"> <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion<?php echo $id; ?>" data-target="#collapse<?php echo $id; ?>"<?= $open ? ' aria-expanded="true"' : '' ?>> <?php echo $title; ?> </a> </div> <div id="collapse<?php echo $id; ?>" class="collapse<?= $open ? ' show' : '' ?>" data-parent="accordion<?php echo $id; ?>"> <div class="card-body"> <?php echo $content; ?> </div> </div> </div> </div> <?php } /* }}} */ public function printAccordion2($title, $content) { /* {{{ */ $id = substr(md5(uniqid()), 0, 4); ?> <div class="accordion2" id="accordion<?php echo $id; ?>"> <a class="accordion2-toggle" data-toggle="collapse" data-parent="#accordion<?php echo $id; ?>" data-target="#collapse<?php echo $id; ?>"> <?php $this->contentHeading($title); ?> </a> <div id="collapse<?php echo $id; ?>" class="collapse" data-parent="accordion<?php echo $id; ?>"> <?php echo $content; ?> </div> </div> <?php } /* }}} */ } class_alias('SeedDMS_Theme_Style', 'SeedDMS_Bootstrap_Style');