[LON-CAPA-cvs] cvs: modules /damieng/graphical_editor/loncapa_daxe/web/nodes lcd_block.dart rank_foil.dart rank_foilgroup.dart rank_response.dart

damieng damieng at source.lon-capa.org
Fri Apr 17 17:42:30 EDT 2015


damieng		Fri Apr 17 21:42:30 2015 EDT

  Modified files:              
    /modules/damieng/graphical_editor/loncapa_daxe/web/nodes	
                                                            	lcd_block.dart 
                                                            	rank_foil.dart 
                                                            	rank_foilgroup.dart 
                                                            	rank_response.dart 
  Log:
  changed rankresponse implementation to avoid problems with undo/redo, switch to/from simple UI, and cut/paste several foils
  
-------------- next part --------------
Index: modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lcd_block.dart
diff -u modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lcd_block.dart:1.1 modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lcd_block.dart:1.2
--- modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lcd_block.dart:1.1	Fri Apr 17 15:35:06 2015
+++ modules/damieng/graphical_editor/loncapa_daxe/web/nodes/lcd_block.dart	Fri Apr 17 21:42:29 2015
@@ -86,12 +86,25 @@
   }
   
   /**
-   * Called when switching to simple UI.
-   * This is replaced by subclasses.
+   * Called when the button is used.
+   * This can be replaced by subclasses.
+   */
+  void switchToSimpleUI() {
+    simpleUI = true;
+    setupSimpleUI();
+    updateHTML();
+  }
+  
+  /**
+   * Called by default switchToSimpleUI() when switching to simple UI.
+   * This can be replaced by subclasses.
    */
   void setupSimpleUI() {
   }
   
+  /**
+   * Called when the button is used.
+   */
   void switchToAdvancedUI() {
     simpleUI = false;
     init();
@@ -148,9 +161,7 @@
       simple.appendText(LCDStrings.get('simple'));
       simple.onClick.listen((h.MouseEvent event) {
         if (simpleUIPossible()) {
-          simpleUI = true;
-          setupSimpleUI();
-          updateHTML();
+          switchToSimpleUI();
           page.updateAfterPathChange();
         }
       });
Index: modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foil.dart
diff -u modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foil.dart:1.1 modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foil.dart:1.2
--- modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foil.dart:1.1	Fri Apr 17 15:35:06 2015
+++ modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foil.dart	Fri Apr 17 21:42:29 2015
@@ -38,14 +38,20 @@
     List<String> possibleAttributes = ['value'];
     final RegExp numberedFoil = new RegExp("^[fF]oil[0-9]+\$");
     final RegExp positiveInteger = new RegExp("^[0-9]+\$");
-    for (DaxeAttr att in attributes)
+    for (DaxeAttr att in attributes) {
       if (!(att.name == 'value' && positiveInteger.hasMatch(att.value) ||
           (att.name == 'name' && numberedFoil.hasMatch(att.value)) ||
           (att.name == 'location' && att.value == 'random')))
         return false;
+    }
     return SimpleUIText.checkNodeContents(this);
   }
   
+  int getRank() {
+    List<RankFoil> foils = (parent as RankFoilgroup).getFoils();
+    return foils.indexOf(this) + 1;
+  }
+  
   @override
   h.Element html() {
     simpleUI = parent is RankFoilgroup && (parent as RankFoilgroup).simpleUI;
@@ -108,12 +114,7 @@
     td.append(grip);
     h.SpanElement rankNumberSpan = new h.SpanElement();
     rankNumberSpan.classes.add('rank-number');
-    int nb = 1;
-    for (DaxeNode dn=previousSibling; dn!=null; dn=dn.previousSibling) {
-      if (dn is RankFoil)
-        nb++;
-    }
-    rankNumberSpan.appendText("$nb");
+    rankNumberSpan.appendText("${getRank()}");
     td.append(rankNumberSpan);
     tr.append(td);
     td = new h.TableCellElement();
@@ -152,12 +153,15 @@
     updateHTML();
   }
   
