/*
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>