Commit 95637c2003dea3d8c1ffdeebf6da2fb69cc2d167
1 parent
12f57aa2
Brad Shuttleworth 2006-02-15 fix KTS-164
Brad Shuttleworth 2006-02-15 fix for KTS-145.
Brad Shuttleworth 2006-02-15 getByDocumentAndField needs to use oField t...
Brad Shuttleworth 2006-02-14 make transition screen more helpful.
Brad Shuttleworth 2006-02-14 fix for KTS-384
Brad Shuttleworth 2006-02-14 attempt a fix of the folder::copy bug,.
Brad Shuttleworth 2006-02-14 make password length admin override a confi...
Brad Shuttleworth 2006-02-14 beef up the way that users are fetched...
Brad Shuttleworth 2006-02-14 folder delete errors were using "array_join...
git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@4927 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
15 changed files
with
432 additions
and
79 deletions
config/config.ini
| ... | ... | @@ -149,3 +149,7 @@ antiword = antiword |
| 149 | 149 | ; minimum password length on password-setting |
| 150 | 150 | ; could be moved into DB-auth-config |
| 151 | 151 | passwordLength = 6 |
| 152 | + | |
| 153 | +; apply the minimum password length to admin while creating / editing accounts? | |
| 154 | +; default is set to "false" meaning that admins can create users with shorter passwords. | |
| 155 | +restrictAdminPasswords = default | ... | ... |
config/dmsDefaults.php
| ... | ... | @@ -390,6 +390,9 @@ $oKTConfig->setdefaultns("tweaks", "genericMetaDataRequired", true); |
| 390 | 390 | $oKTConfig->setdefaultns("tweaks", "phpErrorLogFile", false); |
| 391 | 391 | $oKTConfig->setdefaultns("tweaks", "developmentWindowLog", false); |
| 392 | 392 | |
| 393 | +$oKTConfig->setdefaultns("user_prefs", "passwordLength", 6); | |
| 394 | +$oKTConfig->setdefaultns("user_prefs", "restrictAdminPasswords", false); | |
| 395 | + | |
| 393 | 396 | $oKTConfig->setdefaultns("ui", "ieGIF", true); |
| 394 | 397 | $oKTConfig->setdefaultns("ui", "alwaysShowAll", false); |
| 395 | 398 | ... | ... |
lib/documentmanagement/DocumentFieldLink.inc
| ... | ... | @@ -163,7 +163,7 @@ class DocumentFieldLink extends KTEntity { |
| 163 | 163 | $iMetadataVersionId = $oDocument->getMetadataVersionId(); |
| 164 | 164 | return KTEntityUtil::getByDict('DocumentFieldLink', array( |
| 165 | 165 | 'metadata_version_id' => $iMetadataVersionId, |
| 166 | - 'document_field_id' => KTUtil::getId($oDocument), | |
| 166 | + 'document_field_id' => KTUtil::getId($oField), | |
| 167 | 167 | )); |
| 168 | 168 | } |
| 169 | 169 | } | ... | ... |
lib/foldermanagement/folderutil.inc.php
| ... | ... | @@ -223,10 +223,10 @@ class KTFolderUtil { |
| 223 | 223 | $sFD = ''; |
| 224 | 224 | $sFF = ''; |
| 225 | 225 | if (!empty($aFailedDocuments)) { |
| 226 | - $sFD = _('Documents: ') . array_join(', ', $aFailedDocuments) . '. '; | |
| 226 | + $sFD = _('Documents: ') . implode(', ', $aFailedDocuments) . '. '; | |
| 227 | 227 | } |
| 228 | 228 | if (!empty($aFailedFolders)) { |
| 229 | - $sFF = _('Folders: ') . array_join(', ', $aFailedFolders) . '.'; | |
| 229 | + $sFF = _('Folders: ') . implode(', ', $aFailedFolders) . '.'; | |
| 230 | 230 | } |
| 231 | 231 | return PEAR::raiseError(_('You do not have permission to delete these items. ') . $sFD . $sFF); |
| 232 | 232 | } |
| ... | ... | @@ -267,7 +267,7 @@ class KTFolderUtil { |
| 267 | 267 | $oPerm = KTPermission::getByName('ktcore.permissions.read'); |
| 268 | 268 | $oBaseFolderPerm = KTPermission::getByName('ktcore.permissions.addFolder'); |
| 269 | 269 | |
| 270 | - if (!KTPermissionUtil::userHasPermissionOnItem($oUser, $oPerm, $oDestFolder)) { | |
| 270 | + if (!KTPermissionUtil::userHasPermissionOnItem($oUser, $oBaseFolderPerm, $oDestFolder)) { | |
| 271 | 271 | return PEAR::raiseError(_('You are not allowed to create folders in the destination.')); |
| 272 | 272 | } |
| 273 | 273 | |
| ... | ... | @@ -298,7 +298,7 @@ class KTFolderUtil { |
| 298 | 298 | // child documents |
| 299 | 299 | $aChildDocs = Document::getList(array('folder_id = ?',array($iFolderId))); |
| 300 | 300 | foreach ($aChildDocs as $oDoc) { |
| 301 | - if (KTPermissionUtil::userHasPermissionOnItem($oUser, $oPerm, $oFolder)) { | |
| 301 | + if (KTPermissionUtil::userHasPermissionOnItem($oUser, $oPerm, $oDoc)) { | |
| 302 | 302 | $aDocuments[] = $oDoc; |
| 303 | 303 | } else { |
| 304 | 304 | $aFailedDocuments[] = $oDoc->getName(); |
| ... | ... | @@ -314,10 +314,10 @@ class KTFolderUtil { |
| 314 | 314 | $sFD = ''; |
| 315 | 315 | $sFF = ''; |
| 316 | 316 | if (!empty($aFailedDocuments)) { |
| 317 | - $sFD = _('Documents: ') . array_join(', ', $aFailedDocuments) . '. '; | |
| 317 | + $sFD = _('Documents: ') . implode(', ', $aFailedDocuments) . '. '; | |
| 318 | 318 | } |
| 319 | 319 | if (!empty($aFailedFolders)) { |
| 320 | - $sFF = _('Folders: ') . array_join(', ', $aFailedFolders) . '.'; | |
| 320 | + $sFF = _('Folders: ') . implode(', ', $aFailedFolders) . '.'; | |
| 321 | 321 | } |
| 322 | 322 | return PEAR::raiseError(_('You do not have permission to copy these items. ') . $sFD . $sFF); |
| 323 | 323 | } |
| ... | ... | @@ -325,6 +325,9 @@ class KTFolderUtil { |
| 325 | 325 | // first we walk the tree, creating in the new location as we go. |
| 326 | 326 | // essentially this is an "ok" pass. |
| 327 | 327 | |
| 328 | + | |
| 329 | + $oStorage =& KTStorageManagerUtil::getSingleton(); | |
| 330 | + | |
| 328 | 331 | $aFolderMap = array(); |
| 329 | 332 | |
| 330 | 333 | $sTable = KTUtil::getTableName('folders'); |
| ... | ... | @@ -339,7 +342,13 @@ class KTFolderUtil { |
| 339 | 342 | return $id; |
| 340 | 343 | } |
| 341 | 344 | $aFolderMap[$oFolder->getId()] = $id; |
| 342 | - | |
| 345 | + $oNewBaseFolder = Folder::get($id); | |
| 346 | + $res = $oStorage->createFolder($oNewBaseFolder); | |
| 347 | + if (PEAR::isError($res)) { | |
| 348 | + // it doesn't exist, so rollback and raise.. | |
| 349 | + DBUtil::rollback(); | |
| 350 | + return $res; | |
| 351 | + } | |
| 343 | 352 | $aRemainingFolders = Folder::getList(array('parent_id = ?', array($oFolder->getId())), array('ids' => true)); |
| 344 | 353 | |
| 345 | 354 | |
| ... | ... | @@ -359,34 +368,30 @@ class KTFolderUtil { |
| 359 | 368 | return $id; |
| 360 | 369 | } |
| 361 | 370 | $aFolderMap[$iFolderId] = $id; |
| 371 | + $oNewFolder = Folder::get($id); | |
| 372 | + $res = $oStorage->createFolder($oNewFolder); | |
| 373 | + if (PEAR::isError($res)) { | |
| 374 | + // first delete, then rollback, then fail out. | |
| 375 | + $oStorage->removeFolder($oNewBaseFolder); | |
| 376 | + DBUtil::rollback(); | |
| 377 | + return $res; | |
| 378 | + } | |
| 362 | 379 | |
| 363 | 380 | $aCFIds = Folder::getList(array('parent_id = ?', array($iFolderId)), array('ids' => true)); |
| 364 | 381 | $aRemainingFolders = array_merge($aRemainingFolders, $aCFIds); |
| 365 | 382 | } |
| 366 | 383 | |
| 384 | + | |
| 385 | + | |
| 367 | 386 | // now we can go ahead. |
| 368 | 387 | foreach ($aDocuments as $oDocument) { |
| 369 | 388 | $oChildDestinationFolder = Folder::get($aFolderMap[$oDocument->getFolderID()]); |
| 370 | 389 | $res = KTDocumentUtil::copy($oDocument, $oChildDestinationFolder); |
| 371 | - if (PEAR::isError($res)) { | |
| 390 | + if (PEAR::isError($res) || ($res === false)) { | |
| 372 | 391 | DBUtil::rollback(); |
| 373 | - return PEAR::raiseError(_('Delete Aborted. Unexpected failure to delete document: ') . $oDocument->getName() . $res->getMessage()); | |
| 392 | + return PEAR::raiseError(_('Delete Aborted. Unexpected failure to copydocument: ') . $oDocument->getName() . $res->getMessage()); | |
| 374 | 393 | } |
| 375 | 394 | } |
| 376 | - | |
| 377 | - $oStorage =& KTStorageManagerUtil::getSingleton(); | |
| 378 | - $oStorage->removeFolderTree($oStartFolder); | |
| 379 | - | |
| 380 | - // documents all cleared. | |
| 381 | - $sQuery = 'DELETE FROM ' . KTUtil::getTableName('folders') . ' WHERE id IN (' . DBUtil::paramArray($aFolderIds) . ')'; | |
| 382 | - $aParams = $aFolderIds; | |
| 383 | - | |
| 384 | - $res = DBUtil::runQuery(array($sQuery, $aParams)); | |
| 385 | - | |
| 386 | - if (PEAR::isError($res)) { | |
| 387 | - DBUtil::rollback(); | |
| 388 | - return PEAR::raiseError(_('Failure deleting folders.')); | |
| 389 | - } | |
| 390 | 395 | |
| 391 | 396 | // and store |
| 392 | 397 | DBUtil::commit(); | ... | ... |
lib/groups/Group.inc
| ... | ... | @@ -155,7 +155,7 @@ class Group extends KTEntity { |
| 155 | 155 | $aMembers = array(); |
| 156 | 156 | foreach ($aUserIds as $iUserId) { |
| 157 | 157 | $oUser = User::get($iUserId); |
| 158 | - if ($oUser !== false) { | |
| 158 | + if ((!PEAR::isError($oUser)) && ($oUser !== false)) { | |
| 159 | 159 | $aMembers[] = $oUser; |
| 160 | 160 | } |
| 161 | 161 | } |
| ... | ... | @@ -170,7 +170,7 @@ class Group extends KTEntity { |
| 170 | 170 | $aMembers = array(); |
| 171 | 171 | foreach ($aGroupIds as $iGroupId) { |
| 172 | 172 | $oGroup = Group::get($iGroupId); |
| 173 | - if ($oGroup !== false) { | |
| 173 | + if ((!PEAR::isError($oUser)) && ($oGroup !== false)) { | |
| 174 | 174 | $aMembers[] = $oGroup; |
| 175 | 175 | } |
| 176 | 176 | } | ... | ... |
plugins/ktcore/admin/ajaxComplexConditionals.php
| ... | ... | @@ -62,6 +62,88 @@ class AjaxConditionalAdminDispatcher extends KTAdminDispatcher { |
| 62 | 62 | return $oTemplate->render(); |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | + function do_removeFromBehaviour() { | |
| 66 | + $oFieldset =& $this->oValidator->validateFieldset(KTUtil::arrayGet($_REQUEST, 'fieldset_id')); | |
| 67 | + $field_id = KTUtil::arrayGet($_REQUEST, 'field_id'); | |
| 68 | + $oField =& $this->oValidator->validateField(KTUtil::arrayGet($_REQUEST, 'field_id')); | |
| 69 | + | |
| 70 | + header('Content-type: application/xml'); | |
| 71 | + | |
| 72 | + $instances = (array) KTUtil::arrayGet($_REQUEST, 'fieldsToRemove'); | |
| 73 | + | |
| 74 | + $this->startTransaction(); | |
| 75 | + | |
| 76 | + foreach ($instances as $iInstanceId) { | |
| 77 | + $oInstance = KTValueInstance::get($iInstanceId); | |
| 78 | + if (PEAR::isError($oInstance) || ($oInstance === false)) { | |
| 79 | + $this->rollbackTransaction(); | |
| 80 | + return 'Not OK.'; | |
| 81 | + } | |
| 82 | + | |
| 83 | + $res = $oInstance->delete(); | |
| 84 | + if (PEAR::isError($res) || ($res === false)) { | |
| 85 | + $this->rollbackTransaction(); | |
| 86 | + return 'Not OK.'; | |
| 87 | + } | |
| 88 | + } | |
| 89 | + | |
| 90 | + $this->commitTransaction(); | |
| 91 | + | |
| 92 | + return '<empty>OK.</empty>'; | |
| 93 | + } | |
| 94 | + | |
| 95 | + // get the list of ASSIGNED items for a given column, under a certain parent behaviour. | |
| 96 | + function do_getAssignedList() { | |
| 97 | + $parent_behaviour = KTUtil::arrayGet($_REQUEST, 'parent_behaviour'); | |
| 98 | + //$fieldset_id = KTUtil::arrayGet($_REQUEST, 'fieldset_id'); // | |
| 99 | + $oFieldset =& $this->oValidator->validateFieldset(KTUtil::arrayGet($_REQUEST, 'fieldset_id')); | |
| 100 | + $field_id = KTUtil::arrayGet($_REQUEST, 'field_id'); | |
| 101 | + $oField =& $this->oValidator->validateField(KTUtil::arrayGet($_REQUEST, 'field_id')); | |
| 102 | + | |
| 103 | + header('Content-type: application/xml'); | |
| 104 | + $oTemplating =& KTTemplating::getSingleton(); | |
| 105 | + $oTemplate =& $oTemplating->loadTemplate('ktcore/metadata/conditional/ajax_complex_get_item_list'); | |
| 106 | + | |
| 107 | + $aValues = array(); | |
| 108 | + $aBehaviours = array(); | |
| 109 | + foreach ($oField->getValues() as $oValue) { | |
| 110 | + if (empty($parent_behaviour)) { | |
| 111 | + $oInstance = KTValueInstance::getByLookupSingle($oValue); | |
| 112 | + if (!empty($oInstance)) { | |
| 113 | + if (is_null($aBehaviours[$oInstance->getBehaviourId()])) { | |
| 114 | + $aBehaviours[$oInstance->getBehaviourId()] = KTFieldBehaviour::get($oInstance->getBehaviourId()); | |
| 115 | + } | |
| 116 | + $aValues[$oInstance->getId()] = $oValue->getName() . ' - ' . $aBehaviours[$oInstance->getBehaviourId()]->getName(); | |
| 117 | + } | |
| 118 | + // No parent behaviour (thus master column), so any | |
| 119 | + // instance will do to prevent showing this value | |
| 120 | + continue; | |
| 121 | + } | |
| 122 | + | |
| 123 | + $iInstanceId = KTValueInstance::getByLookupAndParentBehaviour($oValue, $parent_behaviour, array('ids' => true)); | |
| 124 | + | |
| 125 | + if (!empty($iInstanceId)) { | |
| 126 | + | |
| 127 | + $oInstance = KTValueInstance::get($iInstanceId); | |
| 128 | + | |
| 129 | + //print $oInstance->getBehaviourId() . ' - '; | |
| 130 | + //continue; | |
| 131 | + | |
| 132 | + if (is_null($aBehaviours[$oInstance->getBehaviourId()])) { | |
| 133 | + $aBehaviours[$oInstance->getBehaviourId()] = KTFieldBehaviour::get($oInstance->getBehaviourId()); | |
| 134 | + } | |
| 135 | + | |
| 136 | + $aValues[$oInstance->getId()] = $oValue->getName() . ' - ' . $aBehaviours[$oInstance->getBehaviourId()]->getName(); | |
| 137 | + } | |
| 138 | + } | |
| 139 | + $aData = array( | |
| 140 | + 'values' => $aValues, | |
| 141 | + ); | |
| 142 | + $oTemplate->setData($aData); | |
| 143 | + | |
| 144 | + return $oTemplate->render(); | |
| 145 | + } | |
| 146 | + | |
| 65 | 147 | function do_getBehaviourList() { |
| 66 | 148 | $parent_behaviour = KTUtil::arrayGet($_REQUEST, 'parent_behaviour'); |
| 67 | 149 | $fieldset_id = KTUtil::arrayGet($_REQUEST, 'fieldset_id'); | ... | ... |
plugins/ktcore/admin/manageConditionals.php
| ... | ... | @@ -19,8 +19,8 @@ class ManageConditionalDispatcher extends KTAdminDispatcher { |
| 19 | 19 | global $default; |
| 20 | 20 | $this->ru = $default->rootUrl; |
| 21 | 21 | // this is not useful: we _still_ don't chain through the right dispatcher (!) |
| 22 | - $this->aBreadcrumbs[] = array('url' => $default->rootUrl . '/admin.php/documents', 'name' => _('Document Metadata and Workflow Configuration')); | |
| 23 | - $this->aBreadcrumbs[] = array('url' => $default->rootUrl . '/admin.php/documents/fieldmanagement', 'name' => _('Document Field Management')); | |
| 22 | + $this->aBreadcrumbs[] = array('url' => KTUtil::ktLink('/admin.php','documents'), 'name' => _('Document Metadata and Workflow Configuration')); | |
| 23 | + $this->aBreadcrumbs[] = array('url' => KTUtil::ktLink('/admin.php','documents/fieldmanagement'), 'name' => _('Document Field Management')); | |
| 24 | 24 | |
| 25 | 25 | |
| 26 | 26 | } |
| ... | ... | @@ -49,10 +49,11 @@ class ManageConditionalDispatcher extends KTAdminDispatcher { |
| 49 | 49 | * we can then render in/out. Everything "intelligent" happens |
| 50 | 50 | * in AJAX (doing it with submits sucks arse. |
| 51 | 51 | * |
| 52 | - * FIXME we fake it here with nested arrays... | |
| 53 | 52 | */ |
| 53 | + | |
| 54 | 54 | $oFieldset =& KTFieldset::get($fieldset_id); |
| 55 | 55 | $aFields =& $oFieldset->getFields(); |
| 56 | + | |
| 56 | 57 | $this->aBreadcrumbs[] = array( |
| 57 | 58 | 'url' => $this->ru . '/admin.php/documents/fieldmanagement', |
| 58 | 59 | 'query' => 'action=edit&fFieldsetId=' . $oFieldset->getId(), |
| ... | ... | @@ -69,7 +70,7 @@ class ManageConditionalDispatcher extends KTAdminDispatcher { |
| 69 | 70 | "context" => &$this, |
| 70 | 71 | "fieldset_id" => $fieldset_id, |
| 71 | 72 | "aFields" => $aFields, |
| 72 | - "iMasterFieldId" => $aFields[0]->getId(), | |
| 73 | + "iMasterFieldId" => $oFieldset->getMasterFieldId(), | |
| 73 | 74 | ); |
| 74 | 75 | return $oTemplate->render($aTemplateData); |
| 75 | 76 | } |
| ... | ... | @@ -104,7 +105,7 @@ class ManageConditionalDispatcher extends KTAdminDispatcher { |
| 104 | 105 | "context" => &$this, |
| 105 | 106 | "fieldset_id" => $fieldset_id, |
| 106 | 107 | "aFields" => $aFields, |
| 107 | - "iMasterFieldId" => $aFields[0]->getId(), | |
| 108 | + "iMasterFieldId" => $oFieldset->getMasterFieldId(), | |
| 108 | 109 | ); |
| 109 | 110 | return $oTemplate->render($aTemplateData); |
| 110 | 111 | } | ... | ... |
plugins/ktcore/admin/userManagement.php
| ... | ... | @@ -73,13 +73,22 @@ class KTUserAdminDispatcher extends KTAdminDispatcher { |
| 73 | 73 | |
| 74 | 74 | $aOptions = array('autocomplete' => false); |
| 75 | 75 | |
| 76 | + // sometimes even admin is restricted in what they can do. | |
| 77 | + | |
| 78 | + $KTConfig =& KTConfig::getSingleton(); | |
| 79 | + $minLength = ((int) $KTConfig->get('user_prefs/passwordLength', 6)); | |
| 80 | + $restrictAdmin = ((bool) $KTConfig->get('user_prefs/restrictAdminPasswords', false)); | |
| 81 | + $passwordAddRequirement = ''; | |
| 82 | + if ($restrictAdmin) { | |
| 83 | + $passwordAddRequirement = ' ' . sprintf('Password must be at least %d characters long.', $minLength); | |
| 84 | + } | |
| 76 | 85 | |
| 77 | 86 | $add_fields = array(); |
| 78 | 87 | $add_fields[] = new KTStringWidget(_('Username'),_('The username the user will enter to gain access to KnowledgeTree. e.g. <strong>jsmith</strong>'), 'username', null, $this->oPage, true, null, null, $aOptions); |
| 79 | 88 | $add_fields[] = new KTStringWidget(_('Name'),_('The full name of the user. This is shown in reports and listings. e.g. <strong>John Smith</strong>'), 'name', null, $this->oPage, true, null, null, $aOptions); |
| 80 | 89 | $add_fields[] = new KTStringWidget(_('Email Address'), _('The email address of the user. Notifications and alerts are mailed to this address if <strong>email notifications</strong> is set below. e.g. <strong>jsmith@acme.com</strong>'), 'email_address', null, $this->oPage, false, null, null, $aOptions); |
| 81 | 90 | $add_fields[] = new KTCheckboxWidget(_('Email Notifications'), _("If this is specified then the user will have notifications sent to the email address entered above. If it isn't set, then the user will only see notifications on the <strong>Dashboard</strong>"), 'email_notifications', true, $this->oPage, false, null, null, $aOptions); |
| 82 | - $add_fields[] = new KTPasswordWidget(_('Password'), _('Specify an initial password for the user.'), 'password', null, $this->oPage, true, null, null, $aOptions); | |
| 91 | + $add_fields[] = new KTPasswordWidget(_('Password'), _('Specify an initial password for the user.') . $passwordAddRequirement, 'password', null, $this->oPage, true, null, null, $aOptions); | |
| 83 | 92 | $add_fields[] = new KTPasswordWidget(_('Confirm Password'), _('Confirm the password specified above.'), 'confirm_password', null, $this->oPage, true, null, null, $aOptions); |
| 84 | 93 | // nice, easy bits. |
| 85 | 94 | $add_fields[] = new KTStringWidget(_('Mobile Number'), _("The mobile phone number of the user. If the system is configured to send notifications to cellphones, then this number will be SMS'd with notifications. e.g. <strong>999 9999 999</strong>"), 'mobile_number', null, $this->oPage, false, null, null, $aOptions); |
| ... | ... | @@ -162,7 +171,7 @@ class KTUserAdminDispatcher extends KTAdminDispatcher { |
| 162 | 171 | $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => _('User Management')); |
| 163 | 172 | $this->oPage->setBreadcrumbDetails(_('change user password')); |
| 164 | 173 | $this->oPage->setTitle(_("Change User Password")); |
| 165 | - | |
| 174 | + | |
| 166 | 175 | $user_id = KTUtil::arrayGet($_REQUEST, 'user_id'); |
| 167 | 176 | $oUser =& User::get($user_id); |
| 168 | 177 | |
| ... | ... | @@ -193,11 +202,18 @@ class KTUserAdminDispatcher extends KTAdminDispatcher { |
| 193 | 202 | $password = KTUtil::arrayGet($_REQUEST, 'password'); |
| 194 | 203 | $confirm_password = KTUtil::arrayGet($_REQUEST, 'confirm_password'); |
| 195 | 204 | |
| 196 | - if (empty($password)) { | |
| 205 | + $KTConfig =& KTConfig::getSingleton(); | |
| 206 | + $minLength = ((int) $KTConfig->get('user_prefs/passwordLength', 6)); | |
| 207 | + $restrictAdmin = ((bool) $KTConfig->get('user_prefs/restrictAdminPasswords', false)); | |
| 208 | + | |
| 209 | + | |
| 210 | + if ($restrictAdmin && (strlen($password) < $minLength)) { | |
| 211 | + $this->errorRedirectToMain(sprintf(_("The password must be at least %d characters long."), $minLength)); | |
| 212 | + } else if (empty($password)) { | |
| 197 | 213 | $this->errorRedirectToMain(_("You must specify a password for the user.")); |
| 198 | 214 | } else if ($password !== $confirm_password) { |
| 199 | 215 | $this->errorRedirectToMain(_("The passwords you specified do not match.")); |
| 200 | - } | |
| 216 | + } | |
| 201 | 217 | // FIXME more validation would be useful. |
| 202 | 218 | // validated and ready.. |
| 203 | 219 | $this->startTransaction(); |
| ... | ... | @@ -376,7 +392,14 @@ class KTUserAdminDispatcher extends KTAdminDispatcher { |
| 376 | 392 | $password = KTUtil::arrayGet($_REQUEST, 'password'); |
| 377 | 393 | $confirm_password = KTUtil::arrayGet($_REQUEST, 'confirm_password'); |
| 378 | 394 | |
| 379 | - if (empty($password)) { | |
| 395 | + $KTConfig =& KTConfig::getSingleton(); | |
| 396 | + $minLength = ((int) $KTConfig->get('user_prefs/passwordLength', 6)); | |
| 397 | + $restrictAdmin = ((bool) $KTConfig->get('user_prefs/restrictAdminPasswords', false)); | |
| 398 | + | |
| 399 | + | |
| 400 | + if ($restrictAdmin && (strlen($password) < $minLength)) { | |
| 401 | + $this->errorRedirectTo('addUser', sprintf(_("The password must be at least %d characters long."), $minLength)); | |
| 402 | + } else if (empty($password)) { | |
| 380 | 403 | $this->errorRedirectTo('addUser', _("You must specify a password for the user.")); |
| 381 | 404 | } else if ($password !== $confirm_password) { |
| 382 | 405 | $this->errorRedirectTo('addUser', _("The passwords you specified do not match.")); | ... | ... |
resources/css/kt-framing.css
| 1 | 1 | /* ------------------ generic ------------------ */ |
| 2 | 2 | |
| 3 | +html { | |
| 4 | + height: 100%; | |
| 5 | +} | |
| 6 | + | |
| 3 | 7 | body |
| 4 | 8 | { |
| 5 | 9 | padding: 1em ; border: 0; margin: 0; |
| ... | ... | @@ -14,10 +18,12 @@ body |
| 14 | 18 | margin: 0; border: 0; padding: 0; |
| 15 | 19 | } |
| 16 | 20 | |
| 21 | +/* | |
| 17 | 22 | #kt-wrapper |
| 18 | 23 | { |
| 19 | 24 | position: relative; |
| 20 | 25 | } |
| 26 | +*/ | |
| 21 | 27 | |
| 22 | 28 | .copyright { |
| 23 | 29 | margin-top: 1em; |
| ... | ... | @@ -173,8 +179,8 @@ a.main_nav_item { |
| 173 | 179 | { |
| 174 | 180 | position: absolute; |
| 175 | 181 | width: 14em; |
| 176 | - left: 0; | |
| 177 | - top: 0; | |
| 182 | + left: 1em; | |
| 183 | +/* top: 0; */ /* stupid IE bug: absolute position ate my scrollbars */ | |
| 178 | 184 | background: transparent; |
| 179 | 185 | margin: 0 10px 0 0 ; |
| 180 | 186 | border: 0; | ... | ... |
resources/js/conditional_complex_edit.js
| ... | ... | @@ -191,6 +191,53 @@ function getPOSTRequest(fullurl) { |
| 191 | 191 | return req; |
| 192 | 192 | } |
| 193 | 193 | |
| 194 | +function removeFromBehaviour(field_id) { | |
| 195 | + var action = 'removeFromBehaviour'; | |
| 196 | + | |
| 197 | + simpleLog('DEBUG','initiating item list update on field '+field_id); | |
| 198 | + | |
| 199 | + var formKeys = Array(); | |
| 200 | + var formValues = Array(); | |
| 201 | + // action | |
| 202 | + formKeys.push('action'); | |
| 203 | + formValues.push(action); | |
| 204 | + | |
| 205 | + // fieldset-id | |
| 206 | + formKeys.push('fieldset_id'); | |
| 207 | + formValues.push(getFieldsetId()); | |
| 208 | + // field_id | |
| 209 | + formKeys.push('field_id'); | |
| 210 | + formValues.push(field_id); | |
| 211 | + | |
| 212 | + // get the assigned items that are selected. | |
| 213 | + var column = getColumnForField(field_id); | |
| 214 | + var assigned_sources = getElementsByTagAndClassName('SELECT','assigned_item_list', column); | |
| 215 | + if (assigned_sources.length == 0) { | |
| 216 | + simpleLog('ERROR','Unable to locate assigned items.'); | |
| 217 | + return; | |
| 218 | + } | |
| 219 | + var assigned_select = assigned_sources[0]; | |
| 220 | + for (var i=0; i<assigned_select.options.length; i++) { | |
| 221 | + var opt = assigned_select.options[i]; | |
| 222 | + if (opt.selected) { | |
| 223 | + formKeys.push('fieldsToRemove[]'); | |
| 224 | + formValues.push(opt.value); | |
| 225 | + } | |
| 226 | + } | |
| 227 | + | |
| 228 | + | |
| 229 | + // boilerplate. | |
| 230 | + var POSTval = queryString(formKeys, formValues); | |
| 231 | + var req = getPOSTRequest(targeturl); | |
| 232 | + simpleLog('DEBUG','sending request (to '+targeturl+'): \n'+repr(map(null, formKeys, formValues))+'\nqueryString: '+POSTval); | |
| 233 | + var deferred = sendXMLHttpRequest(req, POSTval); | |
| 234 | + deferred.addCallback(partial(do_removeItems, field_id)); | |
| 235 | + deferred.addErrback(handleError); | |
| 236 | +} | |
| 237 | + | |
| 238 | +function do_removeItems(field_id, req) { | |
| 239 | + updateItemListForField(field_id); | |
| 240 | +} | |
| 194 | 241 | |
| 195 | 242 | // updates the item list for a given field to the items which are "free". |
| 196 | 243 | function updateItemListForField(field_id) { |
| ... | ... | @@ -226,6 +273,39 @@ function updateItemListForField(field_id) { |
| 226 | 273 | var deferred = sendXMLHttpRequest(req, POSTval); |
| 227 | 274 | deferred.addCallback(partial(do_updateItemList, field_id)); |
| 228 | 275 | deferred.addErrback(handleError); |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + action = 'getAssignedList'; | |
| 281 | + | |
| 282 | + formKeys = Array(); | |
| 283 | + formValues = Array(); | |
| 284 | + | |
| 285 | + formKeys.push('action'); | |
| 286 | + formValues.push(action); | |
| 287 | + // we need the fixed parent (or null - both are equivalent). | |
| 288 | + formKeys.push('parent_behaviour'); | |
| 289 | + if (fixed_value == null) { | |
| 290 | + formValues.push(''); | |
| 291 | + } else { | |
| 292 | + formValues.push(fixed_value); | |
| 293 | + } | |
| 294 | + // fieldset-id | |
| 295 | + formKeys.push('fieldset_id'); | |
| 296 | + formValues.push(getFieldsetId()); | |
| 297 | + // field_id | |
| 298 | + formKeys.push('field_id'); | |
| 299 | + formValues.push(field_id); | |
| 300 | + | |
| 301 | + | |
| 302 | + // boilerplate. | |
| 303 | + POSTval = queryString(formKeys, formValues); | |
| 304 | + req2 = getPOSTRequest(targeturl); | |
| 305 | + simpleLog('DEBUG','sending request (to '+targeturl+'): \n'+repr(map(null, formKeys, formValues))+'\nqueryString: '+POSTval); | |
| 306 | + var deferred2 = sendXMLHttpRequest(req2, POSTval); | |
| 307 | + deferred2.addCallback(partial(do_updateAssignedItemList, field_id)); | |
| 308 | + deferred2.addErrback(handleError); | |
| 229 | 309 | } |
| 230 | 310 | |
| 231 | 311 | // updates the available behaviours for a given field. |
| ... | ... | @@ -459,6 +539,34 @@ function do_updateItemList(field_id, req) { |
| 459 | 539 | replaceChildNodes(item_select, itemNodes); |
| 460 | 540 | } |
| 461 | 541 | |
| 542 | + | |
| 543 | +function do_updateAssignedItemList(field_id, req) { | |
| 544 | + simpleLog('DEBUG','entering callback for assigned-item-list update.'); | |
| 545 | + var items = req.responseXML.getElementsByTagName('item'); | |
| 546 | + | |
| 547 | + var itemNodes = Array(); | |
| 548 | + for (var i=0; i<items.length; i++) { | |
| 549 | + var item = items[i]; | |
| 550 | + itemNodes.push(createDOM('option',{'value':item.getAttribute('value')},item.getAttribute('label'))); | |
| 551 | + } | |
| 552 | + // now, find the array and replaceChildNodes() it. | |
| 553 | + var column = getColumnForField(field_id); | |
| 554 | + var assigned_wrapper = getElementsByTagAndClassName('DIV','assigned_items',column)[0]; | |
| 555 | + | |
| 556 | + if (itemNodes.length == 0) { | |
| 557 | + setElementClass(assigned_wrapper, 'assigned_items empty'); | |
| 558 | + } else { setElementClass(assigned_wrapper, 'assigned_items'); } | |
| 559 | + | |
| 560 | + | |
| 561 | + var is_sources = getElementsByTagAndClassName('select','assigned_item_list',column); | |
| 562 | + if (is_sources.length == 0) { | |
| 563 | + simpleLog('ERROR','Could not find the assigned item list in field '+field_id); | |
| 564 | + return; | |
| 565 | + } | |
| 566 | + var item_select = is_sources[0]; | |
| 567 | + replaceChildNodes(item_select, itemNodes); | |
| 568 | +} | |
| 569 | + | |
| 462 | 570 | function do_updateBehaviours(field_id, req) { |
| 463 | 571 | simpleLog('DEBUG','entering callback for behaviour-lists update.'); |
| 464 | 572 | // we handle this slightly differently to updateItemList. | ... | ... |
resources/js/conditional_simple_edit.js
| ... | ... | @@ -17,6 +17,16 @@ function getColumnForField(field_id) { |
| 17 | 17 | return getElement('md_'+field_id); |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | +function getButtonsForField(field_id) { | |
| 21 | + return getElement('buttons_'+field_id); | |
| 22 | +} | |
| 23 | + | |
| 24 | +function getNameForField(field_id) { | |
| 25 | + var h = getElement('header_'+field_id); | |
| 26 | + //alert(field_id); | |
| 27 | + return scrapeText(h); | |
| 28 | +} | |
| 29 | + | |
| 20 | 30 | function getFieldIdFromColumn(column) { |
| 21 | 31 | return column.id.substr(3,column.id.length); |
| 22 | 32 | } |
| ... | ... | @@ -29,6 +39,7 @@ function setActiveFields(active_fields) { |
| 29 | 39 | var column = getColumnForField(active_fields[i]); |
| 30 | 40 | setElementClass(column, 'active'); |
| 31 | 41 | } |
| 42 | + | |
| 32 | 43 | } |
| 33 | 44 | |
| 34 | 45 | // takes a field, and sets all items in active_lookups to be active. other items are deleted. |
| ... | ... | @@ -99,13 +110,13 @@ function do_handleAjaxError(err_source, err) { |
| 99 | 110 | } |
| 100 | 111 | |
| 101 | 112 | // from a selected_lookup, get the fixed_field and pass through, getting the items that selection currently activates. |
| 102 | -function updateActiveLookups(selected_lookup) { | |
| 113 | +function updateActiveLookups(selected_lookup, lookup_label) { | |
| 103 | 114 | |
| 104 | 115 | simpleLog('DEBUG','function updateActiveLookups called.'); |
| 105 | 116 | var req = getXMLHttpRequest(); |
| 106 | 117 | req.open('GET',target_url+'?action=updateActiveLookups&active_field='+current_fixed+'&selected_lookup='+selected_lookup, true); |
| 107 | 118 | var deferred = sendXMLHttpRequest(req); |
| 108 | - deferred.addCallback(do_updateActiveLookups); | |
| 119 | + deferred.addCallback(partial(do_updateActiveLookups, lookup_label)); | |
| 109 | 120 | deferred.addErrback(partial(do_handleAjaxError, 'updateActiveLookups')); |
| 110 | 121 | } |
| 111 | 122 | |
| ... | ... | @@ -152,7 +163,7 @@ function storeRelationship(selected_lookup, child_lookups) { |
| 152 | 163 | |
| 153 | 164 | // inform the user that something has happened. |
| 154 | 165 | // FIXME this isn't i18n friendly. |
| 155 | - addInformationNote('Values updated at ' + new Date()); | |
| 166 | + addInformationNote('Dependencies saved. (at ' + new Date() + ')'); | |
| 156 | 167 | |
| 157 | 168 | deferred.addCallback(do_updateActiveLookups); |
| 158 | 169 | deferred.addErrback(partial(do_handleAjaxError, 'storeRelationship')); |
| ... | ... | @@ -187,7 +198,7 @@ function do_updateActiveFields(req) { |
| 187 | 198 | |
| 188 | 199 | // should receive a simple-enough set of "field" elements, |
| 189 | 200 | // filled with "lookup" items. |
| 190 | -function do_updateActiveLookups(req) { | |
| 201 | +function do_updateActiveLookups(label, req) { | |
| 191 | 202 | simpleLog('DEBUG','AJAX function do_updateActiveLookups triggered'); |
| 192 | 203 | var active_fields = Array(); |
| 193 | 204 | var incoming_fields = req.responseXML.getElementsByTagName('field'); |
| ... | ... | @@ -211,6 +222,8 @@ function do_updateActiveLookups(req) { |
| 211 | 222 | setActiveLookupsForField(active_fields[i].field_id, active_fields[i].lookups); |
| 212 | 223 | } |
| 213 | 224 | } |
| 225 | + | |
| 226 | + addInformationNote('Dependencies for value "'+label+' loaded."(at ' + new Date() + ')'); | |
| 214 | 227 | } |
| 215 | 228 | |
| 216 | 229 | |
| ... | ... | @@ -220,19 +233,27 @@ function setExclusiveEditing(field_id) { |
| 220 | 233 | var rootItem = getConditionalTable(); |
| 221 | 234 | var columns = rootItem.getElementsByTagName('TD'); |
| 222 | 235 | for (var i=0; i<columns.length; i++) { |
| 223 | - setElementClass(columns[i], 'inactive'); | |
| 224 | - var item_list = getElementsByTagAndClassName('SELECT','item_list',columns[i])[0]; // FIXME catch potential failure here (pathalogical) | |
| 225 | - item_list.multiple=true; | |
| 226 | - updateNodeAttributes(item_list, {'onchange':null}); | |
| 236 | + var col = columns[i]; | |
| 237 | + if (hasElementClass(col, "buttonset")) { setElementClass(col, 'buttonset inactive'); } | |
| 238 | + else { | |
| 239 | + setElementClass(columns[i], 'inactive'); | |
| 240 | + var item_list = getElementsByTagAndClassName('SELECT','item_list',columns[i])[0]; // FIXME catch potential failure here (pathalogical) | |
| 241 | + item_list.multiple=true; | |
| 242 | + updateNodeAttributes(item_list, {'onchange':null}); | |
| 243 | + } | |
| 227 | 244 | } |
| 228 | 245 | |
| 229 | 246 | // get the "right" column. |
| 230 | 247 | var column = getColumnForField(field_id); |
| 248 | + simpleLog('DEBUG','setExclusiveEditing found column' + column + ' for id ' + field_id); | |
| 231 | 249 | setElementClass(column, 'active editing'); |
| 232 | 250 | var item_list = getElementsByTagAndClassName('SELECT','item_list',column)[0]; // FIXME catch potential failure here (pathalogical) |
| 233 | 251 | item_list.multiple = false; |
| 234 | 252 | updateNodeAttributes(item_list, {'onchange':partial(handleChangedSelection, field_id, item_list)}); |
| 235 | 253 | |
| 254 | + var buttons = getButtonsForField(field_id); | |
| 255 | + setElementClass(buttons, 'buttonset active editing'); | |
| 256 | + | |
| 236 | 257 | simpleLog('ERROR','setExclusiveEditing needs to alter the options so nothing is selected.'); |
| 237 | 258 | } |
| 238 | 259 | |
| ... | ... | @@ -248,6 +269,7 @@ function editSimpleField(field_id) { |
| 248 | 269 | setExclusiveEditing(field_id); |
| 249 | 270 | updateActiveFields(); // trigger an update of the backend. |
| 250 | 271 | // rest is asynchronous. |
| 272 | + addInformationNote('Now editing field "'+getNameForField(field_id)+'".'); | |
| 251 | 273 | } |
| 252 | 274 | |
| 253 | 275 | |
| ... | ... | @@ -279,7 +301,8 @@ function finishSimpleField(field_id) { |
| 279 | 301 | |
| 280 | 302 | // called when a single-view dropdown is activated. |
| 281 | 303 | function handleChangedSelection(field_id, select_input) { |
| 282 | - updateActiveLookups(select_input.value); // handles everything for us. | |
| 304 | + addInformationNote('Loading Dependencies for value "'+scrapeText(select_input.options[select_input.selectedIndex])+'"(at ' + new Date() + ')'); | |
| 305 | + updateActiveLookups(select_input.value, scrapeText(select_input.options[select_input.selectedIndex])); // handles everything for us. | |
| 283 | 306 | } |
| 284 | 307 | |
| 285 | 308 | // push onto the "fixed" stack the field which is being edited at the moment. | ... | ... |
templates/ktcore/metadata/conditional/editcomplex.smarty
| ... | ... | @@ -15,6 +15,12 @@ |
| 15 | 15 | .inactive .behaviour_edit_options |
| 16 | 16 | { display: none; } |
| 17 | 17 | |
| 18 | +.inactive .assigned_items { display: none; } | |
| 19 | + | |
| 20 | +.assigned_items.empty select { display: none; } | |
| 21 | +.assigned_items.empty .assigned_items_message { display: block; color: #666; } | |
| 22 | +.assigned_items_message { display: none; } | |
| 23 | + | |
| 18 | 24 | .helpText { color: #666; } |
| 19 | 25 | {/literal} |
| 20 | 26 | {/capture} |
| ... | ... | @@ -36,6 +42,17 @@ addLoadEvent(updateActiveFields); |
| 36 | 42 | {$context->oPage->requireJSStandalone($sJS)} |
| 37 | 43 | |
| 38 | 44 | <h2>{i18n}Edit Complex Conditional Metadata{/i18n}</h2> |
| 45 | + | |
| 46 | +<p class="descriptiveText">Complex Conditional Metadata depends on what are | |
| 47 | +called "behaviours". Essentially, behaviours are assigned to a <strong>single</strong> | |
| 48 | +field, and can contain any number of values that are available in that field. Each field | |
| 49 | +can have multiple behaviours assigned to it.</p> | |
| 50 | + | |
| 51 | +<p class="descriptiveText important">Each behaviour can cause a number of other behaviours — in | |
| 52 | +the field's <strong>child</strong> fields — to become available. By assigning values | |
| 53 | +to behaviours, and creating relationships between behaviours, you can create extremely complex | |
| 54 | +relationships between available lookup values.</p> | |
| 55 | + | |
| 39 | 56 | <form method="POST" action="{$smarty.server.PHP_SELF}"> |
| 40 | 57 | <input type="hidden" name="fieldset_id" id="global-fieldset-id" value="{$fieldset_id}" /> |
| 41 | 58 | |
| ... | ... | @@ -54,6 +71,21 @@ addLoadEvent(updateActiveFields); |
| 54 | 71 | <h3>{$oField->getName()}</h3> |
| 55 | 72 | <p class="inactivity_message">{i18n}This column is not active.{/i18n}</p> |
| 56 | 73 | <p class="fixed_message">{i18n}Editing behaviour <strong>Jack</strong>{/i18n}</p> |
| 74 | + <div class="assigned_items"> | |
| 75 | + <h3>{i18n}Assigned Items{/i18n}</h3> | |
| 76 | + <select class="assigned_item_list" multiple="true"> | |
| 77 | + <!-- These are orphaned - we fire a "activate" command on load / available. | |
| 78 | + <option value="-1">Test 1</option> | |
| 79 | + <option value="-2">Test 2</option> | |
| 80 | + <option value="-3">Test 3</option> | |
| 81 | + <option value="-4">Test 4</option> | |
| 82 | + --> | |
| 83 | + </select> | |
| 84 | + <br /><input class="assigned_item_list" type="button" value="{i18n}remove behaviour{/i18n}" onclick="removeFromBehaviour({$oField->getId()});" /> | |
| 85 | + <p class="assigned_items_message">No items have been assigned with the current | |
| 86 | + parent behaviour.</p> | |
| 87 | + </div> | |
| 88 | + | |
| 57 | 89 | <div class="unassigned_items"> |
| 58 | 90 | <h3>{i18n}Unassigned/Unavailable{/i18n}</h3> |
| 59 | 91 | <select class="item_list" multiple="true"> |
| ... | ... | @@ -93,9 +125,7 @@ addLoadEvent(updateActiveFields); |
| 93 | 125 | <option value="4">Behaviour 4</option> |
| 94 | 126 | --> |
| 95 | 127 | </select> |
| 96 | - <br /> | |
| 97 | - <a href="#" onclick="changeAssignments({$oField->getId()}); return | |
| 98 | -false;">{i18n}Change Assignments for this field.{/i18n}</a> | |
| 128 | + | |
| 99 | 129 | </div> |
| 100 | 130 | </td> |
| 101 | 131 | {/foreach} | ... | ... |
templates/ktcore/metadata/conditional/editsimple.smarty
| ... | ... | @@ -3,16 +3,20 @@ |
| 3 | 3 | /* inactivity */ |
| 4 | 4 | .active .inactivity_message { display: none; } |
| 5 | 5 | |
| 6 | +select { width: 100%; } | |
| 7 | + | |
| 8 | +.edit_button { margin-bottom: 0.5em; } | |
| 6 | 9 | .save_button, |
| 7 | -.done_button { display: none; } | |
| 10 | +.done_button { display: none; margin-bottom: 0.5em;} | |
| 8 | 11 | |
| 9 | 12 | .active.editing .save_button, |
| 10 | 13 | .active.editing .done_button { display: block; } |
| 11 | 14 | |
| 12 | 15 | .active.editing .edit_button { display: none; } |
| 13 | 16 | |
| 14 | - | |
| 15 | 17 | .active { position: relative; } |
| 18 | +td { vertical-align: top; } | |
| 19 | +.buttonset.inactive { background: transparent; } | |
| 16 | 20 | |
| 17 | 21 | .inactive { background: #ccc; position: relative; } |
| 18 | 22 | .inactive .fixed_message, |
| ... | ... | @@ -61,14 +65,24 @@ addLoadEvent(partial(editSimpleField, {$iMasterFieldId})); |
| 61 | 65 | |
| 62 | 66 | <h2>{i18n}Editing Fieldset Rules (Simple){/i18n}</h2> |
| 63 | 67 | |
| 68 | +<p class="descriptiveText">To make a value in a <strong>child field</strong>available to the user when another value is | |
| 69 | +selected in a <strong>parent field</strong>, first ensure that the parent field is being edited (it will have "save" and "done" | |
| 70 | +as the buttons at the bottom of the column) and then select the value for the parent field. Now select the value(s) in | |
| 71 | +the child column(s) you wish to be available to the user when the parent field's value is selected, | |
| 72 | +and click "save". Note you that you can use Ctrl-<click> to select multiple child values | |
| 73 | +at the same time.</p> | |
| 74 | + | |
| 75 | +<p class="descriptiveText important">Changes made here are stored immediately, without you needing to | |
| 76 | +refresh the page.</p> | |
| 77 | + | |
| 64 | 78 | <form method="POST" action="{$smarty.server.PHP_SELF}"> |
| 65 | 79 | <input type="hidden" name="fieldset_id" id="global-fieldset-id" value="{$fieldset_id}" /> |
| 66 | 80 | |
| 67 | 81 | <table id="simple_conditional_edit"> |
| 68 | 82 | <tr> |
| 69 | - <th>Column 1</th> | |
| 70 | - <th>Column 2</th> | |
| 71 | - <th>Column 3</th> | |
| 83 | +{foreach from=$aFields item=oField} | |
| 84 | + <th id="header_{$oField->getId()}">{$oField->getName()}</th> | |
| 85 | +{/foreach} | |
| 72 | 86 | </tr> |
| 73 | 87 | <tr valign="top"> |
| 74 | 88 | |
| ... | ... | @@ -76,22 +90,28 @@ addLoadEvent(partial(editSimpleField, {$iMasterFieldId})); |
| 76 | 90 | <td class="inactive" id="md_{$oField->getId()}"> |
| 77 | 91 | <p class="inactivity_message">{i18n}This field is not controlled by the currently active group.{/i18n}</p> |
| 78 | 92 | <div class="lookup_items"> |
| 79 | - <h3>Field: {$oField->getName()}</h3> | |
| 80 | 93 | <select class="item_list"> |
| 81 | 94 | {foreach from=$oField->getValues() item=oMetaData} |
| 82 | 95 | <option value="{$oMetaData->getId()}">{$oMetaData->getName()|escape}</option> |
| 83 | 96 | {/foreach} |
| 84 | 97 | </select> |
| 85 | - <div class="buttonset"> | |
| 86 | - <input type="button" value="{i18n}edit{/i18n}" class="edit_button" onclick="editSimpleField({$oField->getId()})" /> | |
| 87 | - <input type="button" value="{i18n}save{/i18n}" class="save_button" onclick="saveSimpleField({$oField->getId()})" /> | |
| 88 | - <input type="button" value="{i18n}done{/i18n}" class="done_button" onclick="finishSimpleField({$oField->getId()})" /> | |
| 89 | - </div> | |
| 98 | + | |
| 90 | 99 | </div> |
| 91 | 100 | </td> |
| 92 | 101 | {/foreach} |
| 93 | 102 | |
| 94 | 103 | </tr> |
| 104 | +<tr> | |
| 105 | +{foreach from=$aFields item=oField} | |
| 106 | + <td class="buttonset" id="buttons_{$oField->getId()}"> | |
| 107 | + <div class="form_actions"> | |
| 108 | + <input type="button" value="{i18n}edit field{/i18n}" class="edit_button" onclick="editSimpleField({$oField->getId()})" /> | |
| 109 | + <input type="button" value="{i18n}save this dependency{/i18n}" class="save_button" onclick="saveSimpleField({$oField->getId()})" /> | |
| 110 | + <input type="button" value="{i18n}finished with this field{/i18n}" class="done_button" onclick="finishSimpleField({$oField->getId()})" /> | |
| 111 | + </div> | |
| 112 | + </td> | |
| 113 | +{/foreach} | |
| 114 | +</tr> | |
| 95 | 115 | </table> |
| 96 | 116 | <!-- |
| 97 | 117 | <table id="brad-log"> | ... | ... |
templates/ktcore/metadata/conditional/manageConditional.smarty
| 1 | 1 | <h2>{i18n}Manage conditional fieldset{/i18n}</h2> |
| 2 | 2 | |
| 3 | +<p class="descriptiveText">Conditional fieldsets allow you to restrict the options | |
| 4 | +a user has for values in some fields based on the values in other fields. There | |
| 5 | +are two kinds of conditional fieldsets: <strong>Simple</strong> and <strong>Complex</strong> | |
| 6 | +. Simple fieldsets should be sufficient for most things: they allow you to say that | |
| 7 | +the values of one field are restricted to a certain subset of values if another field | |
| 8 | +has a specific value. For example, you could say that if the field "Street" is "Jeffrey", | |
| 9 | +then the field "Residents" must be one of "Jones","Smith" or "Friedman".</p> | |
| 10 | + | |
| 11 | +<p class="descriptiveText">Complex fieldsets allow you to give far more detailed structure to | |
| 12 | +your information: The value of "Residents" can depend not only on "Street", but on | |
| 13 | +how the user was allowed to select the specific street (given another field).</p> | |
| 14 | + | |
| 15 | +{* don't show warnings until the basics are done. *} | |
| 16 | + | |
| 17 | +{if ($oMasterField && empty($free_fields))} | |
| 3 | 18 | {if $sIncomplete || !$oFieldset->getIsComplete()} |
| 4 | -<div class="ktError"> | |
| 19 | +<div class="ktInfo"> | |
| 5 | 20 | <p>{i18n}This conditional fieldset is marked such that it |
| 6 | 21 | cannot be used. This happens when the fieldset has been edited and has |
| 7 | 22 | not been set to complete. Setting the fieldset to complete will do a |
| 8 | 23 | check to see if the fieldset is usable by the user.{/i18n}</p> |
| 9 | 24 | </div> |
| 25 | +{/if} | |
| 10 | 26 | |
| 11 | 27 | {if $sIncomplete} |
| 12 | 28 | <div class="ktError"> |
| ... | ... | @@ -27,9 +43,12 @@ to complete{/i18n}: {$sIncomplete|escape}</p> |
| 27 | 43 | <h2>{i18n}Conditional type{/i18n}</h2> |
| 28 | 44 | |
| 29 | 45 | {if $oFieldset->getIsComplex()} |
| 30 | -<p>{i18n}Complex{/i18n}: <a | |
| 46 | +<p>{i18n}The fieldset is currently designated as <strong>Complex</strong>{/i18n}</p> | |
| 47 | + | |
| 48 | +{if ($oMasterField && empty($free_fields))}<p><a | |
| 49 | +class="ktActionLink ktEdit" | |
| 31 | 50 | href="{$rootUrl}/plugins/ktcore/admin/manageConditionals.php?action=editComplexFieldset&fieldset_id={$oFieldset->getId()}">{i18n}Manage |
| 32 | -complex conditional{/i18n}</a></p> | |
| 51 | +complex conditional{/i18n}</a></p>{/if} | |
| 33 | 52 | |
| 34 | 53 | <form action="{$smarty.server.PHP_SELF}" method="POST"> |
| 35 | 54 | <input type="hidden" name="action" value="changeToSimple" /> |
| ... | ... | @@ -39,9 +58,13 @@ complex conditional{/i18n}</a></p> |
| 39 | 58 | |
| 40 | 59 | {else} |
| 41 | 60 | |
| 42 | -<p>{i18n}Simple{/i18n}: <a | |
| 61 | +<p>{i18n}The fieldset is currently designated as <strong>Simple</strong>{/i18n}</p> | |
| 62 | + | |
| 63 | +{if ($oMasterField && empty($free_fields))}<p><a | |
| 64 | +class="ktActionLink ktEdit" | |
| 43 | 65 | href="{$rootUrl}/plugins/ktcore/admin/manageConditionals.php?action=editFieldset&fieldset_id={$oFieldset->getId()}">{i18n}Manage simple conditional{/i18n}</a> |
| 44 | 66 | </p> |
| 67 | +{/if} | |
| 45 | 68 | |
| 46 | 69 | <form action="{$smarty.server.PHP_SELF}" method="POST"> |
| 47 | 70 | <input type="hidden" name="action" value="changeToComplex" /> |
| ... | ... | @@ -54,9 +77,10 @@ href="{$rootUrl}/plugins/ktcore/admin/manageConditionals.php?action=editFieldset |
| 54 | 77 | <p>{i18n}Changing the conditional type set will remove all existing field |
| 55 | 78 | ordering!{/i18n}</p> |
| 56 | 79 | |
| 57 | -<h2>Master field</h2> | |
| 80 | + | |
| 58 | 81 | |
| 59 | 82 | {if !$oMasterField} |
| 83 | +<h2>Master field</h2> | |
| 60 | 84 | {i18n}No master field is set, please select the master field{/i18n}: |
| 61 | 85 | |
| 62 | 86 | <form action="{$smarty.server.PHP_SELF}" method="POST"> |
| ... | ... | @@ -70,15 +94,26 @@ ordering!{/i18n}</p> |
| 70 | 94 | {else} |
| 71 | 95 | |
| 72 | 96 | <form action="{$smarty.server.PHP_SELF}" method="POST"> |
| 97 | +<fieldset> | |
| 98 | +<legend>Master field</legend> | |
| 73 | 99 | <input type="hidden" name="action" value="setMasterField" /> |
| 74 | 100 | <input type="hidden" name="fFieldsetId" value="{$oFieldset->getId()}" /> |
| 75 | 101 | |
| 102 | +<p class="descriptiveText">In order to have a chain of conditions, one initial field | |
| 103 | +must be shown to the user. This is called the <strong>master field</strong>.</p> | |
| 104 | + | |
| 105 | +<div class="form"> | |
| 106 | +<p class="descriptiveText important">{i18n}Changing the master field set will remove all existing field | |
| 107 | +ordering!{/i18n}</p> | |
| 76 | 108 | {entity_select entities=$oFieldset->getFields() name="fFieldId" selected=$oMasterField->getId()} |
| 109 | +</div> | |
| 110 | +<div class="form_actions"> | |
| 77 | 111 | <input type="submit" name="submit" value="{i18n}Change master field{/i18n}" /> |
| 112 | +</div> | |
| 113 | +</fieldset> | |
| 78 | 114 | </form> |
| 79 | 115 | |
| 80 | -<p>{i18n}Changing the master field set will remove all existing field | |
| 81 | -ordering!{/i18n}</p> | |
| 116 | + | |
| 82 | 117 | |
| 83 | 118 | <h2>{i18n}Field ordering{/i18n}</h2> |
| 84 | 119 | |
| ... | ... | @@ -92,30 +127,38 @@ $this->assign("oParentField", DocumentField::get($this->_tpl_vars['aRow']['paren |
| 92 | 127 | $this->assign("oChildField", DocumentField::get($this->_tpl_vars['aRow']['child_field_id'])); |
| 93 | 128 | {/php} |
| 94 | 129 | <li> |
| 95 | -<span title="Field Id {$oParentField->getId()}">Field {$oParentField->getName()|escape}</span> | |
| 96 | -affects the values available in | |
| 97 | -<span title="Field Id {$oChildField->getId()}">field {$oChildField->getName()|escape}</span> | |
| 130 | + {$oParentField->getName()|escape} | |
| 131 | +<span class="descriptiveText">controls the values available in</span> | |
| 132 | + {$oChildField->getName()|escape} | |
| 98 | 133 | </li> |
| 99 | 134 | {/foreach} |
| 100 | 135 | </ul> |
| 101 | 136 | {/if} |
| 102 | 137 | |
| 103 | 138 | { if $free_fields } |
| 104 | -<h3>{i18n}Order fields{/i18n}</h2> | |
| 139 | + | |
| 105 | 140 | |
| 106 | 141 | <form action="{$smarty.server.PHP_SELF}" method="POST"> |
| 142 | +<fieldset> | |
| 107 | 143 | <input type="hidden" name="fFieldsetId" value="{$oFieldset->getId()}" /> |
| 108 | 144 | <input type="hidden" name="action" value="orderFields" /> |
| 109 | 145 | |
| 110 | -The available values of the selected fields: | |
| 111 | -<br /> | |
| 112 | -{entity_select entities=$free_fields name="fFreeFieldIds[]" multiple="yes"} | |
| 113 | -<br /> | |
| 114 | -are conditional on the values of this field: | |
| 115 | -<br /> | |
| 146 | +<legend>{i18n}Order Fields{/i18n}</legend> | |
| 147 | + | |
| 148 | +<div class="field"> | |
| 149 | +<p class="descriptiveText">The value of the field</p> | |
| 116 | 150 | {entity_select entities=$parent_fields name="fParentFieldId"} |
| 117 | -<br /> | |
| 151 | +</div> | |
| 152 | + | |
| 153 | +<div class="field"> | |
| 154 | +<p class="descriptiveText">controls the values of the following fields</p> | |
| 155 | +{entity_select entities=$free_fields name="fFreeFieldIds[]" multiple="yes"} | |
| 156 | +</div> | |
| 157 | + | |
| 158 | +<div class="form_actions"> | |
| 118 | 159 | <input type="submit" name="submit" value="{i18n}Order{/i18n}" /> |
| 160 | +</div> | |
| 161 | +</fieldset> | |
| 119 | 162 | </form> |
| 120 | 163 | {/if} |
| 121 | 164 | ... | ... |
templates/ktcore/workflow/manageTransitions.smarty
| ... | ... | @@ -20,6 +20,10 @@ while the workflow has no documents or document-versions assigned to the workflo |
| 20 | 20 | |
| 21 | 21 | </fieldset> |
| 22 | 22 | |
| 23 | +{if (empty($workflow_info.transitions))} | |
| 24 | +<div class="ktInfo"><p>This workflow does not define any transitions. Use the "Create a new transition" link above | |
| 25 | +to add new transitions.</p></div> | |
| 26 | +{else} | |
| 23 | 27 | <h3>{i18n}Transition Availability{/i18n}</h3> |
| 24 | 28 | |
| 25 | 29 | <p class="descriptiveText">Click on any transition below to edit it directly, |
| ... | ... | @@ -66,3 +70,4 @@ or use the checkboxes to assign which states the transition is available from.</ |
| 66 | 70 | </div> |
| 67 | 71 | |
| 68 | 72 | </form> |
| 73 | +{/if} | |
| 69 | 74 | \ No newline at end of file | ... | ... |