Commit 596c2e02e09405043b0c2c92d95d7d9c92f72c98

Authored by Brad Shuttleworth
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
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 '&nbsp';
  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');
... ...