Sebschlicht2 has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/341136 )

Change subject: edit resource files via JS modals
......................................................................

edit resource files via JS modals

This change allows users to edit external resource files on the entity
page it's associated to.
The page titles has been moved to MoocEntity, as it's more natural.
Boostrap classes have been applied to the modal box form controls.
The JavaScript code has been extended by functions to create resource
entities and edit them as Wikitext, due to the edit hook.
The resource file content is now passed via the JS config vars instead
of being retrieved via AJAX. This significantly increases the
usability. The structure provider thus loads resource entities and
connects them to their parental item, instead of using transclusion.

Change-Id: I3344b39dadf6c87abbe31242cee83e2ddeef969d
---
M includes/model/MoocEntity.php
M includes/model/MoocItem.php
M includes/rendering/MoocContentRenderer.php
M includes/rendering/MoocLessonRenderer.php
M includes/rendering/MoocOverviewRenderer.php
M includes/structure/MoocContentStructureProvider.php
M resources/js/ext.mooc.edit.js
7 files changed, 121 insertions(+), 132 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MOOC 
refs/changes/36/341136/1

diff --git a/includes/model/MoocEntity.php b/includes/model/MoocEntity.php
index 4a56099..bb2a5cc 100644
--- a/includes/model/MoocEntity.php
+++ b/includes/model/MoocEntity.php
@@ -34,10 +34,26 @@
     public function __construct( $type, $title = null ) {
         $this->type = $type;
         // TODO completely separate page Title from MOOC entities?
+        $this->setTitle( $title );
+    }
+
+    /**
+     * Sets the page title.
+     *
+     * @param Title $title page title
+     */
+    public function setTitle( $title ) {
         $this->title = $title;
     }
 
     /**
+     * @return bool whether the entity has child entities
+     */
+    public function hasChildren() {
+        return false;
+    }
+
+    /**
      * Loads the entity fields from a JSON array.
      *
      * @param array $jsonArray associative array (e.g. from json_decode)
diff --git a/includes/model/MoocItem.php b/includes/model/MoocItem.php
index abaeb62..ef27070 100644
--- a/includes/model/MoocItem.php
+++ b/includes/model/MoocItem.php
@@ -20,13 +20,13 @@
     const JFIELD_VIDEO = 'video';
 
     /**
-     * JSON field identifier for the script page title
+     * JSON field identifier for the script
      */
-    const JFIELD_SCRIPT_TITLE = 'scriptTitle';
+    const JFIELD_SCRIPT = 'script';
     /**
-     * JSON field identifier for the quiz page title
+     * JSON field identifier for the quiz
      */
-    const JFIELD_QUIZ_TITLE = 'quizTitle';
+    const JFIELD_QUIZ = 'quiz';
 
     /**
      * JSON field identifier for further reading material
@@ -54,14 +54,14 @@
     public $video;
 
     /**
-     * @var Title title of the script associated with this item
+     * @var MoocResource|null script associated with this item
      */
-    public $scriptTitle;
+    public $script;
 
     /**
-     * @var Title title of the quiz associated with this item
+     * @var MoocResource|null quiz associated with this item
      */
-    public $quizTitle;
+    public $quiz;
 
     /**
      * @var string[] resources of further reading
@@ -75,9 +75,6 @@
 
     public function __construct( $type, $title = null ) {
         parent::__construct( $type, $title );
-
-        // set script and quiz title
-        $this->setTitle( $title );
     }
 
     protected function loadJson( $jsonArray ) {
@@ -92,13 +89,8 @@
         }
     }
 
-    /**
-     * Sets the title and updates the titles of potentially associated 
resources.
-     *
-     * @param $title Title page title
-     */
     public function setTitle( $title ) {
-        $this->title = $title;
+        parent::setTitle( $title );
         $this->scriptTitle = ( $title === null ) ? null : Title::newFromText( 
$title . '/script' );
         $this->quizTitle = ( $title === null ) ? null : Title::newFromText( 
$title . '/quiz' );
     }
@@ -114,7 +106,7 @@
      * @return boolean whether the item has children
      */
     public function hasChildren() {
-        return isset( $this->children ) && !empty( $this->children );
+        return !empty( $this->children );
     }
 
     public function toJson() {
@@ -122,6 +114,8 @@
             self::JFIELD_TYPE => $this->type,
             self::JFIELD_LEARNING_GOALS => $this->learningGoals,
             self::JFIELD_VIDEO => $this->video,
+            self::JFIELD_SCRIPT => ( $this->script !== null ) ? 
$this->script->toJson() : null,
+            self::JFIELD_QUIZ => ( $this->quiz !== null ) ? 
$this->quiz->toJson() : null,
             self::JFIELD_FURTHER_READING => $this->furtherReading
         ];
     }
