xowf::test_item::Answer_manager method grading_dialog_setup (public)

 <instance of xowf::test_item::Answer_manager[i]> grading_dialog_setup \
    examWf

Defined in packages/xowf/tcl/test-item-procs.tcl

Define the modal dialog and everything necessary for reusing this dialog for multiple occasions. This method registers the pop-up and dismiss handlers for JavaScript and returns the HTML markup of the modal dialog.

Parameters:
examWf (required)
Returns:
HTML block for the modal dialog

Testcases:
No testcase defined.
Source code:
set url [$examWf pretty_link -query m=grade-single-item]

# jquery-ui is just needed for draggable()
::template::add_body_script -src urn:ad:js:jquery-ui

::template::add_body_script -script [subst -novariables {

  function thumbnail_files_setup(element) {
    // to be called on the elements of class ".thumbnail-file"
    element.querySelectorAll('.thumbnail-file-text a.delete')
        .forEach(el => el.addEventListener('click', event => {
          // Get the "href" of the a.delete element
          // and call this actions in the background
          var href = event.currentTarget.getAttribute('href');
          if (!href) {
            console.log(".thumbnail-file does not have a proper delete link");
            return
          }
          var fileIcon = event.currentTarget.parentElement.parentElement;
          var request = new XMLHttpRequest();
          request.open('GET', href, true);
          request.onload = function() {
            if (this.status >= 200 && this.status < 400) {
              // Success!
              fileIcon.parentNode.removeChild(fileIcon);
            } else {
              console.log('AJAX request returned bad return code: ' + this.status);
            }
          };
          request.send();
          event.preventDefault();
        }));
  };

  $(document).ready(function(){
    document.querySelectorAll('.thumbnail-file').forEach(el => thumbnail_files_setup(el));

    $('.modal-dialog').draggable();
    $('.modal .confirm').on('click', function(ev) {
      //
      // Popdown: "submit" button of grading dialog was pressed.
      //
      var id = ev.currentTarget.dataset.id;
      var gradingBox  = document.getElementById(id);
      var pointsInput = document.querySelector('#grading-points');
      var helpBlock   = document.querySelector('#grading-points-help-block');
      var comment     = document.querySelector('#grading-comment').value;
      var points      = pointsInput.value;
      var pointsFormGroup = pointsInput.parentElement.parentElement;
      var percentage  = "";
      let hiddenCSSclass = '[::template::CSS class d-none]';

      if (points != "") {
        //
        // Number validation
        //
        if (parseFloat(points) > parseFloat(pointsInput.max) || parseFloat(points) < parseFloat(pointsInput.min)){
          if (parseFloat(points) > parseFloat(pointsInput.max)) {
            helpBlock.textContent = '[_ xowf.Value_max] ' + pointsInput.max;
          } else {
            helpBlock.textContent = '[_ xowf.Value_min] ' + pointsInput.min;
          }
          pointsFormGroup.classList.add('has-error');
          helpBlock.classList.remove(hiddenCSSclass);
          ev.preventDefault();
          return false;
        } else {
          pointsFormGroup.classList.remove('has-error');
          helpBlock.classList.add(hiddenCSSclass);
        }
        var achievable = gradingBox.dataset.achievable;
        if (achievable != "") {
          percentage = "(" + (points*100.0/achievable).toFixed(2) + "%)";
        }

      } else {
        pointsFormGroup.classList.remove('has-error');
        helpBlock.classList.add(hiddenCSSclass);
      }

      document.querySelector('#' + id + ' .points').textContent = points;
      document.querySelector('#' + id + ' .percentage').textContent = percentage;
      document.querySelector('#' + id + ' .comment').textContent = comment;
      gradingBox.dataset.achieved = points;
      gradingBox.dataset.comment = comment;
      if (comment == "") {
        document.querySelector('#' + id + ' .feedback-label').classList.add(hiddenCSSclass);
      } else {
        document.querySelector('#' + id + ' .feedback-label').classList.remove(hiddenCSSclass);
      }

      // Copy the content of the thumbnail files wrapper from the dialog
      // to the main document and register the event handler.
      let thumbnailFilesWrapper =  document.querySelector('#' + id + ' .thumbnail-files-wrapper');
      if (!thumbnailFilesWrapper) {
        thumbnailFilesWrapper = document.createElement('div');
        thumbnailFilesWrapper.className = 'thumbnail-files-wrapper';
        document.querySelector('#' + id).appendChild(thumbnailFilesWrapper);
      }
      thumbnailFilesWrapper.innerHTML = document.querySelector('#thumbnail-files-wrapper').innerHTML;
      //document.querySelector('#' + id + ' .thumbnail-files-wrapper').innerHTML =
      //    document.querySelector('#thumbnail-files-wrapper').innerHTML;
      gradingBox.querySelectorAll('.thumbnail-file').forEach(el => thumbnail_files_setup(el));

      var user_id = gradingBox.dataset.user_id;
      var examGradingBox = document.getElementById('runtime-panel-' + user_id);

      var data = new FormData();
      data.append('question_name', gradingBox.dataset.question_name);
      data.append('user_id', user_id);
      data.append('achieved', points);
      data.append('comment', comment);
      data.append('grading_scheme', examGradingBox.dataset.grading_scheme);
      data.append('achieved_points', examGradingBox.dataset.achieved_points);

      var xhttp = new XMLHttpRequest();
      xhttp.open('POST', '[set url]', true);
      xhttp.onload = function () {
        if (this.readyState == 4) {
          if (this.status == 200) {
            var text = this.responseText;
            var span = document.querySelector('#runtime-panel-' + user_id + ' .achieved-points');
            span.textContent = text;
          } else {
            console.log('sent NOT ok');
          }
        }
      };
      xhttp.send(data);

      return true;
    });

    $('.modal-dialog form').keypress(function(e){
      if(e.keyCode == 13) {
        e.preventDefault();
        return false;
      }
    });

    $('#grading-modal').on('shown.bs.modal', function (ev) {
      //
      // Popup of grading dialog.
      // Copy values from data attributes to input fields.
      //
      var gradingBox = ev.relatedTarget.parentElement;
      document.getElementById('grading-question-title').textContent = gradingBox.dataset.title;
      document.getElementById('grading-participant').textContent = gradingBox.dataset.full_name;

      var pointsInput = document.getElementById('grading-points');
      pointsInput.value = gradingBox.dataset.achieved;
      pointsInput.max = gradingBox.dataset.achievable;
      document.getElementById('grading-comment').value = gradingBox.dataset.comment;
      //document.getElementById('drop-zone').dataset.link = gradingBox.dataset.link;

      var filesUpload = document.getElementById('js-upload-files');
      filesUpload.dataset.file_name_prefix = gradingBox.dataset.question_name;
      filesUpload.dataset.url = gradingBox.dataset.link;
      filesUpload.dataset.disposition = "FileIconified";
      //console.log("... URL "    + filesUpload.dataset.url);

      var feedBackFiles = gradingBox.getElementsByClassName("thumbnail-files-wrapper")\[0\];
      //
      // For legacy composite items, there is no "thumbnail-files-wrapper"
      //
      // console.log(feedBackFiles);
      document.getElementById('thumbnail-files-wrapper').innerHTML =
          (feedBackFiles ? feedBackFiles.innerHTML : "");

      document.querySelectorAll('#grading-modal .thumbnail-file').forEach(el => thumbnail_files_setup(el));

      // Tell confirm button to which grading box it belongs
      var confirmButton = document.querySelector('#grading-modal-confirm');
      confirmButton.dataset.id = gradingBox.id;
    });
  });
}]