-  @override void afterInsert() {
-    (parent as RankFoilgroup).renameFoils(null);
-    (parent as RankFoilgroup).updateHTML();
-  }
-  
-  @override void beforeRemove() {
-    (parent as RankFoilgroup).renameFoils(this);
+  @override
+  x.Node toDOMNode(x.Document domDocument) {
+    x.Node node = super.toDOMNode(domDocument);
+    if (!simpleUI || parent == null)
+      return node;
+    x.Element el = node as x.Element;
+    int nb = getRank();
+    el.setAttribute('name', "foil$nb");
+    el.setAttribute('value', "$nb");
+    return el;
   }
 }
Index: modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foilgroup.dart
diff -u modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foilgroup.dart:1.1 modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foilgroup.dart:1.2
--- modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foilgroup.dart:1.1	Fri Apr 17 15:35:06 2015
+++ modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_foilgroup.dart	Fri Apr 17 21:42:29 2015
@@ -26,13 +26,25 @@
   RankFoil draggedFoil;
   
   RankFoilgroup.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
-    initRankFoilgroup(null);
+    initRankFoilgroup(false);
   }
   
   RankFoilgroup.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
-    if ((parent as RankResponse).simpleUI)
+    if ((parent as RankResponse).simpleUI && simpleUIPossible())
       simpleUI = true;
-    initRankFoilgroup(node);
+    initRankFoilgroup(true);
+  }
+  
+  /**
+   * Returns the RankFoil children
+   */
+  List<RankFoil> getFoils() {
+    List<RankFoil> list = new List<RankFoil>();
+    for (DaxeNode dn in childNodes) {
+      if (dn is RankFoil)
+        list.add(dn);
+    }
+    return list;
   }
   
   /**
@@ -41,23 +53,46 @@
   bool simpleUIPossible() {
     if (attributes.length != 0)
       return false;
+    List<int> values = new List<int>();
+    bool aFoilHasAValue = false;
+    bool aFoilHasNoValue = false;
     for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
       if (dn is RankFoil) {
         if (!dn.simpleUIPossible())
           return false;
+        // check values are unique integers
+        String value = dn.getAttribute('value');
+        if (value != null) {
+          aFoilHasAValue = true;
+          try {
+            int iv = int.parse(value);
+            if (values.contains(iv))
+              return false;
+            values.add(iv);
+          } on FormatException catch(ex) {
+            return false;
+          }
+        } else
+          aFoilHasNoValue = true;
       } else if (dn.nodeType != DaxeNode.TEXT_NODE || dn.nodeValue.trim() != '') {
         return false;
       }
     }
+    if (aFoilHasAValue && aFoilHasNoValue)
+      return false; // reordering is not possible in this case
     return true;
   }
   
-  void initRankFoilgroup(x.Node domNode) {
+  void initRankFoilgroup(bool fromNode) {
     List<x.Element> foilRefs = doc.cfg.elementReferences('foil');
     foilRef = doc.cfg.findSubElement(ref, foilRefs);
-    if (simpleUI && domNode != null && (domNode as x.Element).getElementsByTagName('foil').length == 0) {
-      // new node from DOM in simpleUI: add a foil if there is none
-      addFirstFoil();
+    if (simpleUI && fromNode) {
+      if (getFoils().length == 0) {
+        // new node from DOM in simpleUI: add a foil if there is none
+        addFirstFoil();
+      } else {
+        prepareFoilsForSimpleUI();
+      }
     }
     restrictedInserts = ['foil'];
   }
@@ -71,10 +106,8 @@
     div.id = id;
     div.classes.add('rank-foilgroup');
     h.TableElement table = new h.TableElement();
-    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
-      if (dn is! RankFoil)
-        continue;
-      table.append(dn.html());
+    for (RankFoil foil in getFoils()) {
+      table.append(foil.html());
     }
     div.append(table);
     h.ButtonElement bAdd = new h.ButtonElement();
@@ -104,8 +137,6 @@
    */
   void addFirstFoil() {
     RankFoil foil = new RankFoil.fromRef(foilRef);
-    foil.setAttribute('name', 'foil1');
-    foil.setAttribute('value', '1');
     foil.state = 1;
     appendChild(foil);
   }
