Commit 596c2e02e09405043b0c2c92d95d7d9c92f72c98
1 parent
37b14654
made help work across multiple languages (KTS-662)
git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5427 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
5 changed files
with
226 additions
and
104 deletions
HISTORY.txt
| ... | ... | @@ -10,6 +10,7 @@ Features: |
| 10 | 10 | |
| 11 | 11 | Fixes: |
| 12 | 12 | |
| 13 | + - Made help able to work across multiple languages | |
| 13 | 14 | - KTS-972 Owner, Everyone and Authenticated weren't being respected by browse |
| 14 | 15 | and search |
| 15 | 16 | - KTS-959 Documents weren't properly purged from the cache on change. | ... | ... |
help.php
| ... | ... | @@ -71,20 +71,76 @@ class HelpDispatcher extends KTStandardDispatcher { |
| 71 | 71 | function do_main() { |
| 72 | 72 | // store referer |
| 73 | 73 | $sBackKey = KTUtil::arrayGet($_REQUEST, 'back_key', false); |
| 74 | + $sSubPath = KTUtil::arrayGet($_SERVER, 'PATH_INFO'); | |
| 75 | + | |
| 76 | + // we want to be able to say "i left the system at point x. go back there" | |
| 74 | 77 | if(!$sBackKey) { |
| 75 | 78 | $sReferer = KTUtil::arrayGet($_SERVER ,'HTTP_REFERER'); |
| 76 | 79 | $sBackKey = KTUtil::randomString(); |
| 77 | 80 | $_SESSION[$sBackKey] = $sReferer; |
| 78 | 81 | } |
| 79 | 82 | |
| 80 | - $pathinfo = KTUtil::arrayGet($_SERVER, 'PATH_INFO'); | |
| 81 | - if (empty($pathinfo)) { | |
| 83 | + // no path specified | |
| 84 | + if (empty($sSubPath)) { | |
| 82 | 85 | $this->oPage->setTitle(_kt('No help page specified.')); |
| 83 | 86 | $this->oPage->addError(_kt('No help page specified.')); |
| 84 | 87 | return ' '; |
| 85 | 88 | } |
| 86 | 89 | |
| 87 | - $can_edit = Permission::userIsSystemAdministrator($_SESSION['userID']); | |
| 90 | + // simple test to see if this user is active. | |
| 91 | + $bCanEdit = Permission::userIsSystemAdministrator($_SESSION['userID']); | |
| 92 | + | |
| 93 | + global $default; | |
| 94 | + $sLangCode = $default->defaultLanguage; | |
| 95 | + /* | |
| 96 | + now we need to know a few things. | |
| 97 | + 1. can we find this help file? | |
| 98 | + 2. if we can, display it | |
| 99 | + 2.1 images directly | |
| 100 | + 2.2 html wrapped. | |
| 101 | + 3. if now, fail out. | |
| 102 | + | |
| 103 | + this is essentially handled by asking help.inc.php for the | |
| 104 | + subpath we've been given, PLUS THE LANGUAGE, and checking for | |
| 105 | + a PEAR::raiseError. | |
| 106 | + | |
| 107 | + The "Correct" response we care about is a dictionary: | |
| 108 | + | |
| 109 | + { | |
| 110 | + 'is_image': string | |
| 111 | + 'title': string | |
| 112 | + 'body': string | |
| 113 | + } | |
| 114 | + */ | |
| 115 | + | |
| 116 | + $aHelpData = KTHelp::getHelpInfo($sSubPath); | |
| 117 | + | |
| 118 | + if (PEAR::isError($aHelpData)) { | |
| 119 | + $this->oPage->setTitle($aHelpData->getMessage()); | |
| 120 | + $this->oPage->addError($aHelpData->getMessage()); | |
| 121 | + return ' '; | |
| 122 | + } | |
| 123 | + | |
| 124 | + $aLocInfo = KTHelp::_getLocationInfo($sSubPath); | |
| 125 | + | |
| 126 | + if ($aHelpData['is_image']) { | |
| 127 | + KTHelp::outputHelpImage($sSubPath); | |
| 128 | + exit(0); // done. | |
| 129 | + } else { | |
| 130 | + $this->oPage->setTitle($aHelpData['title']); | |
| 131 | + $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => $aHelpData['title']); | |
| 132 | + $oTemplating =& KTTemplating::getSingleton(); | |
| 133 | + $oTemplate = $oTemplating->loadTemplate("ktcore/help_with_edit"); | |
| 134 | + $aTemplateData = array( | |
| 135 | + "context" => $this, | |
| 136 | + "help_body" => $aHelpData['body'], | |
| 137 | + "target_name" => KTUtil::arrayGet($aLocInfo, 'internal'), | |
| 138 | + "back_key" => $sBackKey, | |
| 139 | + 'can_edit' => $bCanEdit, | |
| 140 | + ); | |
| 141 | + return $oTemplate->render($aTemplateData); | |
| 142 | + } | |
| 143 | + /* | |
| 88 | 144 | $help_path = KTHelp::getHelpSubPath($pathinfo); |
| 89 | 145 | |
| 90 | 146 | if ($help_path == false) { |
| ... | ... | @@ -100,7 +156,7 @@ class HelpDispatcher extends KTStandardDispatcher { |
| 100 | 156 | KTHelp::outputHelpImage($help_path); |
| 101 | 157 | } else { |
| 102 | 158 | // not an image, so: |
| 103 | - $aHelpInfo = KTHelp::getHelpFromFile($pathinfo); | |
| 159 | + $aHelpInfo = KTHelp::getHelpFromFile($pathinfo) | |
| 104 | 160 | } |
| 105 | 161 | |
| 106 | 162 | |
| ... | ... | @@ -129,16 +185,7 @@ class HelpDispatcher extends KTStandardDispatcher { |
| 129 | 185 | $this->oPage->setTitle($aHelpInfo['title']); |
| 130 | 186 | $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => $aHelpInfo['title']); |
| 131 | 187 | |
| 132 | - $oTemplating =& KTTemplating::getSingleton(); | |
| 133 | - $oTemplate = $oTemplating->loadTemplate("ktcore/help_with_edit"); | |
| 134 | - $aTemplateData = array( | |
| 135 | - "context" => $this, | |
| 136 | - "help_body" => $aHelpInfo['body'], | |
| 137 | - "target_name" => $_SERVER['PATH_INFO'], | |
| 138 | - "back_key" => $sBackKey, | |
| 139 | - 'can_edit' => $can_edit, | |
| 140 | - ); | |
| 141 | - return $oTemplate->render($aTemplateData); | |
| 188 | + */ | |
| 142 | 189 | } |
| 143 | 190 | |
| 144 | 191 | function do_go_back() { | ... | ... |
lib/help/help.inc.php
| ... | ... | @@ -31,64 +31,7 @@ |
| 31 | 31 | require_once(KT_LIB_DIR . "/database/dbutil.inc"); |
| 32 | 32 | |
| 33 | 33 | class KTHelp { |
| 34 | - | |
| 35 | - function getHelpSubPath($sHelpFile) { | |
| 36 | - if (empty($sHelpFile)) { return false; } | |
| 37 | - $path_segments = explode("/", $sHelpFile); | |
| 38 | - // cannot be empty, must contain at _least_ 1 item. | |
| 39 | - if (empty($path_segments[0])) { | |
| 40 | - $path_segments = array_slice($path_segments,1); | |
| 41 | - } | |
| 42 | - | |
| 43 | - if (empty($path_segments) or (count($path_segments) < 2)) { | |
| 44 | - return false; // FIXME use PEAR::Error | |
| 45 | - } | |
| 46 | - | |
| 47 | - // we now assume that path_segments[0] is the module | |
| 48 | - // path_segments[1..] is the subpath. we need to insert the LANG | |
| 49 | - | |
| 50 | - $lang_code = 'EN'; // FIXME extract the lang from the environ (?) | |
| 51 | - | |
| 52 | - $final_path = array(null,'kthelp', $path_segments[0]); | |
| 53 | - $final_path[] = $lang_code; | |
| 54 | - $final_path = kt_array_merge($final_path, array_slice($path_segments, 1)); | |
| 55 | - | |
| 56 | - $help_path = implode('/',$final_path); | |
| 57 | - | |
| 58 | - return $help_path; | |
| 59 | - } | |
| 60 | - | |
| 61 | - function getHelpFromFile($sHelpFile) { | |
| 62 | - if (empty($sHelpFile)) { return false; } | |
| 63 | - $help_path = KTHelp::getHelpSubPath($sHelpFile); | |
| 64 | - | |
| 65 | - $fspath = KT_DIR . $help_path; // FIXME use OS.path_sep equivalent? | |
| 66 | - | |
| 67 | - if (!file_exists($fspath)) { | |
| 68 | - return false; | |
| 69 | - } | |
| 70 | - | |
| 71 | - if (KTHelp::isImageFile($help_path)) { | |
| 72 | - return false; // can't - not what users expect. | |
| 73 | - } | |
| 74 | - | |
| 75 | - // now we ASSUME its html: we'll fail anyway if we aren't. | |
| 76 | - $handle = fopen($fspath, "r"); | |
| 77 | - $contents = fread($handle, filesize($fspath)); | |
| 78 | - fclose($handle); | |
| 79 | - | |
| 80 | - $info = KTHelp::_parseHTML($contents); | |
| 81 | - | |
| 82 | - $body = KTUtil::arrayGet($info,'body'); | |
| 83 | - if (empty($body)) { | |
| 84 | - return false; | |
| 85 | - } | |
| 86 | - | |
| 87 | - $info['name'] = $help_path; // set so we can save into db if needed. | |
| 88 | - | |
| 89 | - return $info; | |
| 90 | - } | |
| 91 | - | |
| 34 | + | |
| 92 | 35 | // world's simplest (and possibly worst) regex-split. |
| 93 | 36 | function _parseHTML($sHTML) { |
| 94 | 37 | $title_array = preg_split('#</?title>#',$sHTML,-1,PREG_SPLIT_NO_EMPTY); |
| ... | ... | @@ -107,11 +50,10 @@ class KTHelp { |
| 107 | 50 | return $res; |
| 108 | 51 | } |
| 109 | 52 | |
| 110 | - function isImageFile($sHelpPath) { | |
| 111 | - // from pluginutil.inc.php | |
| 112 | - $fspath = KT_DIR . $sHelpPath; | |
| 113 | - | |
| 114 | - $pi = pathinfo($fspath); | |
| 53 | + // $sFSPath : filesystem path for the resource. | |
| 54 | + // return true or false | |
| 55 | + function isImageFile($sFSPath) { | |
| 56 | + $pi = pathinfo($sFSPath); | |
| 115 | 57 | $mime_type = ""; |
| 116 | 58 | $sExtension = KTUtil::arrayGet($pi, 'extension'); |
| 117 | 59 | if (!empty($sExtension)) { |
| ... | ... | @@ -125,9 +67,18 @@ class KTHelp { |
| 125 | 67 | return false; |
| 126 | 68 | } |
| 127 | 69 | |
| 128 | - function outputHelpImage($sHelpPath) { | |
| 129 | - $fspath = KT_DIR . $sHelpPath; | |
| 130 | - | |
| 70 | + // output the help image referred to by the subpath | |
| 71 | + function outputHelpImage($sSubPath) { | |
| 72 | + // FIXME there are error cases here ... | |
| 73 | + $aPathInfo = KTHelp::_getLocationInfo($sSubPath); | |
| 74 | + if (PEAR::isError($aPathInfo)) { return $aPathInfo; } // gets caught further up the stack | |
| 75 | + | |
| 76 | + $pi = pathinfo($aPathInfo['external']); | |
| 77 | + $mime_type = ""; | |
| 78 | + $sExtension = KTUtil::arrayGet($pi, 'extension'); | |
| 79 | + if (!empty($sExtension)) { | |
| 80 | + $mime_type = DBUtil::getOneResultKey(array("SELECT mimetypes FROM " . KTUtil::getTableName('mimetypes') . " WHERE LOWER(filetypes) = ?", $sExtension), "mimetypes"); | |
| 81 | + } | |
| 131 | 82 | |
| 132 | 83 | header("Content-Type: $mime_type"); |
| 133 | 84 | header("Content-Length: " . filesize($fspath)); |
| ... | ... | @@ -135,6 +86,144 @@ class KTHelp { |
| 135 | 86 | exit(0); |
| 136 | 87 | } |
| 137 | 88 | |
| 89 | + /* | |
| 90 | + input: | |
| 91 | + sSubPath : the path in the form "plugin/lower-level-file" | |
| 92 | + sLangCode : the language code in the form "en_US" | |
| 93 | + | |
| 94 | + returns a dictionary | |
| 95 | + { | |
| 96 | + 'is_image': string | |
| 97 | + 'title': string | |
| 98 | + 'body': string | |
| 99 | + } | |
| 100 | + */ | |
| 101 | + function getHelpInfo($sSubPath, $sLangCode = null) { | |
| 102 | + $aInfo = array( | |
| 103 | + 'is_image' => false, | |
| 104 | + 'title' => null, | |
| 105 | + 'body' => null, | |
| 106 | + 'help_id' => null, | |
| 107 | + ); | |
| 108 | + $aPathInfo = KTHelp::_getLocationInfo($sSubPath, $sLangCode); | |
| 109 | + if (PEAR::isError($aPathInfo)) { | |
| 110 | + return $aPathInfo; | |
| 111 | + } | |
| 112 | + | |
| 113 | + // first, check the extension to see if its an image. | |
| 114 | + // failing that, check the DB for an entry (+ return if found) | |
| 115 | + // failing that, check the FS for the entry (+ return if found) | |
| 116 | + // failing that, through an exception. | |
| 117 | + | |
| 118 | + if (KTHelp::isImageFile($aPathInfo['external'])) { | |
| 119 | + $aInfo['is_image'] = true; | |
| 120 | + return $aInfo; | |
| 121 | + } | |
| 122 | + | |
| 123 | + // check DB | |
| 124 | + $oReplacement =& KTHelpReplacement::getByName($aPathInfo['internal']); | |
| 125 | + if (!PEAR::isError($oReplacement)) { | |
| 126 | + $aInfo['title'] = $oReplacement->getTitle(); | |
| 127 | + $aInfo['body'] = $oReplacement->getDescription(); | |
| 128 | + $aInfo['help_id'] = $oReplacement->getID(); | |
| 129 | + return $aInfo; | |
| 130 | + } | |
| 131 | + | |
| 132 | + // check FS | |
| 133 | + if (!file_exists($aPathInfo['external'])) { | |
| 134 | + return PEAR::raiseError(_kt("Unable to locate the requested help file for this language.")); | |
| 135 | + } | |
| 136 | + | |
| 137 | + // so it might exist in some form. | |
| 138 | + $contents = file_get_contents($aPathInfo['external']); | |
| 139 | + | |
| 140 | + $aData = KTHelp::_parseHTML($contents); | |
| 141 | + | |
| 142 | + $aInfo['body'] = KTUtil::arrayGet($aData,'body'); | |
| 143 | + if (empty($aInfo['body'])) { | |
| 144 | + return PEAR::raiseError(_kt("The requested help language has no contents.")); | |
| 145 | + } | |
| 146 | + $aInfo['title'] = KTUtil::arrayGet($aData, 'title', _kt("Untitled Help File")); | |
| 147 | + | |
| 148 | + return $aInfo; | |
| 149 | + } | |
| 150 | + | |
| 151 | + function _getLocationInfo($sSubPath, $sLangCode = null) { | |
| 152 | + // FIXME use a cheap cache here? is it even worth it? | |
| 153 | + $aInfo = array( | |
| 154 | + 'subpath' => null, | |
| 155 | + 'internal' => null, | |
| 156 | + 'external' => null, | |
| 157 | + ); | |
| 158 | + | |
| 159 | + $oHelpReg =& KTHelpRegistry::getSingleton(); | |
| 160 | + | |
| 161 | + if (is_null($sLangCode)) { | |
| 162 | + global $default; | |
| 163 | + $sLangCode = $default->defaultLanguage; | |
| 164 | + } | |
| 165 | + | |
| 166 | + $aParts = explode('/', $sSubPath); | |
| 167 | + | |
| 168 | + if (count($aParts) < 2) { | |
| 169 | + return PEAR::raiseError(_kt("Too few parts to the requested help location.")); | |
| 170 | + } | |
| 171 | + | |
| 172 | + $sPluginName = $aParts[0]; | |
| 173 | + $sSubLocation = implode('/', array_slice($aParts, 1)); | |
| 174 | + | |
| 175 | + $sInternalName = sprintf("%s/%s/%s", $sPluginName, $sLangCode, $sSubLocation); | |
| 176 | + | |
| 177 | + // this is a pseudo-name. essentially, this maps to the canonical | |
| 178 | + // name of the help file in the database, NOT to the filesystem | |
| 179 | + | |
| 180 | + //$sBaseDir = sprintf("%s/kthelp/%s/%s", KT_DIR, $sPluginName, $sLangCode); | |
| 181 | + $sBaseDir = $oHelpReg->getBaseDir($sPluginName, $sLangCode); | |
| 182 | + | |
| 183 | + if (PEAR::isError($sBaseDir)) { return $sBaseDir; } | |
| 184 | + $sExternalName = sprintf("%s/%s", $sBaseDir, $sSubLocation); | |
| 185 | + | |
| 186 | + $aInfo['subpath'] = $sSubPath; | |
| 187 | + $aInfo['internal'] = $sInternalName; | |
| 188 | + $aInfo['external'] = $sExternalName; | |
| 189 | + | |
| 190 | + return $aInfo; | |
| 191 | + } | |
| 192 | +} | |
| 193 | + | |
| 194 | +class KTHelpRegistry { | |
| 195 | + var $plugin_lang_map; | |
| 196 | + | |
| 197 | + function KTHelpRegistry() { | |
| 198 | + $this->plugin_lang_map = array(); | |
| 199 | + } | |
| 200 | + | |
| 201 | + function &getSingleton () { | |
| 202 | + if (!KTUtil::arrayGet($GLOBALS, 'oKTHelpRegistry')) { | |
| 203 | + $GLOBALS['oKTHelpRegistry'] = new KTHelpRegistry; | |
| 204 | + } | |
| 205 | + | |
| 206 | + return $GLOBALS['oKTHelpRegistry']; | |
| 207 | + } | |
| 208 | + | |
| 209 | + function registerHelp($sPluginName, $sLang, $sBaseDir) { | |
| 210 | + $lang_map = KTUtil::arrayGet($this->plugin_lang_map, $sPluginName, array()); | |
| 211 | + $lang_map[$sLang] = $sBaseDir; | |
| 212 | + $this->plugin_lang_map[$sPluginName] = $lang_map; | |
| 213 | + } | |
| 214 | + | |
| 215 | + function getBaseDir($sPluginName, $sLangCode) { | |
| 216 | + $lang_map = KTUtil::arrayGet($this->plugin_lang_map, $sPluginName); | |
| 217 | + | |
| 218 | + if (is_null($lang_map)) { | |
| 219 | + return PEAR::raiseError(_kt("There is no help available in your language for this plugin")); | |
| 220 | + } | |
| 221 | + $sBaseDir = KTUtil::arrayGet($lang_map, $sLangCode); | |
| 222 | + if (is_null($sBaseDir)) { | |
| 223 | + return PEAR::raiseError(_kt("There is no help available in your language for this plugin")); | |
| 224 | + } | |
| 225 | + return $sBaseDir; | |
| 226 | + } | |
| 138 | 227 | } |
| 139 | 228 | |
| 140 | 229 | ?> | ... | ... |
plugins/ktcore/KTDashlets.php
| ... | ... | @@ -46,15 +46,13 @@ class KTInfoDashlet extends KTBaseDashlet { |
| 46 | 46 | $aHelpInfo = array(); |
| 47 | 47 | $can_edit = Permission::userIsSystemAdministrator($_SESSION['userID']); |
| 48 | 48 | |
| 49 | - $help_path = KTHelp::getHelpSubPath($this->helpLocation); | |
| 50 | - if ($help_path == false) { | |
| 49 | + $help_path = KTHelp::_getLocationInfo($this->helpLocation); | |
| 50 | + if (PEAR::isError($help_path)) { | |
| 51 | 51 | return false; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | // We now check for substitute help files. try to generate an error. |
| 55 | - $oReplacementHelp = KTHelpReplacement::getByName($help_path); | |
| 56 | - | |
| 57 | - $aHelpInfo = KTHelp::getHelpFromFile($this->helpLocation); | |
| 55 | + $aHelpInfo = KTHelp::getHelpInfo($this->helpLocation); | |
| 58 | 56 | |
| 59 | 57 | // NORMAL users never see edit-option. |
| 60 | 58 | if (!$can_edit) { |
| ... | ... | @@ -67,19 +65,6 @@ class KTInfoDashlet extends KTBaseDashlet { |
| 67 | 65 | } |
| 68 | 66 | } |
| 69 | 67 | |
| 70 | - | |
| 71 | - | |
| 72 | - if (!PEAR::isError($oReplacementHelp)) { | |
| 73 | - $aHelpInfo['title'] = $oReplacementHelp->getTitle(); | |
| 74 | - $aHelpInfo['body'] = $oReplacementHelp->getDescription(); | |
| 75 | - $this->help_id = $oReplacementHelp->getId(); | |
| 76 | - | |
| 77 | - } else { | |
| 78 | - $this->help_id = null; | |
| 79 | - } | |
| 80 | - | |
| 81 | - if (empty($aHelpInfo)) { return false; } | |
| 82 | - | |
| 83 | 68 | $this->aHelpInfo = $aHelpInfo; |
| 84 | 69 | $this->canEdit = $can_edit; |
| 85 | 70 | |
| ... | ... | @@ -97,7 +82,7 @@ class KTInfoDashlet extends KTBaseDashlet { |
| 97 | 82 | 'body' => $this->aHelpInfo['body'], |
| 98 | 83 | 'can_edit' => $this->canEdit, |
| 99 | 84 | 'target_name' => $this->helpLocation, |
| 100 | - 'help_id' => $this->help_id, | |
| 85 | + 'help_id' => $this->aHelpInfo['help_id'], | |
| 101 | 86 | ); |
| 102 | 87 | return $oTemplate->render($aTemplateData); |
| 103 | 88 | } | ... | ... |
plugins/ktcore/admin/manageHelp.php
| ... | ... | @@ -126,19 +126,19 @@ class ManageHelpDispatcher extends KTAdminDispatcher { |
| 126 | 126 | |
| 127 | 127 | function do_customise() { |
| 128 | 128 | $name = KTUtil::arrayGet($_REQUEST, 'name'); |
| 129 | - $subname = KTHelp::getHelpSubPath($name); | |
| 130 | - $oHelpReplacement = KTHelpReplacement::getByName($subname); | |
| 129 | + $aPathInfo = KTHelp::_getLocationInfo($name); | |
| 130 | + $oHelpReplacement = KTHelpReplacement::getByName($aPathInfo['internal']); | |
| 131 | 131 | // XXX: Check against "already exists" |
| 132 | 132 | |
| 133 | 133 | //var_dump($name); |
| 134 | 134 | |
| 135 | 135 | if (!PEAR::isError($oHelpReplacement)) { |
| 136 | 136 | // Already exists... |
| 137 | - return $this->errorRedirectTo('editReplacement', _kt('Replacement already exists.'),'id=' . $oHelpReplacement->getId()); | |
| 137 | + return $this->successRedirectTo('editReplacement', _kt('Replacement already exists. Editing the existing copy instead of replacing.'),'id=' . $oHelpReplacement->getId()); | |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | - $info = KTHelp::getHelpFromFile($name); | |
| 141 | - if ($info === false) { | |
| 140 | + $info = KTHelp::getHelpInfo($name); | |
| 141 | + if (PEAR::isError($info)) { | |
| 142 | 142 | $info = array('name' => $name); |
| 143 | 143 | $info['title'] = _kt('New Help File'); |
| 144 | 144 | $info['body'] = _kt('New Help File'); | ... | ... |