set uploader_link [::[$examWf package_id] make_link $examWf file-upload]
set dropZone [::xowiki::BootstrapNavbarDropzone new  -href $uploader_link  -label #xowf.Feedback_files_dnd#  -text "Text for SUBMIT label"  -file_name_prefix ""  -disposition File]
set dropZoneHTML [$dropZone asHTML]
#ns_log notice "dropZoneHTML=$dropZoneHTML"

return [::xowiki::bootstrap::modal_dialog  -id grading-modal  -title "#xowf.Grading#: <span id='grading-participant'></span>"  -subtitle "#xowf.question#: <span id='grading-question-title'></span>"  -body [subst [ns_trim -delimiter | {
              |<form class="form-horizontal" role="form" action='#' method="post">
              |  <div class="form-group">
              |    <label for="grading-points" class="control-label col-sm-2">#xowf.Points#:</label>
              |    <div class="col-sm-9">
              |      <input class="form-control" id="grading-points" placeholder="#xowf.Points#"
              |             type="number" step="0.1" min="0">
              |      <span id="grading-points-help-block" class="help-block hidden"></span>
              |    </div>
              |  </div>
              |  <div class="form-group">
              |    <label for="grading-comment" class="control-label col-sm-2">#xowf.feedback#:</label>
              |    <div class="col-sm-9">
              |      <textarea lines="2" class="form-control" id="grading-comment"
              |                placeholder="..."></textarea>
              |    </div>
              |  </div>
              |</form>
              |<div class="control-label">#xowf.Feedback_files#:</div>
              |<div id="thumbnail-files-wrapper"></div>
              |<ul class="dropZone">$dropZoneHTML</ul>
            }]]  ]
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: