diff --git a/CourseEditorOperations.php b/CourseEditorOperations.php index 10cf8cb..141c078 100644 --- a/CourseEditorOperations.php +++ b/CourseEditorOperations.php @@ -1,314 +1,313 @@ type) { case 'fromTopic': - self::createNewCourseFromTopic($operation->params); + $result = self::createNewCourseFromTopic($operation); + CourseEditorUtils::setComposedOperationSuccess($operation, $result); break; case 'fromDepartment': - self::createNewCourseFromDepartment($operation->params); + $result = self::createNewCourseFromDepartment($operation); + CourseEditorUtils::setComposedOperationSuccess($operation, $result); break; } - //FIXME Must be a serius return object and error handling - return "ok"; + return json_encode($operation); } public static function manageCourseMetadataOp($operationRequested){ $operation = json_decode($operationRequested); $params = $operation->params; $title = $params[0]; $topic = $params[1]; $description = $params[2]; $externalReferences = $params[3]; $isImported = $params[4]; $originalAuthors = $params[5]; $isReviewed = $params[6]; $reviewedOn = $params[7]; $pageTitle = MWNamespace::getCanonicalName(NS_COURSEMETADATA) . ':' . $title; $metadata = "
" . $topic . "
\r\n"; if($description !== '' && $description !== null){ $metadata .= "
" . $description . "
\r\n"; } if($externalReferences !== '' && $externalReferences !== null){ $metadata .= "
" . $externalReferences . "
\r\n"; } if($isImported !== false || $isReviewed !== false){ $metadata .= "
" . true . "
\r\n"; if($isImported !== false){ $metadata .= "
" . $isImported . "
\r\n"; $metadata .= "
" . $originalAuthors . "
\r\n"; } if($isReviewed !== false){ $metadata .= "
" . $isReviewed . "
\r\n"; $metadata .= "
" . $reviewedOn . "
\r\n"; } } $resultCreateMetadataPage = CourseEditorUtils::editWrapper($pageTitle, $metadata , null, null); CourseEditorUtils::setSingleOperationSuccess($operation, $resultCreateMetadataPage); return json_encode($operation); - //FIXME Return an object with results in order to display error to the user } private function createBasicCourseMetadata($topic, $title, $description){ $topic = ($topic === null ? $title : $topic); $pageTitle = MWNamespace::getCanonicalName(NS_COURSEMETADATA) . ':' . $title; $metadata = "
" . $topic . "
\r\n"; if($description !== '' && $description !== null){ $metadata .= "
" . $description . "
\r\n"; } - $resultCreateMetadataPage = CourseEditorUtils::editWrapper($pageTitle, $metadata , null, null); - //FIXME Return an object with results in order to display error to the user + $apiResult = CourseEditorUtils::editWrapper($pageTitle, $metadata , null, null); + return $apiResult; } - private function createNewCourseFromDepartment($params){ + private function createNewCourseFromDepartment(&$operation){ + $params = $operation->params; $department = $params[0]; $title = $params[1]; $description = $params[2]; $namespace = $params[3]; if($department != null && $title != null && $namespace != null){ $compareResult = strcmp($namespace, 'NS_COURSE'); $namespaceCostant = ($compareResult == 0 ? NS_COURSE : NS_USER); $pageTitle = MWNamespace::getCanonicalName($namespaceCostant) . ':'; if($namespaceCostant == NS_USER){ - self::createPrivateCourse($pageTitle, null, $title, $description); + $result = self::createPrivateCourse($pageTitle, $topic, $title, $description); + $user = CourseEditorUtils::getRequestContext()->getUser(); + $userPage = $pageTitle . $user->getName(); + $operation->courseTitle = $userPage . '/' . $title; }else{ - self::createPublicCourseFromDepartment($pageTitle, $department, $title, $description); + $result = self::createPublicCourseFromDepartment($pageTitle, $department, $title, $description); + $operation->courseTitle = $pageTitle . $title; } } + + return $result; } - private function createNewCourseFromTopic($params){ + private function createNewCourseFromTopic(&$operation){ + $params = $operation->params; $topic = $params[0]; $title = $params[1]; $description = $params[2]; $namespace = $params[3]; if($topic != null && $title != null && $namespace != null){ $compareResult = strcmp($namespace, 'NS_COURSE'); $namespaceCostant = ($compareResult === 0 ? NS_COURSE : NS_USER); $pageTitle = MWNamespace::getCanonicalName($namespaceCostant) . ':'; if($namespaceCostant == NS_USER){ - self::createPrivateCourse($pageTitle, $topic, $title, $description); + $result = self::createPrivateCourse($pageTitle, $topic, $title, $description); + $user = CourseEditorUtils::getRequestContext()->getUser(); + $userPage = $pageTitle . $user->getName(); + $operation->courseTitle = $userPage . '/' . $title; }else{ - self::createPublicCourseFromTopic($pageTitle, $topic, $title, $description); + $result = self::createPublicCourseFromTopic($pageTitle, $topic, $title, $description); + $operation->courseTitle = $pageTitle . $title; } } + return $result; } private function createPrivateCourse($pageTitle, $topic, $title, $description){ $context = CourseEditorUtils::getRequestContext(); $user = $context->getUser(); $userPage = $pageTitle . $user->getName(); $titleWithUser = $user->getName() . '/' . $title; $pageTitle = $userPage . "/" . $title; $resultCreateCourse = CourseEditorUtils::editWrapper($pageTitle, "{{CCourse|}}", null, null); $resultCreateMetadataPage = self::createBasicCourseMetadata($topic, $titleWithUser, $description); $textToPrepend = "{{Course|" . $title . "|" . $user->getName() . "}}"; $resultPrependToUserPage = CourseEditorUtils::editWrapper($userPage, null, $textToPrepend, null); - //FIXME Return an object with results in order to display error to the user + return array($resultCreateCourse, $resultCreateMetadataPage, $resultPrependToUserPage); + } private function createPublicCourseFromTopic($pageTitle, $topic, $title, $description){ $pageTitle .= $title; $resultCreateCourse = CourseEditorUtils::editWrapper($pageTitle, "{{CCourse|}}", null, null); $topicCourses = CourseEditorUtils::getTopicCourses($topic); $text = $topicCourses . "{{Course|" . $title . "}}}}"; $resultCreateMetadataPage = self::createBasicCourseMetadata($topic, $title, $description); $resultAppendToTopic = CourseEditorUtils::editWrapper($topic, $text, null, null); - //FIXME Return an object with results in order to display error to the user - + return array($resultCreateCourse, $resultCreateMetadataPage, $resultAppendToTopic); } private function createPublicCourseFromDepartment($pageTitle, $department, $title, $description){ $pageTitle .= $title; $resultCreateCourse = CourseEditorUtils::editWrapper($pageTitle, "{{CCourse|}}", null, null); $text = "{{Topic|" . "{{Course|" . $title . "}}}}"; $listElementText = "\r\n* [[" . $title . "]]"; $resultCreateMetadataPage = self::createBasicCourseMetadata(null, $title, $description); $resultAppendToTopic = CourseEditorUtils::editWrapper($title, $text, null, null); $resultAppendToDepartment = CourseEditorUtils::editWrapper($department, null, null, $listElementText); - //FIXME Return an object with results in order to display error to the user - + return array($resultCreateCourse, $resultCreateMetadataPage, $resultAppendToTopic, $resultAppendToDepartment); } public static function applyCourseOp($courseName, $operation){ $value = json_decode($operation); switch ($value->action) { case 'rename-move-task': $sectionName = $value->elementName; $newSectionName = $value->newElementName; - /*$chapters = CourseEditorUtils::getChapters($courseName . '/' .$sectionName); - $newSectionText = ""; - foreach ($chapters as $chapter) { - $newSectionText .= "* [[" . $courseName . "/" . $newSectionName . "/" . $chapter ."|". $chapter ."]]\r\n"; - }*/ $pageTitle = $courseName . "/" . $sectionName; $newPageTitle = $courseName . '/' . $newSectionName; $apiResult = CourseEditorUtils::moveWrapper($pageTitle, $newPageTitle); - //$resultEdit = CourseEditorUtils::editWrapper($newPageTitle, $newSectionText, null, null); - //$apiResult = array($resultMove, $resultEdit); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'rename-update-task': $sectionName = $value->elementName; $newSectionName = $value->newElementName; $chapters = CourseEditorUtils::getChapters($courseName . '/' .$newSectionName); $newSectionText = ""; foreach ($chapters as $chapter) { $newSectionText .= "* [[" . $courseName . "/" . $newSectionName . "/" . $chapter ."|". $chapter ."]]\r\n"; } - //$pageTitle = $courseName . "/" . $sectionName; $newPageTitle = $courseName . '/' . $newSectionName; - //$apiResult = CourseEditorUtils::moveWrapper($pageTitle, $newPageTitle); $apiResult = CourseEditorUtils::editWrapper($newPageTitle, $newSectionText, null, null); - //$apiResult = array($resultMove, $resultEdit); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'delete-chapters-task': $user = CourseEditorUtils::getRequestContext()->getUser(); $sectionName = $value->elementName; $chapters = CourseEditorUtils::getChapters($courseName . '/' . $sectionName); $title = Title::newFromText( $courseName . '/' . $sectionName, $defaultNamespace=NS_MAIN ); $pageTitle = $courseName . '/' . $sectionName; if(!$title->userCan('delete', $user, 'secure')){ $prependText = "\r\n{{DeleteMe}}"; - //$resultSection = CourseEditorUtils::editWrapper($pageTitle, null, $prependText, null); foreach ($chapters as $chapter) { $pageTitle = $courseName . '/' . $sectionName . '/' . $chapter; $prependText = "\r\n{{DeleteMe}}"; $apiResult = CourseEditorUtils::editWrapper($pageTitle, null, $prependText, null); } }else { foreach ($chapters as $chapter) { $pageTitle = $courseName . '/' . $sectionName . '/' . $chapter; - $resultChapters = CourseEditorUtils::deleteWrapper($pageTitle); + $apiResult = CourseEditorUtils::deleteWrapper($pageTitle); } - //$resultSection = CourseEditorUtils::deleteWrapper($pageTitle); } - //$apiResult = array($resultSection, $resultChapters); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'delete-section-task': $user = CourseEditorUtils::getRequestContext()->getUser(); $sectionName = $value->elementName; $title = Title::newFromText( $courseName . '/' . $sectionName, $defaultNamespace=NS_MAIN ); $pageTitle = $courseName . '/' . $sectionName; if(!$title->userCan('delete', $user, 'secure')){ $prependText = "\r\n{{DeleteMe}}"; $apiResult = CourseEditorUtils::editWrapper($pageTitle, null, $prependText, null); }else { $apiResult = CourseEditorUtils::deleteWrapper($pageTitle); } CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'add': $sectionName = $value->elementName; $pageTitle = $courseName . '/' . $sectionName; $text = ""; $apiResult = CourseEditorUtils::editWrapper($pageTitle, $text, null, null); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'update': $newCourseText = "{{CCourse|\r\n"; $newSectionsArray = json_decode($value->elementsList); foreach ($newSectionsArray as $section) { $newCourseText .= "{{SSection|" . $section ."}}\r\n"; } $newCourseText .= "}}"; $categories = CourseEditorUtils::getCategories($courseName); if(sizeof($categories) > 0){ foreach ($categories as $category) { $newCourseText .= "\r\n[[" . $category['title'] . "]]"; } } $apiResult = CourseEditorUtils::editWrapper($courseName, $newCourseText, null, null); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'update-collection': $apiResult = CourseEditorUtils::updateCollection($courseName); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; /*case 'fix-link': $targetPage = $value->elementName; $linkToReplace = $value->linkToReplace; list($course, $section, $chapter) = explode('/', $linkToReplace); $replacement = $course . '/' . $value->replacement . '/' . $chapter; $title = Title::newFromText($targetPage); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); $newText = str_replace(str_replace(' ', '_', $linkToReplace), $replacement, $text); $apiResult = CourseEditorUtils::editWrapper($targetPage, $newText, null, null); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); $value->text = $newText; break;*/ } return json_encode($value); } public static function applySectionOp($sectionName, $operation){ $context = CourseEditorUtils::getRequestContext(); $value = json_decode($operation); switch ($value->action) { case 'rename': $chapterName = $value->elementName; $newChapterName = $value->newElementName; $from = $sectionName . '/' . $chapterName; $to = $sectionName . '/' . $newChapterName; $apiResult = CourseEditorUtils::moveWrapper($from, $to); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'delete': $user = $context->getUser(); $chapterName = $value->elementName; $title = Title::newFromText($sectionName . '/' . $chapterName, $defaultNamespace=NS_MAIN); if(!$title->userCan('delete', $user, 'secure')){ $pageTitle = $sectionName . '/' . $chapterName; $prependText = "\r\n{{DeleteMe}}"; $apiResult = CourseEditorUtils::editWrapper($pageTitle, null, $prependText, null); }else { $pageTitle = $sectionName . '/' . $chapterName; $apiResult = CourseEditorUtils::deleteWrapper($pageTitle); } CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'add': $chapterName = $value->elementName; $pageTitle = $sectionName . '/' . $chapterName; $text = ""; $apiResult = CourseEditorUtils::editWrapper($pageTitle, $text, null, null); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'update': $newSectionText = ""; $newChaptersArray = json_decode($value->elementsList); foreach ($newChaptersArray as $chapter) { $newSectionText .= "* [[" . $sectionName . "/" . $chapter ."|". $chapter ."]]\r\n"; } $apiResult = CourseEditorUtils::editWrapper($sectionName, $newSectionText); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'purge': $explodedString = explode("/", $sectionName); $pageToBePurged = (sizeof($explodedString) > 2 ? $explodedString[0] . "/" . $explodedString[1] : $explodedString[0]); $apiResult = CourseEditorUtils::purgeWrapper($pageToBePurged); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; case 'update-collection': $explodedString = explode("/", $sectionName); $courseName = (sizeof($explodedString) > 2 ? $explodedString[0] . "/" . $explodedString[1] : $explodedString[0]); $apiResult = CourseEditorUtils::updateCollection($courseName); CourseEditorUtils::setSingleOperationSuccess($value, $apiResult); break; } return json_encode($value); } } diff --git a/CourseEditorTemplates.php b/CourseEditorTemplates.php index f4f013d..f1edc7a 100644 --- a/CourseEditorTemplates.php +++ b/CourseEditorTemplates.php @@ -1,217 +1,220 @@ data['section']; ?>

