diff --git a/CourseEditorTemplates.php b/CourseEditorTemplates.php index a5665c3..657642d 100644 --- a/CourseEditorTemplates.php +++ b/CourseEditorTemplates.php @@ -1,68 +1,68 @@ data['chapters']; $section = $this->data['section']; ?>

-
  Recycle bin
+
  
data['course']; ?>

-
  Recycle bin
+
  
getRequest(); $user = $this->getUser(); if ( ! ( $user->isAllowed( 'move' ) ) ) { // The effect of loading this page is comparable to purge a page. // If desired a dedicated right e.g. "viewmathstatus" could be used instead. throw new PermissionsError( 'move' ); } switch ($request->getVal('actiontype')){ case 'editsection': $sectionName = $request->getVal('pagename'); $this->editSection($sectionName); return; case 'savesection': $sectionName = $request->getVal('sectionName'); $originalChapters = $request->getVal('originalChapters'); $editStack = $request->getVal('editStack'); $newChapters = $request->getVal('newChapters'); $this->saveSection($sectionName, $originalChapters, $editStack, $newChapters); return; case 'editcourse': $courseName = $request->getVal('pagename'); $this->editCourse($courseName); return; case 'savecourse': $courseName = $request->getVal('courseName'); $originalSections = $request->getVal('originalSections'); $editStack = $request->getVal('editStack'); $newSections = $request->getVal('newSections'); $this->saveCourse($courseName, $originalSections, $editStack, $newSections); return; + case 'movecourse': + $courseName = $request->getVal('pagename'); + $this->moveCourse($courseName); + return; default: $this->createNewCourse(); return; } } private function editCourse($courseName){ $out = $this->getOutput(); $out->enableOOUI(); $title = Title::newFromText( $courseName, $defaultNamespace=NS_MAIN ); $page = WikiPage::factory( $title ); $content = $page->getContent( Revision::RAW ); $text = ContentHandler::getContentText( $content ); $regex = "/\{{2}\w+\|(.*)\}{2}/"; preg_match_all($regex, $text, $matches, PREG_PATTERN_ORDER); $this->sectionsList = $matches[1]; $this->setHeaders(); $out->setPageTitle("Course Editor"); $out->addInlineScript(" var sections = " . json_encode($this->sectionsList) . ", editStack = [];"); $out->addModules( 'ext.courseEditor.course' ); $template = new CourseEditorTemplate(); $template->setRef('courseEditor', $this); $template->set('context', $this->getContext()); $template->set('course', $courseName); $out->addTemplate( $template ); } private function saveCourse($courseName, $originalSections, $editStack, $newSections){ $stack = json_decode($editStack); foreach ($stack as $value) { switch ($value->action) { case 'rename': $sectionName = $value->elementName; $newSectionName = $value->newElementName; $title = Title::newFromText( $courseName . "/" . $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); $chapters = $matches[2]; $newSectionText = ""; foreach ($chapters as $value) { $newSectionText .= "* [[" . $courseName . "/" . $newSectionName . "/" . $value ."|". $value ."]]\r\n"; } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $courseName . "/" . $sectionName, 'text' => $newSectionText, 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'move', 'from' => $courseName . '/' . $sectionName, 'to' => $courseName . '/' . $newSectionName, 'token' => $token, 'noredirect' => false, 'movetalk' => true, 'movesubpages'=> true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } break; case 'delete': $user = $this->getContext()->getUser(); $sectionName = $value->elementName; $title = Title::newFromText($courseName . '/' . $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); $chapters = $matches[2]; if(!$title->userCan('delete', $user, 'secure')){ try { $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $courseName . '/' . $sectionName, 'prependtext' => '{{deleteme}}', 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } foreach ($chapters as $value) { try { $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $courseName . '/' . $sectionName . '/' . $value, 'prependtext' => '{{deleteme}}', 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } }else { foreach ($chapters as $value) { try { $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'delete', 'title' => $courseName . '/' . $sectionName . '/' . $value, 'token' => $token ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'delete', 'title' => $courseName . '/' . $sectionName, 'token' => $token ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } break; case 'add': $sectionName = $value->elementName; try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $courseName . '/' . $sectionName, 'text' => "", 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } break; } } - $newCourseText = "[{{fullurl:Special:CourseEditor|actiontype=editcourse&pagename={{FULLPAGENAME}}}} Modifica]\r\n"; + $newCourseText = "[{{fullurl:Special:CourseEditor|actiontype=editcourse&pagename={{FULLPAGENAMEE}}}} Modifica]\r\n"; $newSectionsArray = json_decode($newSections); foreach ($newSectionsArray as $value) { $newCourseText .= "{{Sezione|" . $value ."}}\r\n"; } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $courseName, 'text' => $newCourseText, 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } private function saveSection($sectionName, $originalChapters, $editStack, $newChapters){ $out = $this->getOutput(); $stack = json_decode($editStack); foreach ($stack as $value) { switch ($value->action) { case 'rename': $chapterName = $value->elementName; $newChapterName = $value->newElementName; try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'move', 'from' => $sectionName . '/' . $chapterName, 'to' => $sectionName . '/' . $newChapterName, 'token' => $token, 'noredirect' => false, 'movetalk' => true, 'movesubpages'=> true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } break; case 'delete': $user = $this->getContext()->getUser(); $chapterName = $value->elementName; $title = Title::newFromText($sectionName . '/' . $chapterName, $defaultNamespace=NS_MAIN); if(!$title->userCan('delete', $user, 'secure')){ try { $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $sectionName . '/' . $chapterName, 'prependtext' => '{{deleteme}}', 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } }else { try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'delete', 'title' => $sectionName . '/' . $chapterName, 'token' => $token ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } break; case 'add': $chapterName = $value->elementName; try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $sectionName . '/' . $chapterName, 'text' => "", 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } break; } } $newSectionText = ""; $newChaptersArray = json_decode($newChapters); foreach ($newChaptersArray as $value) { $newSectionText .= "* [[" . $sectionName . "/" . $value ."|". $value ."]]\r\n"; } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'edit', 'title' => $sectionName, 'text' => $newSectionText, 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } try { $user = $this->getContext()->getUser(); $token = $user->getEditToken(); list($course, $section) = explode("/", $sectionName); $api = new ApiMain( new DerivativeRequest( $this->getContext()->getRequest(), array( 'action' => 'purge', 'titles' => $course, 'forcerecursivelinkupdate' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } } private function editSection($sectionName){ $out = $this->getOutput(); $out->enableOOUI(); $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); $this->chaptersList = $matches[2]; $this->setHeaders(); $out->setPageTitle("Section Editor"); $out->addInlineScript(" var chapters = " . json_encode($this->chaptersList) . ", editStack = [];"); $out->addModules( 'ext.courseEditor.section' ); $template = new SectionEditorTemplate(); $template->setRef('courseEditor', $this); $template->set('context', $this->getContext()); $template->set('section', $sectionName); $template->set('chapters', $this->chaptersList); $out->addTemplate( $template ); } + private function moveCourse($courseName){ + $regex = "/\/(.*)/"; + preg_match($regex, $courseName, $matches); + $courseNameWithoutNamespace = $matches[1]; + try { + $user = $this->getContext()->getUser(); + $token = $user->getEditToken(); + $api = new ApiMain( + new DerivativeRequest( + $this->getContext()->getRequest(), + array( + 'action' => 'move', + 'from' => $courseName, + 'to' => MWNamespace::getCanonicalName(NS_COURSE) . ':' . $courseNameWithoutNamespace, + 'token' => $token, + 'noredirect' => true, + 'movetalk' => true, + 'movesubpages'=> true + ), + true // treat this as a POST + ), + true // Enable write. + ); + $api->execute(); + } catch(UsageException $e){ + return $e; + } + } + private function createNewCourse() { $out = $this->getOutput(); $out->enableOOUI(); $formDescriptor = array( 'topic' => array( 'class' => 'HTMLTextField', 'label' => wfMessage( 'courseeditor-set-topic' ) ), 'name' => array( 'class' => 'HTMLTextField', 'label' => wfMessage( 'courseeditor-set-course' ) ), 'namespace' => array( 'class' => 'HTMLRadioField', 'label' => wfMessage('courseeditor-radiobutton-namespace'), 'options' => array( wfMessage('courseeditor-radiobutton-namespace-private')->text() => NS_USER, wfMessage('courseeditor-radiobutton-namespace-public')->text() => NS_COURSE ), 'default' => NS_USER, ) ); $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); $form->setSubmitCallback( array( 'SpecialCourseEditor', 'validateForm' ) ); $form->show(); } public static function validateForm($formData){ if($formData['topic'] != null || $formData['name'] != null){ $context = new RequestContext(); try { $user = $context->getUser(); $token = $user->getEditToken(); $selectedNamespace = $formData['namespace']; $randomCourseId = SpecialCourseEditor::generateRandomCourseId(); $pageTitle = MWNamespace::getCanonicalName($selectedNamespace) . ':'; if($selectedNamespace == NS_USER){ $pageTitle .= $user->getName() . '/' . $formData['name'] . '_' . $randomCourseId; }else{ $pageTitle .= $formData['name'] . '_' . $randomCourseId; } $api = new ApiMain( new DerivativeRequest( $context->getRequest(), array( 'action' => 'edit', 'title' => $pageTitle, 'appendtext' => "{{Course|}}\n\n[[Category:".$formData['topic']."]]", 'token' => $token, 'notminor' => true ), true // treat this as a POST ), true // Enable write. ); $api->execute(); } catch(UsageException $e){ return $e; } return true; } return wfMessage( 'courseeditor-validate-form' ); } public static function generateRandomCourseId(){ $randomCourseId = ''; $switchToChar = true; $random = 0; for ($i=0; $i < 6; $i++) { $random = mt_rand(48, 57); if($switchToChar){ $random += 49; $randomCourseId .= chr($random); $switchToChar = false; }else { $randomCourseId .= chr($random); $switchToChar = true; } } return $randomCourseId; } } diff --git a/extension.json b/extension.json index 7956a78..62c1f27 100644 --- a/extension.json +++ b/extension.json @@ -1,83 +1,93 @@ { "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", "CourseEditorHooks":"CourseEditorHooks.php", "SectionEditorTemplate":"CourseEditorTemplates.php", "CourseEditorTemplate" : "CourseEditorTemplates.php", "SpecialCourseEditor":"SpecialCourseEditor.php" }, "MessagesDirs":{ "CourseEditor":[ "i18n" ] }, "ExtensionMessagesFiles": { "CourseEditorAlias": "CourseEditor.alias.php" }, "ResourceFileModulePaths": { "localBasePath": "" }, "ResourceModules": { "ext.courseEditor.section": { "scripts":[ "modules/commonFunctions.js", "modules/sectionEditor.js" ], "dependencies": [ "oojs-ui" ], "styles": [ "modules/styles/style.css" ], "messages": [ "courseeditor", "courseeditor-add-new-chapter", "courseeditor-save-section", "courseeditor-cancel", "courseeditor-rename", - "courseeditor-edit-dialog" + "courseeditor-edit-dialog", + "courseeditor-message-dialog-title", + "courseeditor-message-dialog-message", + "courseeditor-message-dialog-cancel", + "courseeditor-message-dialog-restore", + "courseeditor-message-dialog-create-new" ] }, "ext.courseEditor.course": { "scripts":[ "modules/commonFunctions.js", "modules/courseEditor.js" ], "dependencies": [ "oojs-ui" ], "styles": [ "modules/styles/style.css" ], "messages": [ "courseeditor", "courseeditor-add-new-section", "courseeditor-save-course", "courseeditor-cancel", "courseeditor-rename", - "courseeditor-edit-dialog" + "courseeditor-edit-dialog", + "courseeditor-message-dialog-title", + "courseeditor-message-dialog-message", + "courseeditor-message-dialog-cancel", + "courseeditor-message-dialog-restore", + "courseeditor-message-dialog-create-new" ] } }, "config":{ }, "Hooks":{ }, "SpecialPages": { "CourseEditor": "SpecialCourseEditor" }, "manifest_version":1 } diff --git a/i18n/en.json b/i18n/en.json index e52d90e..469df42 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,18 +1,24 @@ { "courseeditor" : "Editor di corsi", "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-set-topic" : "Insert the topic", "courseeditor-set-course" : "Insert the name of the 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-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-recycle-bin" : "Recycle bin" } diff --git a/i18n/it.json b/i18n/it.json index 390a81a..616e271 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -1,18 +1,24 @@ { "courseeditor" : "Editor di 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-set-topic" : "Inserisci l'argomento del corso", "courseeditor-set-course" : "Inserisci il nome del corso", "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-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-recycle-bin" : "Cestino" } diff --git a/modules/commonFunctions.js b/modules/commonFunctions.js index 681312b..025af05 100644 --- a/modules/commonFunctions.js +++ b/modules/commonFunctions.js @@ -1,272 +1,271 @@ /* Create a gloabal windowManager to open dialogs and append it to the body*/ var windowManager = new OO.ui.WindowManager(); $('body').append( windowManager.$element ); /******** HELPER METHODS ********/ /** * 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){ createDragItem(draggableWidget, elementName, editStack); editStack.push({ action: 'add', elementName: elementName }); }else { var messageDialog = new OO.ui.MessageDialog(); windowManager.addWindows( [ messageDialog ] ); windowManager.openWindow( messageDialog, { - title: 'Ops...', - message: 'There\'s a deleted element with the same name, what do you want to do?', + title: OO.ui.deferMsg('courseeditor-message-dialog-title'), + message: OO.ui.deferMsg('courseeditor-message-dialog-message'), actions: [ - { action: 'reject', label: 'Cancel', flags: 'safe' }, - { action: 'restore', label: 'Restore' }, + { 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: 'Create new', + 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); - $('button[id="' + elementName + '"]').remove(); } else if(data && data.action === 'confirm') { 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 ); }; /******** UTIL METHODS ********/ /** * 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; }; /** * 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'); - $(this).parent().remove(); restoreElement(draggableWidget, elementToRestore, editStack); }); } /******** OO.UI OBJECTS ********/ /****** 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 ); };