File:  [LON-CAPA] / modules / damieng / graphical_editor / loncapa_daxe / web / nodes / essay_response.dart
Revision 1.9: download - view: text, annotated - select for diffs
Mon Mar 27 17:35:05 2017 UTC (7 years, 2 months ago) by damieng
Branches: MAIN
CVS tags: HEAD
avoid adding a missing textline to a response when opening a document missing it (using advanced response in that case); added more messages related to hintgroup, textline and textfield to explain why the switch to simple UI fails

/*
  This file is part of LONCAPA-Daxe.

  LONCAPA-Daxe is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  LONCAPA-Daxe is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Daxe.  If not, see <http://www.gnu.org/licenses/>.
*/

part of loncapa_daxe;

/**
 * Display for essayresponse, with a possible simple UI.
 * Jaxe display type: 'essayresponse'.
 */
class EssayResponse extends LCDBlock {
  
  static List<String> simpleUIAttributes = ['id'];
  static Map<String,Map<String,String>> paramDef = {
    'handgrade': {
      'name': 'handgrade',
      'type': 'string_yesno',
      'default': 'yes',
      'description': 'Hand Graded'
    },
    'maxcollaborators': {
      'name': 'maxcollaborators',
      'type': 'int_zeropos',
      'default': '0',
      'description': 'Maximum Number of Collaborators'
    },
    'uploadedfiletypes': {
      'name': 'uploadedfiletypes',
      'type': 'string_fileext',
      'default': '',
      'description': 'Allowed File Extensions for Uploaded Files'
    },
    'maxfilesize': {
      'name': 'maxfilesize',
      'type': 'float_pos',
      'default': '10.0',
      'description': 'Max. cumulative size (MB) for submitted files'
    }
  };
  