-
-
  


+

+ data['course']; ?>

-
-
  


+

+
data['topic']){ $topic = $this->data['topic']; ?>
data['department']){ $department = $this->data['department']; ?>
+

+
data['course']; if($this->data['metadataResult']){ $metadataResult = $this->data['metadataResult']; } ?>


getNamespace(); if(MWNamespace::equals($namespaceIndex, NS_USER)){ self::updateUserCollection($courseName); }else { $pageTitle = "Project:" . wfMessage('courseeditor-collection-book-category') ."/" . $name; $collectionText = "{{" . wfMessage('courseeditor-collection-savedbook-template') . " \n| setting-papersize = a4 \n| setting-toc = auto \n| setting-columns = 1 \n| setting-footer = yes\n}}\n"; $collectionText .= "== " . str_replace('_', ' ', $name) . " ==\r\n"; $sections = self::getSections($courseName); foreach ($sections as $section) { $chapters = self::getChapters($courseName . '/' .$section); $collectionText .= ";" . $section . "\r\n"; foreach ($chapters as $chapter) { $collectionText .= ":[[" . $courseName . "/" . $section . "/" . $chapter . "]]\r\n"; } } $categoryName = wfMessage('courseeditor-collection-book-category'); if ( !$categoryName->isDisabled() ) { $catTitle = Title::makeTitle( NS_CATEGORY, $categoryName ); if ( !is_null( $catTitle ) ) { $collectionText .= "\n[[" . $catTitle->getPrefixedText() ."|" . $name . "]]"; } } $editResult = self::editWrapper($pageTitle, $collectionText, null, null); return $editResult; } } private function updateUserCollection($courseName){ list($namespaceAndUser, $title) = explode('/', $courseName, 2); $pageTitle = $namespaceAndUser . "/" . wfMessage('courseeditor-collection-book-category') . "/" . $title; $collectionText = "{{" . wfMessage('courseeditor-collection-savedbook-template') . " \n| setting-papersize = a4 \n| setting-toc = auto \n| setting-columns = 1 \n| setting-footer = yes\n}}\n"; $collectionText .= "== " . str_replace('_', ' ', $title). " ==\r\n"; $sections = self::getSections($courseName); foreach ($sections as $section) { $chapters = self::getChapters($courseName . '/' .$section); $collectionText .= ";" . $section . "\r\n"; foreach ($chapters as $chapter) { $collectionText .= ":[[" . $courseName . "/" . $section . "/" . $chapter . "]]\r\n"; } } $categoryName = wfMessage('courseeditor-collection-book-category'); if ( !$categoryName->isDisabled() ) { $catTitle = Title::makeTitle( NS_CATEGORY, $categoryName ); if ( !is_null( $catTitle ) ) { $collectionText .= "\n[[" . $catTitle->getPrefixedText() ."|" . $title. "]]"; } } $editResult = self::editWrapper($pageTitle, $collectionText, null, null); return $editResult; } public static function getMetadata($courseName){ $title = Title::newFromText($courseName, $defaultNamespace=NS_COURSEMETADATA ); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); if($text === ''){ return null; } $regex = "/
(.*?)
/s"; preg_match_all($regex, $text, $matches, PREG_PATTERN_ORDER); $metadataResult = array(); $metadataKeys = $matches[1]; $metadataValues = $matches[2]; for ($i=0; $i < sizeof($metadataKeys); $i++) { $metadataResult[$metadataKeys[$i]] = $metadataValues[$i]; } return $metadataResult; } public static function getTopicCourses($topic){ $title = Title::newFromText($topic, $defaultNamespace=NS_MAIN ); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); $textNoNewLines = trim(preg_replace('/\n+/', '', $text)); $regex = "/({{Topic|.+)}}.*$/"; preg_match_all($regex, $textNoNewLines, $matches, PREG_PATTERN_ORDER); return $matches[1][0]; } /** * This method is a workaround (read it HACK) to check the API results. * MediaWiki ApiResult object is not "standard" but if an error/exception * occurs the result variable is a string. */ public static function setSingleOperationSuccess(&$operation, $result){ $isSuccess = true; if (is_string($result)) { $isSuccess = false; } $operation->success = $isSuccess; } /** * This method is a workaround (read it HACK) to check the API results. * MediaWiki ApiResult object is not "standard" but if an error/exception * occurs the result variable is a string. */ - public static function setComposedOperationSuccess(&$operation, $result){ + public static function setComposedOperationSuccess(&$operation, $resultsArray){ $isSuccess = true; - if (is_string($result[0]) || is_string($result[1])) { - $isSuccess = false; + foreach ($resultsArray as $result) { + if (is_string($result)) { + $isSuccess = false; + break; + } } $operation->success = $isSuccess; } public static function getRequestContext(){ if(self::$requestContext == null) { $context = new RequestContext(); self::$requestContext = $context; } return self::$requestContext; } public static function getCategories($courseName){ try { $api = new ApiMain( new DerivativeRequest( self::getRequestContext()->getRequest(), array( 'action' => 'query', 'titles' => $courseName, 'prop' => 'categories' ) ), true ); $api->execute(); $results = $api->getResult()->getResultData(null, array('Strip' => 'all')); $page = reset($results['query']['pages']); return $page['categories']; } catch(UsageException $e){ return $e->getMessage(); } } public static function getChapters($sectionName){ $title = Title::newFromText($sectionName, $defaultNamespace=NS_MAIN ); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); $regex = "/\*\s*\[{2}([^|]*)\|?([^\]]*)\]{2}\s*/"; preg_match_all($regex, $text, $matches, PREG_PATTERN_ORDER); return $matches[2]; } public static function getSections($courseName){ $title = Title::newFromText( $courseName, $defaultNamespace=NS_MAIN ); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); $regex = "/\{{2}SSection\|(.*)\}{2}/"; preg_match_all($regex, $text, $matches, PREG_PATTERN_ORDER); return $matches[1]; } public static function deleteWrapper($title){ $context = self::getRequestContext(); try { $user = $context->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $context->getRequest(), array( 'action' => 'delete', 'title' => $title, 'token' => $token ), true ), true ); $api->execute(); return $api->getResult()->getResultData(null, array('Strip' => 'all')); } catch(UsageException $e){ return $e->getMessage(); } } public static function purgeWrapper($titles){ $context = self::getRequestContext(); try { $api = new ApiMain( new DerivativeRequest( $context->getRequest(), array( 'action' => 'purge', 'titles' => $titles, 'forcerecursivelinkupdate' => true ), true ), true ); $api->execute(); return $api->getResult()->getResultData(null, array('Strip' => 'all')); } catch(UsageException $e){ return $e->getMessage(); } } public static function editWrapper($title, $text, $textToPrepend, $textToAppend){ $context = self::getRequestContext(); try { $user = $context->getUser(); $token = $user->getEditToken(); //$token = $this->getCsrfToken(); $api = new ApiMain( new DerivativeRequest( $context->getRequest(), array( 'action' => 'edit', 'title' => $title, 'text' => $text, // automatically override text 'prependtext' => $textToPrepend, // automatically override text 'appendtext' => $textToAppend, 'notminor' => true, 'token' => $token ), true ), true ); $api->execute(); return $api->getResult()->getResultData(null, array('Strip' => 'all')); } catch(UsageException $e){ return $e->getMessage(); } } public static function moveWrapper($from, $to){ $context = self::getRequestContext(); try { $user = $context->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $context->getRequest(), array( 'action' => 'move', 'from' => $from, 'to' => $to, //'noredirect' => true, 'movetalk' => true, 'movesubpages' => true, 'token' => $token ), true ), true ); $api->execute(); return $api->getResult()->getResultData(null, array('Strip' => 'all')); } catch(UsageException $e){ return $e->getMessage(); } } public static function getBacklinksWrapper($title){ } } diff --git a/extension.json b/extension.json index 942b1b7..913dca9 100644 --- a/extension.json +++ b/extension.json @@ -1,142 +1,144 @@ { "name":"CourseEditor", "version":"0.1.0", "author":[ "Alessandro Tundo", "Gianluca Rigoletti", "Riccardo Iaconelli" ], "url":"https://github.com/WikiToLearn/CourseEditor", "descriptionmsg":"", "license-name":"GPLv3", "type":"special", "AutoloadClasses":{ "CourseEditor":"CourseEditor.php", "CourseEditorOperations":"CourseEditorOperations.php", "CourseEditorUtils":"CourseEditorUtils.php", "SectionEditorTemplate":"CourseEditorTemplates.php", "CourseEditorTemplate" : "CourseEditorTemplates.php", "CourseCreatorTemplate" : "CourseEditorTemplates.php", "ManageMetadataTemplate" : "CourseEditorTemplates.php", "SpecialCourseEditor":"SpecialCourseEditor.php" }, "MessagesDirs":{ "CourseEditor":[ "i18n" ] }, "ExtensionMessagesFiles": { "CourseEditorAlias": "CourseEditor.alias.php", "CourseEditorNamespaces": "CourseEditor.namespaces.php" }, "ResourceFileModulePaths": { "localBasePath": "" }, "ResourceModules": { "ext.courseEditor.manageMetadata": { "scripts":["modules/manageMetadata.js"] }, "ext.courseEditor.create": { "scripts":["modules/createCourse.js"] }, "ext.courseEditor.section": { "scripts":[ "modules/commonFunctions.js", "modules/sectionEditor.js" ], "dependencies": [ "oojs-ui", "mediawiki.util" ], "styles": [ "modules/styles/style.css" ], "messages": [ "courseeditor", "courseeditor-add-new-chapter", "courseeditor-save-section", "courseeditor-cancel", "courseeditor-rename", "courseeditor-edit-dialog", "courseeditor-message-dialog-title", "courseeditor-message-dialog-message", "courseeditor-message-dialog-cancel", "courseeditor-message-dialog-restore", "courseeditor-message-dialog-create-new", "courseeditor-error-operation", "courseeditor-operation-action-add", "courseeditor-operation-action-delete", "courseeditor-operation-action-rename", "courseeditor-operation-action-purge", "courseeditor-operation-action-update", "courseeditor-operation-action-update-collection", "courseeditor-error-operation-fail" ] }, "ext.courseEditor.course": { "scripts":[ "modules/commonFunctions.js", "modules/courseEditor.js" ], "dependencies": [ "oojs-ui", "mediawiki.util" ], "styles": [ "modules/styles/style.css" ], "messages": [ "courseeditor", "courseeditor-add-new-section", "courseeditor-save-course", "courseeditor-cancel", "courseeditor-rename", "courseeditor-edit-dialog", "courseeditor-message-dialog-title", "courseeditor-message-dialog-message", "courseeditor-message-dialog-cancel", "courseeditor-message-dialog-restore", "courseeditor-message-dialog-create-new", "courseeditor-error-operation", "courseeditor-operation-action-add", - "courseeditor-operation-action-delete", - "courseeditor-operation-action-rename", + "courseeditor-operation-action-delete-chapters-task", + "courseeditor-operation-action-delete-section-task", + "courseeditor-operation-action-rename-move-task", + "courseeditor-operation-action-rename-update-task", "courseeditor-operation-action-purge", "courseeditor-operation-action-update", "courseeditor-operation-action-update-collection", "courseeditor-error-operation-fail" ] } }, "namespaces": [ { "id": 2800, "constant": "NS_COURSE", "name": "Course", "subpages" : true }, { "id": 2801, "constant": "NS_COURSE_TALK", "name": "Course_talk", "subpages" : true }, { "id": 2900, "constant": "NS_COURSEMETADATA", "name": "CourseMetadata" } ], "config": { "AjaxExportList": [ "CourseEditorOperations::manageCourseMetadataOp", "CourseEditorOperations::createCourseOp", "CourseEditorOperations::applySectionOp", "CourseEditorOperations::applyCourseOp" ] }, "SpecialPages": { "CourseEditor": "SpecialCourseEditor" }, "manifest_version":1 } diff --git a/i18n/en.json b/i18n/en.json index cfe00d0..6cf091d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,52 +1,54 @@ { "courseeditor" : "Course editor", "courseeditor-managemetata-pagetitle": "Metadata management", "courseeditor-credits-info": "CourseEditor is an extension to create and manage courses.", "courseeditor-add-new-section" : "Add a new section", "courseeditor-save-course": "Save course", "courseeditor-add-new-chapter" : "Add New Chapter", "courseeditor-save-section" : "Save Section", "courseeditor-cancel" : "Cancel", "courseeditor-edit-dialog" : "Edit", "courseeditor-rename" : "Rename", "courseeditor-organize-chapters" : "You can organize, add and delete chapters", "courseeditor-organize-sections" : "You can organize, add and delete sections", "courseeditor-input-department-label" : "Department:", "courseeditor-input-topic-label" : "Topic:", "courseeditor-input-course-label" : "Title:", "courseeditor-input-course-placeholder" : "Insert the title of the course", "courseeditor-input-description-label" : "Description:", "courseeditor-input-description-placeholder" : "Insert a description", "courseeditor-input-externalreferences-label" : "External references:", "courseeditor-input-externalreferences-placeholder" : "Insert external references", "courseeditor-input-reviewed-label" : "Reviewed", "courseeditor-input-imported-label" : "Imported", "courseeditor-input-originalauthors-label" : "Original authors:", "courseeditor-input-originalauthors-placeholder" : "Insert the original authors", "courseeditor-input-reviewedon-label" : "Reviewed on:", "courseeditor-input-reviewedon-placeholder" : "Insert the date (dd/mm/yyyy)", "courseeditor-save-button" : "Save", "courseeditor-create-button" : "Create!", "courseeditor-alert-message" : "Hey, there is a course with the same title yet!
Choose another title or start to contribute immediately to the existing course.", "courseeditor-validate-form" : "Please, insert a topic and a name", "courseeditor-radiobutton-namespace" : "Do you want to creatre a private course in your personal page or a public one?", "courseeditor-radiobutton-namespace-private" : "Private", "courseeditor-radiobutton-namespace-public" : "Public", "courseeditor-message-dialog-title" : "Oops...", "courseeditor-message-dialog-message" : "There's an element in the recycle bin with the same name, what do you want to do?", "courseeditor-message-dialog-cancel" : "Cancel", "courseeditor-message-dialog-restore" : "Restore", "courseeditor-message-dialog-create-new" : "Create new", "courseeditor-alert-message-existing-element" : "There is already an element with the same name. Please, enter a different one.", "courseeditor-recycle-bin" : "Recycle bin", "courseeditor-error-operation" : "Sorry, something went wrong! :(
", "courseeditor-operation-action-add" : "Add", - "courseeditor-operation-action-rename" : "Rename", - "courseeditor-operation-action-delete" : "Delete", + "courseeditor-operation-action-rename-move-task" : "Rename", + "courseeditor-operation-action-rename-update-task" : "Update links", + "courseeditor-operation-action-delete-chapters-task" : "Delete chapters of", + "courseeditor-operation-action-delete-section-task" : "Delete ", "courseeditor-operation-action-purge" : "Purge", "courseeditor-operation-action-update" : "Update", "courseeditor-operation-action-update-collection" : "Update book", "courseeditor-error-operation-fail" : " fails!", "courseeditor-collection-book-category": "Books", "courseeditor-collection-savedbook-template": "saved_book" } diff --git a/i18n/it.json b/i18n/it.json index b6cd82a..b0b324d 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -1,52 +1,54 @@ { "courseeditor" : "Editor di corsi", "courseeditor-managemetata-pagetitle": "Gestione metadati", "courseeditor-credits-info": "CourseEditor è una estensione per creare ed organizzare corsi.", "courseeditor-add-new-section" : "Aggiungi una nuova sezione", "courseeditor-save-course": "Salva corso", "courseeditor-add-new-chapter" : "Aggiungi un nuovo capitolo", "courseeditor-save-section" : "Salva sezione", "courseeditor-cancel" : "Cancella", "courseeditor-edit-dialog" : "Modifica", "courseeditor-rename" : "Rinomina", "courseeditor-organize-chapters" : "Qui puoi organizzare, aggiungere e rimuovere capitoli", "courseeditor-organize-sections" : "Qui puoi organizzare, aggiungere e rimuovere sezioni", "courseeditor-input-department-label" : "Dipartmento:", "courseeditor-input-topic-label" : "Argomento:", "courseeditor-input-course-label" : "Titolo:", "courseeditor-input-course-placeholder" : "Inserisci il titolo del corso", "courseeditor-input-description-label" : "Descrizione:", "courseeditor-input-description-placeholder" : "Insersci la descrizione", "courseeditor-input-externalreferences-label" : "Riferimenti esterni:", "courseeditor-input-externalreferences-placeholder" : "Inserisci i riferimenti esterni", "courseeditor-input-reviewed-label" : "Revisionato", "courseeditor-input-imported-label" : "Importato", "courseeditor-input-originalauthors-label" : "Autori originali:", "courseeditor-input-originalauthors-placeholder" : "Inserisci gli autori originali", "courseeditor-input-reviewedon-label" : "Revisionato il:", "courseeditor-input-reviewedon-placeholder" : "Inserisci la data (gg/mm/aaaa)", "courseeditor-save-button" : "Salva", "courseeditor-create-button" : "Crea!", "courseeditor-alert-message" : "Ehi, c'è un corso con lo stesso titolo!
Scegli un altro titolo o inizia a contribuire subito al corso esitente.
", "courseeditor-validate-form" : "Inserisci l'argomento e il corso!", "courseeditor-radiobutton-namespace" : "Vuoi creare un corso privato nella tua pagina personale o uno pubblico?", "courseeditor-radiobutton-namespace-private" : "Privato", "courseeditor-radiobutton-namespace-public" : "Pubblico", "courseeditor-message-dialog-title" : "Ops...", "courseeditor-message-dialog-message" : "C'è un elemento nel cestino con lo stesso nome, cosa vuoi fare?", "courseeditor-message-dialog-cancel" : "Indietro", "courseeditor-message-dialog-restore" : "Ripristina", "courseeditor-message-dialog-create-new" : "Crea nuovo", "courseeditor-alert-message-existing-element" : "È già presente un elemento con lo stesso nome. Per favore, inserire un nome diverso.", "courseeditor-recycle-bin" : "Cestino", "courseeditor-error-operation" : "Scusa, qualcosa è andato storto! :(
", "courseeditor-operation-action-add" : "Aggiungi", - "courseeditor-operation-action-rename" : "Rinomina ", - "courseeditor-operation-action-delete" : "Elimina", + "courseeditor-operation-action-rename-move-task" : "Rinomina ", + "courseeditor-operation-action-rename-update-task" : "Aggiorna links", + "courseeditor-operation-action-delete-chapters-task" : "Elimina capitoli di", + "courseeditor-operation-action-delete-section-task" : "Elimina", "courseeditor-operation-action-purge" : "Purga", "courseeditor-operation-action-update" : "Aggiorna", "courseeditor-operation-action-update-collection" : "Aggiorna libro", "courseeditor-error-operation-fail" : " fallito!", "courseeditor-collection-book-category": "Libri", "courseeditor-collection-savedbook-template": "libro_salvato" } diff --git a/modules/commonFunctions.js b/modules/commonFunctions.js index c5a44c2..ecc68f0 100644 --- a/modules/commonFunctions.js +++ b/modules/commonFunctions.js @@ -1,465 +1,464 @@ /* Create a gloabal windowManager to open dialogs and append it to the body*/ var windowManager = new OO.ui.WindowManager(); $('body').append( windowManager.$element ); /******** UTIL METHODS ********/ var createMicroOperations = function(operation){ switch (operation.action) { case 'rename': return createRenameMicroOperations(operation); break; case 'delete': return createDeleteMicroOperations(operation); break; default: return createDefaultMicroOperations(operation); } }; var createDefaultMicroOperations = function(operation){ var microOps = []; microOps.push(operation); return microOps; } var createRenameMicroOperations = function(operation) { var microOps = []; microOps.push({ action: 'rename-move-task', elementName: operation.elementName, newElementName: operation.newElementName }); microOps.push({ action: 'rename-update-task', elementName: operation.elementName, newElementName: operation.newElementName }); return microOps; }; var createDeleteMicroOperations = function(operation) { var microOps = []; microOps.push({ action: 'delete-chapters-task', elementName: operation.elementName }); microOps.push({ action: 'delete-section-task', elementName: operation.elementName }); return microOps; }; /* var createMicroDefaultOperations = function(operation, callback) { var microOps = []; microOps.push(operation); callback(microOps); }; var createMicroRenameOperations = function(operation, callback) { var title = new mw.Title($('#courseName').text()); var microOps = []; getSubpages(title, operation, function(subpages){ for (var i = 0; i < subpages.query.allpages.length; i++) { var page = subpages.query.allpages[i]; //The better HACK ever: not return the callback until the for dosn't // completed if(i === subpages.query.allpages.length - 1) { getMicroOpsFromBacklinks(page, operation, microOps, function(microOps) { //Move the page and all its subpages microOps.push(operation); callback(microOps); }); } else { getMicroOpsFromBacklinks(page, operation, microOps, function(){}); } } }); }; var getMicroOpsFromBacklinks = function(page, operation, microOps, returnMicroOps){ var api = new mw.Api(); api.get( { action: 'query', list: 'backlinks', bltitle: page.title, } ).done( function ( data) { if(data.query.backlinks.length > 0){ var backlinks = data.query.backlinks; backlinks.shift(); //the course with transcluded pages for (var i = 0; i < backlinks.length; i++) { microOps.push({ action: 'fix-link', elementName: backlinks[i].title, linkToReplace: page.title, replacement: operation.newElementName }); } } returnMicroOps(microOps); }); }; var getSubpages = function (title, operation, returnSubpages){ var api = new mw.Api(); api.get( { action: 'query', list: 'allpages', apprefix: title.getMain() + "/" + operation.elementName, apnamespace: title.getNamespaceId() } ).done( function ( data) { returnSubpages(data); }); };*/ /** * Init handlers * @param {DraggableGroupWidget} [draggableWidget] * @param {TextInputWidget} [textInputWidget] * @param {Array} [editStack] */ var initHandlers = function(draggableWidget, textInputWidget, editStack){ $('.deleteElementIcon').click(function(){ deleteElement(draggableWidget, $(this).parent().text(), editStack); }); $('.editElementIcon').click(function(){ editElement(draggableWidget, $(this).parent().text(), editStack); }); $('.oo-ui-inputWidget-input').attr('id', 'addElement'); $('#addElement').blur(function(){ $('#alert').hide(); addElement(draggableWidget, textInputWidget.getValue(), editStack); textInputWidget.setValue(''); }); $('#addElement').keypress(function(keypressed) { if(keypressed.which === 13) { addElement(draggableWidget, textInputWidget.getValue(), editStack); textInputWidget.setValue(''); } }); }; /** * Find the index of a deleted element in the editStack * @param {String} [elementName] * @param {Array} [editStack] */ var findIndexOfDeletedElement = function(editStack, elementName) { for (var i = 0; i < editStack.length; i++) { if (editStack[i]['action'] === 'delete' && editStack[i]['elementName'] === elementName) { return i; } } return null; }; /** * Find the index of already added or renamed element in the editStack * @param {String} [elementName] * @param {DraggableWidget} [draggableWidget] * @return boolean */ var elementExist = function(draggableWidget, elementName) { var items = draggableWidget.getItems(); for (var item in items) { if (items[item].data === elementName) { return true; } } return false; }; /** * Create a drag item, its handlers on edit and remove icons and append it to * to the draggableWidget. * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var createDragItem = function(draggableWidget, elementName, editStack){ //Create item and icons var dragItem = new DraggableHandledItemWidget( { data: elementName, icon: 'menu', label: elementName } ); var iconDelete = $(""); var iconEdit = $(""); //Append icons and add the item to draggableWidget dragItem.$label.append(iconDelete, iconEdit); draggableWidget.addItems([dragItem]); //Create handlers $(iconDelete).click(function(){ deleteElement(draggableWidget, $(this).parent().text(), editStack); }); $(iconEdit).click(function(){ editElement(draggableWidget, $(this).parent().text(), editStack); }); }; /** * Create a button list group item, its handler on undo and append it to * to the RecycleBin list group. * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var createRecycleBinItem = function(draggableWidget, elementName, editStack){ //Create item and icon var liButton = $('
  •   ' + elementName +'
  • '); var undoDeleteIcon = $(''); //Append icon and add the item to the list liButton.prepend(undoDeleteIcon); $('.list-group').append(liButton); //Create handler $(undoDeleteIcon).click(function(){ var elementToRestore = $(this).parent().attr('id'); restoreElement(draggableWidget, elementToRestore, editStack); }); } /******** HELPER METHODS ********/ var dequeue = function(queueName){ $(document).dequeue(queueName); }; /** * Delete a element from the draggableWidget and add a item to the * RecycleBin list. * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var deleteElement = function(draggableWidget, elementName, editStack){ var elementToRemove = draggableWidget.getItemFromData(elementName); draggableWidget.removeItems([elementToRemove]); editStack.push({ action: 'delete', elementName: elementName }); createRecycleBinItem(draggableWidget, elementName, editStack); }; /** * Restore a element from the RecycleBin and remove its deletion * from the editStack * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var restoreElement = function(draggableWidget, elementName, editStack){ createDragItem(draggableWidget, elementName, editStack); editStack.splice(editStack.indexOf({action: 'delete', element: elementName})); $('li[id="' + elementName + '"]').remove(); }; /** * Add a element to the draggableWidget automatically if its name isn't * in the RecycleBin list, otherwise open a MessageDialog and ask to the user * if he/she prefer to restore the element or create a new one. * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var addElement = function(draggableWidget, elementName, editStack){ if($.trim(elementName).length !== 0){ if(findIndexOfDeletedElement(editStack, elementName) !== null){ var messageDialog = new OO.ui.MessageDialog(); windowManager.addWindows( [ messageDialog ] ); windowManager.openWindow( messageDialog, { title: OO.ui.deferMsg('courseeditor-message-dialog-title'), message: OO.ui.deferMsg('courseeditor-message-dialog-message'), actions: [ { action: 'reject', label: OO.ui.deferMsg('courseeditor-message-dialog-cancel'), flags: 'safe' }, { action: 'restore', label: OO.ui.deferMsg('courseeditor-message-dialog-restore') }, { action: 'confirm', label: OO.ui.deferMsg('courseeditor-message-dialog-create-new'), flags: [ 'primary', 'constructive' ] } ] } ).then( function ( opened ) { opened.then( function ( closing, data ) { if ( data && data.action === 'restore' ) { restoreElement(draggableWidget, elementName, editStack); } else if(data && data.action === 'confirm') { createDragItem(draggableWidget, elementName, editStack); editStack.push({ action: 'add', elementName: elementName }); } } ); } ); }else if (elementExist(draggableWidget, elementName)) { $('#alert').show(); }else { createDragItem(draggableWidget, elementName, editStack); editStack.push({ action: 'add', elementName: elementName }); } } }; /** * Rename a element * @param {DraggableGroupWidget} [draggableWidget] * @param {String} [elementName] * @param {Array} [editStack] */ var editElement = function(draggableWidget, elementName, editStack){ var dialog = new EditDialog(draggableWidget, elementName, editStack); windowManager.addWindows( [ dialog ] ); windowManager.openWindow( dialog ); }; /******** OO.UI OBJECTS ********/ -//var progressBar = new OO.ui.ProgressBarWidget(); function ProgressDialog( config ) { ProgressDialog.parent.call( this, config ); }; OO.inheritClass( ProgressDialog, OO.ui.Dialog ); ProgressDialog.static.escapable = false; ProgressDialog.prototype.initialize = function () { ProgressDialog.parent.prototype.initialize.call( this ); this.progressBar = new OO.ui.ProgressBarWidget({ progress: 0 }); this.currentOp = new OO.ui.LabelWidget( { label: '' } ); this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); this.content.$element.append(this.progressBar.$element, this.currentOp.$element); this.$body.append( this.content.$element ); }; ProgressDialog.prototype.getBodyHeight = function () { return this.content.$element.outerHeight( true ); }; ProgressDialog.prototype.updateProgress = function(unitaryIncrement){ var currentProgress = this.progressBar.getProgress(); this.progressBar.setProgress(currentProgress + unitaryIncrement); }; ProgressDialog.prototype.setCurrentOp = function(operation){ var labelToSet = OO.ui.msg('courseeditor-operation-action-' + operation.action); if(operation.elementName){ labelToSet += " " + operation.elementName; } this.currentOp.setLabel(labelToSet); }; /****** Draggable Widget ******/ /** * Draggable group widget containing drag/drop items * * @param {Object} [config] Configuration options */ function DraggableGroupWidget( config ) { // Configuration initialization config = config || {}; // Parent constructor DraggableGroupWidget.parent.call( this, config ); // Mixin constructors OO.ui.mixin.DraggableGroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) ); } /* Setup */ OO.inheritClass( DraggableGroupWidget, OO.ui.Widget ); OO.mixinClass( DraggableGroupWidget, OO.ui.mixin.DraggableGroupElement ); /** * Drag/drop items with custom handle * * @param {Object} [config] Configuration options */ function DraggableHandledItemWidget( config ) { // Configuration initialization config = config || {}; // Parent constructor DraggableHandledItemWidget.parent.call( this, config ); // Mixin constructors OO.ui.mixin.DraggableElement.call( this, $.extend( { $handle: this.$icon }, config ) ); } /* Setup */ OO.inheritClass( DraggableHandledItemWidget, OO.ui.DecoratedOptionWidget ); OO.mixinClass( DraggableHandledItemWidget, OO.ui.mixin.DraggableElement ); /****** Edit Dialog ******/ /* Create a dialog */ function EditDialog(draggableWidget, elementName, editStack, config ) { EditDialog.parent.call( this, config ); this.draggableWidget = draggableWidget; this.elementName = elementName; this.editStack = editStack; this.textInputWidget = new OO.ui.TextInputWidget($.extend( { validate: 'non-empty' }, config ) ); this.textInputWidget.setValue(elementName); } /* Inheritance */ OO.inheritClass( EditDialog, OO.ui.ProcessDialog ); /* Static Properties */ EditDialog.static.title = OO.ui.deferMsg( 'courseeditor-edit-dialog' ); EditDialog.static.actions = [ { action: 'save', label: OO.ui.deferMsg( 'courseeditor-rename' ), flags: 'primary' }, { label: OO.ui.deferMsg( 'courseeditor-cancel' ), flags: 'safe' } ]; /* Initialize the dialog elements */ EditDialog.prototype.initialize = function () { EditDialog.parent.prototype.initialize.apply( this, arguments ); this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); this.content.$element.append(this.textInputWidget.$element ); this.$body.append( this.content.$element ); }; /* Define actions */ EditDialog.prototype.getActionProcess = function ( action ) { var dialog = this; if ( action === 'save' ) { return new OO.ui.Process( function () { var newElementName = dialog.textInputWidget.getValue(); var items = dialog.draggableWidget.getItems(); items.filter(function(element) { if(element.data === dialog.elementName){ element.setData(newElementName); element.setLabel(newElementName); var iconDelete = $(""); var iconEdit = $(""); element.$label.append(iconDelete, iconEdit); $(iconDelete).click(function(){ deleteElement(dialog.draggableWidget, $(this).parent().text(), dialog.editStack); }); $(iconEdit).click(function(){ editElement(dialog.draggableWidget, $(this).parent().text(), dialog.editStack); }); dialog.editStack.push({ action: 'rename', elementName: dialog.elementName, newElementName: newElementName }) } }); dialog.close( { action: action } ); } ); } return EditDialog.parent.prototype.getActionProcess.call( this, action ); }; diff --git a/modules/courseEditor.js b/modules/courseEditor.js index 946f513..a256dcb 100644 --- a/modules/courseEditor.js +++ b/modules/courseEditor.js @@ -1,138 +1,136 @@ $(function () { var dragElements = []; //Add all existing sections to the dragSections array $.each(sections, function(key, value){ var dragItem = new DraggableHandledItemWidget( { data: value, icon: 'menu', label: value } ); dragItem.$label.append("", ""); dragElements.push(dragItem); }); //Create a draggableWidget with the items in the dragSections array var draggableWidget = new DraggableGroupWidget( { items: dragElements } ); var fieldDrag = new OO.ui.FieldLayout(draggableWidget); //Create a textInputWidget for new sections var textInputWidget = new OO.ui.TextInputWidget( { placeholder: OO.ui.deferMsg( 'courseeditor-add-new-section' ) } ); var fieldInput = new OO.ui.FieldLayout( textInputWidget); //Append all created elements to DOM $('#sectionsList').append(fieldDrag.$element, fieldInput.$element); initHandlers(draggableWidget, textInputWidget, editStack); $('#saveCourseButton').click(function(){ var newSections = []; $.each(draggableWidget.getItems(), function(key, value){ newSections.push(value.data); }); editStack.push({ action: 'update', elementsList: JSON.stringify(newSections) }); editStack.push({ action: 'update-collection' }); var progressDialog = new ProgressDialog( { size: 'medium' } ); var unitaryIncrement = 100/editStack.length; windowManager.addWindows( [ progressDialog ] ); windowManager.openWindow( progressDialog ); var doTask = function(microOp, next){ progressDialog.setCurrentOp(microOp); $.getJSON( mw.util.wikiScript(), { action: 'ajax', rs: 'CourseEditorOperations::applyCourseOp', rsargs: [$('#courseName').text(), JSON.stringify(microOp)] }, function ( data ) { - console.log(data); - if (data.success !== true) { - var alert = '
    '; - $('#saveDiv').after(alert); + if (data.success !== true){ $('#alert').html(OO.ui.deferMsg('courseeditor-error-operation')); $('#alert').append(OO.ui.deferMsg('courseeditor-operation-action-' + data.action)); if(data.elementName){ var localizedMsg = " " + data.elementName + OO.ui.msg('courseeditor-error-operation-fail'); $('#alert').append(localizedMsg); }else { $('#alert').append(OO.ui.deferMsg('courseeditor-error-operation-fail')); } + $('#alert').show(); windowManager.closeWindow(progressDialog); $(document).clearQueue('tasks'); }else { progressDialog.updateProgress(unitaryIncrement); next(); } }); }; var createTask = function(microOp){ return function(next){ doTask(microOp, next); } }; /*function prepareCreateMicroOperations(operation) { var dfd=$.Deferred(); createMicroOperations(operation, function(microOps){ for (var i = 0; i < microOps.length; i++) { console.log(microOps[i]); $(document).queue('tasks', createTask(microOps[i])); } dfd.resolve(); }); return dfd.promise(); } var promises = []; while (editStack.length > 0) { var operation = editStack.shift(); promises.push(prepareCreateMicroOperations(operation)); } $.when.apply($, promises).done(function(){ $(document).queue('tasks', createTask({ action: 'update', elementsList: JSON.stringify(newSections) })); $(document).queue('tasks', createTask({ action: 'update-collection' })); $(document).queue('tasks', function(){ windowManager.closeWindow(progressDialog); //window.location.assign('/' + $('#courseName').text()); }); dequeue('tasks'); });*/ while( editStack.length > 0) { var operation = editStack.shift(); var microOps = createMicroOperations(operation); for (var i = 0; i < microOps.length; i++) { $(document).queue('tasks', createTask(microOps[i])); } }; $(document).queue('tasks', function(){ windowManager.closeWindow(progressDialog); window.location.assign('/' + $('#courseName').text()); }); dequeue('tasks'); }); }) diff --git a/modules/createCourse.js b/modules/createCourse.js index 4557a33..315f27b 100644 --- a/modules/createCourse.js +++ b/modules/createCourse.js @@ -1,95 +1,100 @@ $(function () { var delay = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); $('#courseName').keypress(function() { delay(function(){ $('#alert').hide(); $('#createCourseButton').removeAttr('disabled'); if($.trim($('#courseName').val()).length !== 0){ var api = new mw.Api(); if($('#courseTopic').length !== 0){ api.get({ action : 'query', titles : 'Course:' + $('#courseName').val().trim() } ).done( function ( data ) { var pages = data.query.pages; if (!pages['-1']) { for (var pageId in pages) { - if (pages.hasOwnProperty(pagesId)) { + if (pages.hasOwnProperty(pageId)) { $('#coursesList').html('' + pages[pageId].title + '
    '); } } $('#createCourseButton').attr('disabled', true); $('#alert').show(); } } ); }else { api.get({ action : 'query', list : 'prefixsearch', pssearch : $('#courseName').val().trim(), psnamespace: '2800', psprofile: 'classic' }).done( function ( data ) { $('#coursesList').html(''); var resultsArray = data.query.prefixsearch; if (resultsArray.length > 0) { for (var i = 0; i < resultsArray.length; i++){ //Exit when the result is a subpage if(resultsArray[i].title.indexOf('/') >= 0) break; $('#coursesList').append('' + resultsArray[i].title + '
    '); } $('#createCourseButton').attr('disabled', true); $('#alert').show(); } }); } } }, 500 ); }); $('#createCourseButton').click(function(e){ e.preventDefault(); var courseName = $('#courseName').val().trim(); var courseDescription = $('#courseDescription').val().trim(); var courseNamespace = $('input[name="courseNamespace"]:checked').val(); var courseTopic, courseDepartment, operationRequested; if($('#courseTopic').length !== 0){ courseTopic = $('#courseTopic').val().trim(); operationRequested = { type : 'fromTopic', params : [ courseTopic, courseName, courseDescription, courseNamespace ] }; }else{ courseDepartment = $('#courseDepartment').val().trim(); operationRequested = { type : 'fromDepartment', params : [ courseDepartment, courseName, courseDescription, courseNamespace ] }; } $.post( mw.util.wikiScript(), { action: 'ajax', rs: 'CourseEditorOperations::createCourseOp', rsargs: [JSON.stringify(operationRequested)] - }, function ( data ) { - //window.location.assign('/' + courseTopic); + }, function ( result ) { + var resultObj = JSON.parse(result); + if(resultObj.success !== true){ + $('#alertError').show(); + }else { + window.location.assign('/' + resultObj.courseTitle); + } }); }); }) diff --git a/modules/sectionEditor.js b/modules/sectionEditor.js index 4f6385a..2e0038b 100644 --- a/modules/sectionEditor.js +++ b/modules/sectionEditor.js @@ -1,97 +1,100 @@ $(function () { var dragElements = []; //Add all existing chapters to the dragElements array $.each(chapters, function(key, value){ var dragItem = new DraggableHandledItemWidget( { data: value, icon: 'menu', label: value } ); dragItem.$label.append("", ""); dragElements.push(dragItem); }); //Create a draggableWidget with the items in the dragElements array var draggableWidget = new DraggableGroupWidget( { items: dragElements } ); var fieldDrag = new OO.ui.FieldLayout(draggableWidget); //Create a textInputWidget for new chapters var textInputWidget = new OO.ui.TextInputWidget( { placeholder: OO.ui.deferMsg( 'courseeditor-add-new-chapter' ) } ); var fieldInput = new OO.ui.FieldLayout( textInputWidget); //Append all created elements to DOM $('#chaptersList').append(fieldDrag.$element, fieldInput.$element); //Init Handlers initHandlers(draggableWidget, textInputWidget, editStack); $('#saveSectionButton').click(function(){ var newChapters = []; $.each(draggableWidget.getItems(), function(key, value){ newChapters.push(value.data); }); editStack.push({ action: 'update', elementsList: JSON.stringify(newChapters) }); editStack.push({ action: 'purge' }); editStack.push({ action: 'update-collection' }); var progressDialog = new ProgressDialog( { size: 'medium' } ); + var unitaryIncrement = 100/editStack.length; + windowManager.addWindows( [ progressDialog ] ); windowManager.openWindow( progressDialog ); var createTask = function(operation){ return function(next){ doTask(operation, next); } }; var doTask = function(operation, next){ + progressDialog.setCurrentOp(operation); $.getJSON( mw.util.wikiScript(), { action: 'ajax', rs: 'CourseEditorOperations::applySectionOp', rsargs: [$('#sectionName').text(), JSON.stringify(operation)] }, function ( data ) { if (data.success !== true) { - var alert = '
    '; - $('#saveDiv').after(alert); $('#alert').html(OO.ui.msg('courseeditor-error-operation')); - $('#alert').append(OO.ui.msg('courseeditor-error-operation-action-' + data.action)); + $('#alert').append(OO.ui.msg('courseeditor-operation-action-' + data.action)); if(data.elementName){ var localizedMsg = " " + data.elementName + OO.ui.msg('courseeditor-error-operation-fail'); $('#alert').append(localizedMsg); }else { $('#alert').append(OO.ui.msg('courseeditor-error-operation-fail')); } + $('#alert').show(); windowManager.closeWindow(progressDialog); $(document).clearQueue('tasks'); }else{ + progressDialog.updateProgress(unitaryIncrement); next(); } }); }; while( editStack.length > 0 ) { var operation = editStack.shift(); $(document).queue('tasks', createTask(operation)); }; $(document).queue('tasks', function(){ windowManager.closeWindow(progressDialog); window.location.assign('/' + $('#sectionName').text()); }); dequeue('tasks') }); })