@@ -129,28 +160,59 @@
     doc.doNewEdit(new UndoableEdit.removeNode(foil));
   }
   
-  void renameFoils(RankFoil removedFoil) {
-    // rename foils automatically only when all names are [fF]oil[0-9]+
-    // and values are [0-9]+
-    final RegExp numberedFoil = new RegExp("^[fF]oil[0-9]+\$");
-    final RegExp positiveInteger = new RegExp("^[0-9]+\$");
-    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
-      String name = dn.getAttribute('name');
-      if (name != null && !numberedFoil.hasMatch(name))
-        return;
-      String value = dn.getAttribute('value');
-      if (value != null && !positiveInteger.hasMatch(value))
-        return;
+  /**
+   * Reorders the foils based on their values, and removes the name and value attributes.
+   * It is assumed that simple UI is possible.
+   */
+  void prepareFoilsForSimpleUI() {
+    List<RankFoil> foils = getFoils();
+    if (foils.length == 0)
+      return;
+    bool needOrdering = false;
+    for (int i=0; i<foils.length-1; i++) {
+      String value1 = foils[i].getAttribute('value');
+      String value2 = foils[i+1].getAttribute('value');
+      if (value1 == null || value2 == null)
+        break;
+      int cv1 = int.parse(value1);
+      int cv2 = int.parse(value2);
+      if (cv1 > cv2) {
+        needOrdering = true;
+        break;
+      }
+    }
+    UndoableEdit edit = null;
+    if (needOrdering) {
+      // remove all child nodes, order the foils in the array, reinsert them with the right name/value
+      for (DaxeNode dn in childNodes)
+        removeChild(dn);
+      foils.sort((foil1, foil2) {
+        int cv1 = int.parse(foil1.getAttribute('value'));
+        int cv2 = int.parse(foil2.getAttribute('value'));
+        return cv1.compareTo(cv2);
+      });
+      int nb = 1;
+      for (RankFoil foil in foils)
+        appendChild(foil);
     }
     int nb = 1;
-    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
-      if (dn is! RankFoil)
-        continue;
-      if (dn == removedFoil)
-        continue;
-      dn.setAttribute('name', "foil$nb");
-      dn.setAttribute('value', "$nb");
-      dn.updateValidity();
+    for (RankFoil foil in foils) {
+      if (foil.getAttribute('name') != null)
+        foil.removeAttribute('name');
+      if (foil.getAttribute('value') != null)
+        foil.removeAttribute('value');
+      nb++;
+    }
+  }
+  
+  /**
+   * Adds the name and value attributes to the foils, when switching to advanced UI
+   */
+  void addNamesAndValue() {
+    int nb = 1;
+    for (RankFoil foil in getFoils()) {
+      foil.setAttribute('name', "foil$nb");
+      foil.setAttribute('value', "$nb");
       nb++;
     }
   }
Index: modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_response.dart
diff -u modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_response.dart:1.1 modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_response.dart:1.2
--- modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_response.dart:1.1	Fri Apr 17 15:35:06 2015
+++ modules/damieng/graphical_editor/loncapa_daxe/web/nodes/rank_response.dart	Fri Apr 17 21:42:29 2015
@@ -27,11 +27,11 @@
   bool displaySimpleButton = true;
   
   RankResponse.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
-    initRankResponse(null);
+    initRankResponse(false);
   }
   
   RankResponse.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
-    initRankResponse(node);
+    initRankResponse(true);
   }
   
   /**
@@ -58,13 +58,38 @@
     return true;
   }
   
-  void initRankResponse(x.Node domNode) {
+  /**
+   * Returns the first foilgroup.
+   */
+  RankFoilgroup getFoilgroup() {
+    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
+      if (dn is RankFoilgroup)
+        return dn;
+    }
+    return null;
+  }
+  
+  /**
+   * Returns the first hintgroup.
+   */
+  Hintgroup getHintgroup() {
+    for (DaxeNode dn=firstChild; dn!= null; dn=dn.nextSibling) {
+      if (dn is Hintgroup)
+        return dn;
+    }
+    return null;
+  }
+  
+  void initRankResponse(bool fromNode) {
     simpleUI = simpleUIPossible();
-    if (simpleUI && domNode != null) {
+    if (simpleUI && fromNode) {
       // new node from DOM: add a foilgroup and hintgroup if missing
-      if ((domNode as x.Element).getElementsByTagName('foilgroup').length == 0)
+      RankFoilgroup foilgroup = getFoilgroup();
+      if (foilgroup != null)
+        foilgroup.prepareFoilsForSimpleUI();
+      else
         appendChild(newFoilgroup());
-      if ((domNode as x.Element).getElementsByTagName('hintgroup').length == 0)
+      if (getHintgroup() == null)
         appendChild(newHintgroup());
     }
     if (simpleUI)
@@ -83,9 +108,46 @@
   }
   
   @override
+  void switchToSimpleUI() {
+    // Replace the whole node, to keep the simpleUI status in the edit history
+    // (to avoid problems when names and values have to be changed automatically)
+    UndoableEdit edit = new UndoableEdit.compound(LCDStrings.get('switch_to_simple_ui'));
+    Position pos = new Position(parent, parent.offsetOf(this));
+    edit.addSubEdit(new UndoableEdit.removeNode(this));
+    setAttribute('no-simpleui', 'true');
+    RankResponse newNode = new DaxeNode.clone(this);
+    removeAttribute('no-simpleui');
+    newNode.removeAttribute('no-simpleui');
+    newNode.simpleUI = true;
+    newNode.setupSimpleUI();
+    edit.addSubEdit(new UndoableEdit.insertNode(pos, newNode));
+    doc.doNewEdit(edit);
+  }
+  
+  @override
   void setupSimpleUI() {
+    // NOTE: changes here do not need to be undoable, because a new node is created.
     setupRestrictions();
-    autoInsertFoilgroupAndHintgroup();
+    RankFoilgroup foilgroup = getFoilgroup();
+    if (foilgroup != null)
+      foilgroup.prepareFoilsForSimpleUI();
+    insertFoilgroupAndHintgroup();
+  }
+  
+  @override
+  void switchToAdvancedUI() {
+    UndoableEdit edit = new UndoableEdit.compound(LCDStrings.get('switch_to_advanced_ui'));
+    Position pos = new Position(parent, parent.offsetOf(this));
+    edit.addSubEdit(new UndoableEdit.removeNode(this));
+    RankResponse newNode = new DaxeNode.clone(this);
+    newNode.simpleUI = false;
+    newNode.restrictedInserts = null;
+    RankFoilgroup foilgroup = newNode.getFoilgroup();
+    if (foilgroup != null)
+      foilgroup.addNamesAndValue();
+    newNode.init();
+    edit.addSubEdit(new UndoableEdit.insertNode(pos, newNode));
+    doc.doNewEdit(edit);
   }
   
   @override
@@ -116,10 +178,9 @@
   }
   
   /**
-   * This inserts a foilgroup and hintgroup if missing, as if the user had done it
-   * (with undoable edits).
+   * Inserts a foilgroup and hintgroup if missing.
    */
-  void autoInsertFoilgroupAndHintgroup() {
+  void insertFoilgroupAndHintgroup() {
     bool foundFoilgroup = false;
     bool foundHintgroup = false;
     for (DaxeNode dn in childNodes) {
@@ -129,8 +190,8 @@
         foundHintgroup = true;
     }
     if (!foundFoilgroup)
-      doc.insertNode(newFoilgroup(), new Position(this, 0));
+      insertBefore(newFoilgroup(), null);
     if (!foundHintgroup)
-      doc.insertNode(newHintgroup(), new Position(this, offsetLength));
+      appendChild(newHintgroup());
   }
 }


More information about the LON-CAPA-cvs mailing list