File:  [LON-CAPA] / modules / damieng / graphical_editor / loncapa_daxe / web / nodes / radio_foil.dart
Revision 1.10: download - view: text, annotated - select for diffs
Wed Mar 22 16:37:44 2017 UTC (7 years, 2 months ago) by damieng
Branches: MAIN
CVS tags: HEAD
bug fix: simpleUI cannot be set when newNodeCreationUI is called (this is changing display of a new foil inserted in a simple radio response without using the add foil button)

/*
  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 a foil inside a radiobuttonresponse.
 * Uses a simplified UI if the parent (RadioFoilgroup) is.
 */
class RadioFoil extends LCDBlock {
  
  RadioFoil.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
  }
  
  RadioFoil.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
  }
  
  @override
  bool simpleUIPossible() {
    final RegExp numberedFoil = new RegExp("^((radio)?[fF]oil)?[0-9]+\$");
    for (DaxeAttr att in attributes)
      if (!(att.name == 'value' ||
          (att.name == 'name' && numberedFoil.hasMatch(att.value)) ||
          (att.name == 'location' && att.value == 'random')))
        throw new SimpleUIException('foil: ' + LCDStrings.get('attribute_problem') + att.name);
    String value = getAttribute('value'); // NOTE: value must be defined for simple UI
    if (!(value == 'true' || value == 'false' || value == 'unused'))
      throw new SimpleUIException('foil: ' + LCDStrings.get('attribute_problem') + 'value');
    return SimpleUIText.checkNodeContents(this);
  }
  
  void setupRestrictions() {
    if (restrictedInserts == null)
      restrictedInserts = SimpleUIText.possibleDescendants;
  }
  
  @override
  h.Element html() {
    simpleUI = parent is RadioFoilgroup && (parent as RadioFoilgroup).simpleUI && simpleUIPossibleNoThrow();
    if (!simpleUI)
      return super.html();
    setupRestrictions();
    
    h.TableRowElement tr = new h.TableRowElement();
    tr.id = id;
    h.TableCellElement td = new h.TableCellElement();
    h.ImageElement grip = new h.ImageElement(src:'images/grip.png', width:8, height:16);
    grip.classes.add('grip-icon');
    setupDrag(grip);
    td.append(grip);
    tr.append(td);
    td = new h.TableCellElement();
    h.RadioButtonInputElement radio = new h.RadioButtonInputElement();
    radio.name = parent.id;
    radio.title = LCDStrings.get('click_to_select');
    if (getAttribute('value') == 'true')
      radio.checked = true;
    radio.onChange.listen((h.Event event) {
      if (radio.checked)
        (parent as RadioFoilgroup).selectFoil(this);
    });
    td.append(radio);
    tr.append(td);
    td = new h.TableCellElement();
    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
      td.append(dn.html());
    }
    tr.append(td);
    td = new h.TableCellElement();
    h.ImageElement deleteImg = new h.ImageElement(src:'images/delete.png', width:16, height:16);
    deleteImg.classes.add('delete-icon');
    deleteImg.onClick.listen((h.MouseEvent e) => (parent as RadioFoilgroup).removeFoil(this));
    td.append(deleteImg);
    tr.append(td);
    return tr;
  }
  
  @override
  h.Element getHTMLContentsNode() {
    if (!simpleUI)
      return super.getHTMLContentsNode();
    return(getHTMLNode().nodes[2]);
  }
  
  @override
  void updateAttributes() {
    if (!simpleUI) {
      super.updateAttributes();
      return;
    }
    updateHTML();
  }
  
  @override
  void newNodeCreationUI(ActionFunction okfct) {
    // called when a new element is inserted
    // automatically set value=false, do not display an attribute dialog
    // (this is necessary for simple UI, not bad for advanced UI)
    setAttribute('value', 'false');
    okfct();
  }
  
  int getRank() {
    int nb = 1;
    for (DaxeNode dn=previousSibling; dn!=null; dn=dn.previousSibling) {
      if (dn is RadioFoil)
        nb++;
    }
    return nb;
  }
  
  // NOTE: ideally we should keep foil names up to date by adjusting them with all events,
  // but that is not possible with copy/paste and undo/redo
  // (we would need an API for the event, and this is not easy to add in Cursor.paste()).
  // -> getAttribute and toDOMNode overrides are a hack for validation/source/copy/paste/undo/redo/switch to advanced
  
  @override
  String getAttribute(String name) {
    if (!simpleUI || name != 'name')
      return super.getAttribute(name);
    // for validation, return a value
    RadioFoilgroup group = parent as RadioFoilgroup;
    String prefix = group.simpleFoilNamePrefix;
    int nb = getRank();
    return "$prefix$nb";
  }
  
  @override
  x.Node toDOMNode(x.Document domDocument) {
    x.Node node = super.toDOMNode(domDocument);
    replaceSingleParagraphByContents(node);
    // set name and value attributes if necessary
    if (!simpleUI || parent == null)
      return node;
    x.Element el = node as x.Element;
    RadioFoilgroup group = parent as RadioFoilgroup;
    String prefix = group.simpleFoilNamePrefix;
    int nb = getRank();
    el.setAttribute('name', "$prefix$nb");
    return el;
  }
  
  /**
   * Replace a single paragraph by its content to avoid layout issues in LON-CAPA
   * (layout will still be ugly if there is more than one paragraph).
   * This is static because it is also used in other foils.
   */
  static void replaceSingleParagraphByContents(x.Node node) {
    x.Node first = node.firstChild;
    if (first != null && first.nodeType == x.Node.TEXT_NODE &&
        first.nodeValue.trim() == '')
      first = first.nextSibling;
    if (first != null && first.nodeType == x.Node.ELEMENT_NODE &&
        first.nodeName == 'p' && !first.hasAttributes()) {
      x.Element p = first;
      x.Node after = p.nextSibling;
      if (after == null || (after.nodeType == x.Node.TEXT_NODE &&
          after.nodeValue.trim() == '' && after.nextSibling == null)) {
        x.Node next;
        for (x.Node n=p.firstChild; n!=null; n=next) {
          next = n.nextSibling;
          p.removeChild(n);
          node.insertBefore(n, p);
        }
        node.removeChild(p);
      }
    }
  }
}

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