/*
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;
/**
* Generic block element for LON-CAPA
* Attributes can be edited directly in it.
* Buttons can be used to collapse the element and the attribute fields.
* Jaxe display type: 'lcdblock'.
*/
class LCDBlock extends DNBlock {
bool simpleUI = false;
bool displaySimpleButton = false;
LCDBlock.fromRef(x.Element elementRef) : super.fromRef(elementRef) {
}
LCDBlock.fromNode(x.Node node, DaxeNode parent) : super.fromNode(node, parent) {
// replace CDATA sections by text
DaxeNode child = firstChild;
while (child != null) {
DaxeNode next = child.nextSibling;
if (child is DNCData) {
if (child.previousSibling is DNText && child.previousSibling.nodeValue == '\n')
removeChild(child.previousSibling);
if (child.nextSibling is DNText && child.nextSibling.nodeValue == '\n') {
next = child.nextSibling.nextSibling;
removeChild(child.nextSibling);
}
String text;
if (child.firstChild != null)
text = child.firstChild.nodeValue;
else
text = null;
if (text != null)
insertBefore(new DNText(text), child);
removeChild(child);
}
child = next;
}
normalize();
}
/**
* Returns true if the node can be displayed with a simple UI.
* This is replaced by subclasses.
* Subclasses can throw a SimpleUIException with a message explaining why
* it is not possible to switch to simple UI.
*/
bool simpleUIPossible() {
return false;
}
/**
* Returns true if the node can be displayed with a simple UI, false otherwise,
* without throwing any Exception. Uses simpleUIPossible() and catches possible exceptions.
*/
bool simpleUIPossibleNoThrow() {
bool possible;
try {
possible = simpleUIPossible();
} on Exception {
possible = false;
}
return possible;
}
/**
* Called when the button is used.
* This can be replaced by subclasses.
*/
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));
simpleUI = true;
LCDBlock newNode = new DaxeNode.clone(this);
simpleUI = false;
edit.addSubEdit(new UndoableEdit.insertNode(pos, newNode));
doc.doNewEdit(edit);
page.scrollToNode(newNode);
}
/**
* 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() {
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));
simpleUI = false;
LCDBlock newNode = new DaxeNode.clone(this);
simpleUI = true;
newNode.restrictedInserts = null;
newNode.init();
newNode.state = 1;
// remove any empty hintgroup
for (DaxeNode dn in newNode.childNodes) {
if (dn is Hintgroup && dn.firstChild == null)
newNode.removeChild(dn);
}
edit.addSubEdit(new UndoableEdit.insertNode(pos, newNode));
doc.doNewEdit(edit);
page.scrollToNode(newNode);
}
@override
h.DivElement createHeaderDiv() {
h.DivElement headerDiv = super.createHeaderDiv();
// add simple/advanced switch to the default block header
h.DivElement titleDiv = headerDiv.firstChild;
h.SpanElement titleSpan = titleDiv.nodes[1];
if (simpleUI) {
h.ButtonElement advanced = new h.ButtonElement();
advanced.classes.add('lcd-advanced');
advanced.appendText(LCDStrings.get('advanced'));
advanced.onClick.listen((h.MouseEvent event) {
switchToAdvancedUI();
page.updateAfterPathChange();
});
titleDiv.insertBefore(advanced, titleSpan);
} else if (displaySimpleButton) {
h.ButtonElement simple = new h.ButtonElement();
simple.classes.add('lcd-advanced');
simple.appendText(LCDStrings.get('simple'));
simple.onClick.listen((h.MouseEvent event) {
bool possible;
String message = null;
try {
possible = simpleUIPossible();
if (!possible)
message = LCDStrings.get('simpleui_not_possible'); // default message
} on SimpleUIException catch (ex) {
message = ex.message; // precise message
possible = false;
}
if (possible) {
switchToSimpleUI();
page.updateAfterPathChange();
} else
h.window.alert(message);
});
titleDiv.insertBefore(simple, titleSpan);
}
return headerDiv;
}
@override
Position firstCursorPositionInside() {
if (hasContent && !simpleUI)
return(new Position(this, 0));
else
return(null);
}
@override
Position lastCursorPositionInside() {
if (hasContent && !simpleUI)
return(new Position(this, offsetLength));
else
return(null);
}
@override
x.Node toDOMNode(x.Document domDocument) {
// do not output an empty hintgroup in simple UI
DaxeNode hintgroup = null;
DaxeNode next = null;
if (simpleUI) {
for (DaxeNode dn=firstChild; dn != null; dn=dn.nextSibling) {
if (dn is Hintgroup && dn.firstChild == null) {
hintgroup = dn;
next = dn.nextSibling;
break;
}
}
}
if (hintgroup != null)
removeChild(hintgroup);
x.Node dom = super.toDOMNode(domDocument);
if (hintgroup != null)
insertBefore(hintgroup, next);
dom.setUserData('simpleUI', simpleUI, null);
return dom;
}
@override
h.TableRowElement attributeHTML(x.Element refAttr) {
h.TableRowElement tr = super.attributeHTML(refAttr);
// add <input type=color> to help picking colors
String name = doc.cfg.attributeQualifiedName(this, ref, refAttr);
h.TableCellElement td = tr.nodes[2];
SimpleTypeControl attributeControl = attributeControls[name];
String value = attributeControl.value;
h.Element ht = td.firstChild;
if (refAttr.getAttribute('type') == 'color-or-perl') {
h.InputElement colorInput = new h.InputElement();
colorInput.type = 'color';
if (value.length == 7)
colorInput.value = '#' + value.substring(1);
colorInput.onChange.listen((h.Event e) => attributeControl.setValue(colorInput.value));
td.append(colorInput);
if (ht.firstChild is h.TextInputElement) {
h.TextInputElement input = ht.firstChild;
input.size = 8;
input.style.width = 'initial';
input.onKeyUp.listen((h.Event e) {
// update the color input if a user types the color
if (input.value.length == 7) {
colorInput.value = '#' + input.value.substring(1);
}
});
}
}
return(tr);
}
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>