  EssayResponse.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
    displaySimpleButton = true;
  }
  
  EssayResponse.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
    displaySimpleButton = true;
    if (simpleUIPossibleNoThrow()) {
      bool node_simpleUI = node.getUserData('simpleUI');
      if (node_simpleUI == null || node_simpleUI)
        setupSimpleUI();
    }
  }
  
  @override
  bool simpleUIPossible() {
    for (DaxeAttr att in attributes) {
      if (!simpleUIAttributes.contains(att.name)) {
        throw new SimpleUIException('essayresponse: ' + LCDStrings.get('attribute_problem') + ' ' + att.name);
      }
    }
    int nbTextfield = 0;
    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
      if (dn is Textfield) {
        if (!dn.simpleUIPossible())
          return false;
        nbTextfield++;
      } else if (dn is LCDParameter) {
        if (!paramDef.keys.contains(dn.getAttribute('name')))
          return throw new SimpleUIException(LCDStrings.get('advanced_response_param'));
      } else if (dn.nodeType != DaxeNode.TEXT_NODE) {
        String title = doc.cfg.elementTitle(dn.ref);
        throw new SimpleUIException(LCDStrings.get('element_prevents') + ' ' + dn.nodeName +
            (title != null ? " ($title)" : ''));
      } else if (dn.nodeValue.trim() != '') {
        return false;
      }
    }
    if (nbTextfield != 1)
      throw new SimpleUIException(LCDStrings.get('one_textfield'));
    return true;
  }
  
  @override
  h.Element html() {
    if (!simpleUI)
      return super.html();
    h.DivElement div = new h.DivElement();
    div.id = "$id";
    div.classes.add('dn');
    if (!valid)
      div.classes.add('invalid');
    div.classes.add('dnblock');
    
    h.DivElement headerDiv = createHeaderDiv();
    headerDiv.classes.add('without-content-afterwards');
    div.append(headerDiv);
    
    return(div);
  }
  
  @override
  h.Element createAttributesHTML() {
    h.Element attHTML = super.createAttributesHTML();
    if (!simpleUI || attHTML == null)
      return attHTML;
    // add the fake attribute (textfield spellcheck)
    if (state == 0) {
      h.TableElement table = attHTML;
      for (DaxeNode dn in childNodes) {
        if (dn is LCDParameter || dn is Textfield) {
          h.Element he = dn.html(); // might be table or tr
          if (he is h.TableRowElement) {
            table.append(he);
          } else if (he is h.TableElement) {
            // turn the table into a tbody, for column alignment
            h.TableSectionElement tbody = table.createTBody();
            List<h.TableRowElement> rows = new List.from(he.rows);
            for (h.Element tr in rows)
              tbody.append(tr);
            table.append(tbody);
          }
        }
      }
      return table;
    } else if (state == 1) {
      h.DivElement attDiv = attHTML;
      for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
        if (dn is LCDParameter && dn.getAttribute('default') != null) {
          attDiv.append(new h.Text(" "));
          h.Element att_name = new h.SpanElement();
          att_name.attributes['class'] = 'attribute_name';
          att_name.text = dn.getAttribute('name');
          attDiv.append(att_name);
          attDiv.append(new h.Text("="));
          h.Element att_val = new h.SpanElement();
          att_val.attributes['class'] = 'attribute_value';
          att_val.text = dn.getAttribute('default');
          attDiv.append(att_val);
        } else if (dn is Textfield && dn.getAttribute('spellcheck') != null) {
          attDiv.append(new h.Text(" "));
          h.Element att_name = new h.SpanElement();
          att_name.attributes['class'] = 'attribute_name';
          att_name.text = LCDStrings.get('spellcheck');
          attDiv.append(att_name);
          attDiv.append(new h.Text("="));
          h.Element att_val = new h.SpanElement();
          att_val.attributes['class'] = 'attribute_value';
          att_val.text = dn.getAttribute('spellcheck');
          attDiv.append(att_val);
        }
      }
      return attDiv;
    } else
      return null;
  }
  
  @override
  void updateHTMLAfterChildrenChange(List<DaxeNode> changed) {
    updateHTML(); // because DaxeNode's update does not handle fake attributes
  }
  
  void setupRestrictions() {
    for (int i=0; i<attRefs.length; i++) {
      x.Element refAttr = attRefs[i];
      if (!simpleUIAttributes.contains(doc.cfg.attributeName(refAttr))) {
        attRefs.removeAt(i);
        i--;
      }
    }
    restrictedInserts = [];
  }
  
  @override
  void setupSimpleUI() {
    simpleUI = true;
    setupRestrictions();
    fixChildrenForSimpleUI();
  }
  
  @override
  void newNodeCreationUI(ActionFunction okfct) {
    setupSimpleUI();
    okfct();
  }
  
  Textfield newTextfield() {
    List<x.Element> textfieldRefs = doc.cfg.elementReferences('textfield');
    x.Element textfieldRef = doc.cfg.findSubElement(ref, textfieldRefs);
    Textfield textfield = NodeFactory.create(textfieldRef);
    textfield.state = 1;
    return textfield;
  }
  
  LCDParameter newResponseParam(Map<String,String> def) {
    List<x.Element> responseparamRefs = doc.cfg.elementReferences('responseparam');
    x.Element responseparamRef = doc.cfg.findSubElement(ref, responseparamRefs);
    LCDParameter responseparam = new LCDParameter.fromRef(responseparamRef);
    responseparam.setAttribute('name', def['name']);
    responseparam.setAttribute('type', def['type']);
    responseparam.setAttribute('default', def['default']);
    responseparam.setAttribute('description', def['description']);
    responseparam.state = 1;
    return responseparam;
  }
  
  /**
   * This inserts a textline, hintgroup if missing.
   */
  void fixChildrenForSimpleUI() {
    Textfield textfield = null;
    List foundParams = [];
    for (DaxeNode dn in childNodes) {
      if (dn.nodeType == DaxeNode.ELEMENT_NODE) {
        if (dn.nodeName == 'textfield')
          textfield = dn;
        else if (dn.nodeName == 'responseparam')
          foundParams.add(dn.getAttribute('name'));
      }
    }
    for (String paramName in paramDef.keys) {
      if (!foundParams.contains(paramName) && paramName != 'handgrade')
        insertBefore(newResponseParam(paramDef[paramName]), textfield);
    }
    if (textfield == null)
      appendChild(newTextfield());
  }
  
  /**
   * Remove parameters that are not set or set to default when serializing.
   */
  @override
  x.Node toDOMNode(x.Document domDocument) {
    x.Element response = super.toDOMNode(domDocument);
    List<x.Node> list = response.getElementsByTagName('responseparam');
    for (x.Node n in list) {
      x.Element p = n;
      Map<String,String> param = paramDef[p.getAttribute('name')];
      if (param != null && (p.getAttribute('default') == '' ||
          (p.getAttribute('type') == param['type'] &&
           p.getAttribute('default') == param['default'] &&
           p.getAttribute('description') == param['description']))) {
        if (p.nextSibling is x.Text && p.nextSibling.nodeValue == '\n')
          p.parentNode.removeChild(p.nextSibling);
        p.parentNode.removeChild(p);
      }
    }
    return(response);
  }
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>