diff --git a/includes/rendering/MoocContentRenderer.php 
b/includes/rendering/MoocContentRenderer.php
index 7b2618e..820d909 100644
--- a/includes/rendering/MoocContentRenderer.php
+++ b/includes/rendering/MoocContentRenderer.php
@@ -184,11 +184,11 @@
     }
 
     protected function addScriptSection() {
-        $this->beginSection(self::SECTION_KEY_SCRIPT);
-        
-        if ($this->item->scriptTitle->exists()) {
-            // transclude script if existing
-            $this->out->addWikiText('{{:' . $this->item->scriptTitle . '}}');
+        $this->beginSection( self::SECTION_KEY_SCRIPT );
+
+        // add script if existing
+        if ( $this->item->script !== null ) {
+            $this->out->addWikiText( $this->item->script->content );
         } else {
             // show info box if script not created yet
             // TODO pass link to edit script resource page
@@ -199,11 +199,11 @@
     }
 
     protected function addQuizSection() {
-        $this->beginSection(self::SECTION_KEY_QUIZ);
-        
-        if ($this->item->quizTitle->exists()) {
-            // transclude quiz if existing
-            $this->out->addWikiText('{{:' . $this->item->quizTitle . '}}');
+        $this->beginSection( self::SECTION_KEY_QUIZ );
+
+        // add quiz if existing
+        if ( $this->item->quiz !== null ) {
+            $this->out->addWikiText( $this->item->quiz->content );
         } else {
             // show info box if quiz not created yet
             // TODO pass link to edit quiz resource page
@@ -365,7 +365,7 @@
             switch ($sectionKey) {
                 case self::SECTION_KEY_VIDEO:
                     // simple text input field
-                    $this->out->addHTML('<input type="text" class="value" />');
+                    $this->out->addHTML( '<input type="text" class="value 
form-control" />' );
                     break;
 
                 // ordered lists
@@ -376,7 +376,7 @@
 
                 default:
                     // auto-growing textarea
-                    $this->out->addHTML('<textarea class="value auto-grow" 
rows="1"></textarea>');
+                    $this->out->addHTML( '<textarea class="value auto-grow 
form-control" rows="1"></textarea>' );
                     break;
             }
         }
@@ -494,22 +494,32 @@
      *
      * @param MoocItem $item MOOC item to add
      */
-    protected function addNavigationItem($item) {
-        $this->out->addHTML('<li>');
-        $this->out->addWikiText('[[' . $item->title . '|' . $item->getName() . 
']]');
+    protected function addNavigationItem( $item ) {
+        $this->out->addHTML( '<li>' );
+        $this->out->addWikiText( '[[' . $item->title . '|' . $item->getName() 
. ']]' );
         // register link for interwiki meta data
-        $this->parserOutput->addLink($item->title);
+        $this->parserOutput->addLink( $item->title );
         // TODO do this for next/previous links and displayed children as well
         
         // add menu items for children - if any
-        if ($item->hasChildren()) {
-            $this->out->addHTML('<ul>');
+        if ( $item->hasChildren() ) {
+            // limit to MoocItems
+            $children = [];
             foreach ($item->children as $childItem) {
-                $this->addNavigationItem($childItem);
+                if ( $childItem instanceof MoocItem ) {
+                    array_push( $children, $childItem );
+                }
             }
-            $this->out->addHTML('</ul>');
+
+            if ( !empty( $children ) ) {
+                $this->out->addHTML( '<ul>' );
+                foreach ( $children as $childItem ) {
+                    $this->addNavigationItem( $childItem );
+                }
+                $this->out->addHTML( '</ul>' );
+            }
         }
-        $this->out->addHTML('</li>');
+        $this->out->addHTML( '</li>' );
     }
 
     /**
diff --git a/includes/rendering/MoocLessonRenderer.php 
b/includes/rendering/MoocLessonRenderer.php
index 8777063..3031710 100644
--- a/includes/rendering/MoocLessonRenderer.php
+++ b/includes/rendering/MoocLessonRenderer.php
@@ -172,7 +172,7 @@
 
     protected function fillModalBoxForm( $sectionKey, $action ) {
         if ( $sectionKey == self::SECTION_KEY_UNITS && $action == 
self::ACTION_ADD ) {
-            $this->out->addHTML( '<input type="text" class="value" />' );
+            $this->out->addHTML( '<input type="text" class="value 
form-control" />' );
         } else {
             parent::fillModalBoxForm( $sectionKey, $action );
         }
diff --git a/includes/rendering/MoocOverviewRenderer.php 
b/includes/rendering/MoocOverviewRenderer.php
index a1e8edd..d58aa81 100644
--- a/includes/rendering/MoocOverviewRenderer.php
+++ b/includes/rendering/MoocOverviewRenderer.php
@@ -67,7 +67,7 @@
 
     protected function fillModalBoxForm( $sectionKey, $action ) {
         if ( $sectionKey == self::SECTION_KEY_LESSONS && $action == 
self::ACTION_ADD ) {
-            $this->out->addHTML( '<input type="text" class="value" />' );
+            $this->out->addHTML( '<input type="text" class="value 
form-control" />' );
         } else {
             parent::fillModalBoxForm( $sectionKey, $action );
         }
diff --git a/includes/structure/MoocContentStructureProvider.php 
b/includes/structure/MoocContentStructureProvider.php
index 2cd872b..bbe8d54 100644
--- a/includes/structure/MoocContentStructureProvider.php
+++ b/includes/structure/MoocContentStructureProvider.php
@@ -54,13 +54,11 @@
             $contentModel = new MoocContent( $row->old_text );
             if ( $contentModel->isValid() ) {
                 $item = $contentModel->loadItem();
-                if ( $item instanceof MoocItem ) {
-                    $item->setTitle( Title::newFromText( $row->page_title, 
$namespace ) );
-                    array_push( $items, $item );
-                }
+                $item->setTitle( Title::newFromText( $row->page_title, 
$namespace ) );
+                // this adds the rendered item as well
+                array_push( $items, $item );
             }
         }
-
 
         // load structure from item titles
         //TODO this requires the items to be sorted by title while children 
arrays MUST maintain the original creation ordering
@@ -81,11 +79,12 @@
             }
         }
 
+        // build item hierarchy
         $prevLesson = null;
         foreach ( $items as $item ) {
             // determine item parent
             $parent = $rootItem;
-            if ($prevLesson != null && $item->title->isSubpageOf( 
$prevLesson->title )) {
+            if ( $prevLesson !== null && $item->title->isSubpageOf( 
$prevLesson->title ) ) {
                 // child unit of previous lesson
                 $parent = $prevLesson;
             } else {
@@ -93,11 +92,21 @@
                 $prevLesson = $item;
             }
 
-            // register item as child of parent
-            if ( !isset( $parent->children ) ) {
-                $parent->children = [];
+            if ( $item instanceof MoocItem ) {
+                // register item as child of parent
+                if ( !isset( $parent->children ) ) {
+                    $parent->children = [];
+                }
+                array_push( $parent->children, $item );
+            } elseif ( $item instanceof MoocResource
+                && $parent->title !== null && $parent->title->equals( 
$renderedItem->title ) ) {
+                // register resource to rendered item
+                if ( $item instanceof MoocScript ) {
+                    $renderedItem->script = $item;
+                } else if ( $item instanceof MoocQuiz ) {
+                    $renderedItem->quiz = $item;
+                }
             }
-            array_push( $parent->children, $item );
         }
         $renderedItem->baseItem = $rootItem;
 
diff --git a/resources/js/ext.mooc.edit.js b/resources/js/ext.mooc.edit.js
index 5548f24..5ae74b5 100644
--- a/resources/js/ext.mooc.edit.js
+++ b/resources/js/ext.mooc.edit.js
@@ -71,56 +71,6 @@
   }
 
   /**
-   * Gets the raw content of a page.
-   *
-   * @param title page title
-   * @returns {*} jQuery-promise on the AJAX request
-   */
-  function apiGetRawPage( title ) {
-    mw.log( 'loading raw content of page ' + title );
-    return new mw.Api().get( {
-      'action': 'query',
-      'prop': 'revisions',
-      'rvprop': 'content',
-      'titles': title
-    } ).then( function ( json ) {
-      mw.log( 'The page has been retrieved successfully. Response:' );
-      mw.log( json );
-      return getFirstPageRevisionContent( json );
-    } ).fail( function ( code, response ) {
-      mw.log.warn( 'Failed to save the item! Cause:' );
-      mw.log.warn( response.error );
-      mw.log( response );
-
-      if ( code === "http" ) {
-        mw.log.warn( "HTTP error: " + response.textStatus ); // result.xhr 
contains the jqXHR object
-      }
-      //TODO show the user that the process has failed!
-    } );
-  }
-
-  /**
-   * Extracts the content of the first revision of the first page in a 
revisions query response.
-   *
-   * @param json revisions query response
-   * @returns {string|null} content of the first revision of the first page in 
the revisions query response
-   */
-  function getFirstPageRevisionContent( json ) {
-    if ( 'query' in json && 'pages' in json.query ) {
-      var page = null;
-      for ( var key in json.query.pages ) {
-        page = json.query.pages[key];
-        if ( 'revisions' in page ) {
-          if ( page.revisions.length > 0 && '*' in page.revisions[0] ) {
-            return page.revisions[0]['*'];
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
    * Creates a non-existing Wikipage.
    *
    * @param title page title
@@ -193,10 +143,33 @@
    * @returns {*} jQuery-promise on the AJAX request
    */
   function apiSaveItem( title, item, summary ) {
-    // remove temporary values TODO is there a better way to do this? prevents 
to extend the JSON by these fields
+    // remove temporary values
     delete item.script;
     delete item.quiz;
     return apiSavePage( title, JSON.stringify( item ), summary );
+  }
+
+  /**
+   * Saves or creates a resource entity.
+   *
+   * @param title resource entity page title
+   * @param content resource file content
+   * @param summary edit summary
+   * @param create flag whether to create the page
+   * @param type type of the resource entity that should be created
+   * @returns {*} jQuery-promise on the AJAX request
+   */
+  function apiSaveResourceEntity( title, content, summary, create, type ) {
+    if ( create === true && type !== undefined && type !== null ) {
+      // the content needs to validate against MoocResource when creating the 
page
+      content = JSON.stringify({
+        'type': type,
+        'content': content
+      });
+      return apiCreatePage( title, content, summary );
+    } else {
+      return apiSavePage( title, content, summary );
+    }
   }
 
   /**
@@ -272,6 +245,8 @@
     $btnSave.on( 'click', onSaveItem );
     var $btnReset = $form.find( '.btn-reset' );
     $btnReset.on( 'click', onResetModal );
+    var $autoGrowingTextarea = $form.find( 'textarea.auto-grow' );
+    $autoGrowingTextarea.on( 'input', onTextareaValueChanged );
   }
 
   /**
@@ -293,25 +268,13 @@
 
       case 'script':
       case 'quiz':
-        // enable textarea to grow automatically and inject remote page content
-        var $textarea = $form.find( 'textarea.value' );
-        if ( item[section] === undefined ) {
-          mw.log( 'registering hooks on auto-growing textarea: ' + 
$textarea.length );
-          $textarea.on( 'input', onTextareaValueChanged );
-          $btnSave.prop( 'disabled', true );
-          // download remote page content
-          var title = mw.config.get( 'wgPageName' ) + '/' + section;
-          apiGetRawPage( title ).then( function ( content ) {
-            mw.log( section + ( ( content !== null ) ? ' loaded' : ' is empty' 
) );
-            item[section] = content;
-            $textarea.val( content );
-            resizeTextarea( $textarea );
-            $btnSave.prop( 'disabled', false );
-          } );
-        } else {
-          $textarea.val( item[section] );
+        // inject resource file content, if any, and resize textarea
+        if ( item[section] !== null ) {
+          var $textarea = $form.find( 'textarea.value' );
+          $textarea.val( item[section].content );
           resizeTextarea( $textarea );
         }
+        $btnSave.prop( 'disabled', false );
         break;
 
       default:
@@ -350,20 +313,17 @@
 
       case 'script':
       case 'quiz':
-        var externalPageExists = ( item[section] !== undefined && 
item[section] !== null );
-        item[section] = $form.find( '.value' ).val();
         // TODO show loading indicator
-        if ( externalPageExists ) {
-          apiSavePage( item[section + 'Title'], item[section], editSummary 
).then( function ( ) {
-            // reload page on success
-            reloadPage();
-          } );
-        } else {
-          apiCreatePage( item[section + 'Title'], item[section], editSummary 
).then( function ( ) {
-            // reload page on success
-            reloadPage();
-          } );
-        }
+        var resourcePageTitle = mw.config.get( 'wgPageName' ) + '/' + section;
+        var resourcePageContent = $form.find( '.value' ).val();
+        var resourcePageExists = ( item[section] !== null );
+
+        // save/create the resource entity to its page
+        apiSaveResourceEntity( resourcePageTitle, resourcePageContent, 
editSummary,
+          !resourcePageExists, section ).then( function ( ) {
+          // reload page on success
+          reloadPage();
+        } );
         break;
     }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/341136
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3344b39dadf6c87abbe31242cee83e2ddeef969d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MOOC
Gerrit-Branch: master
Gerrit-Owner: Sebschlicht2 <sebschli...@uni-koblenz.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to