/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.core.gui.components.form.flexible.impl.elements;
import org.apache.commons.lang.StringEscapeUtils;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.DefaultComponentRenderer;
import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement.Layout;
import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
import org.olat.core.gui.render.RenderResult;
import org.olat.core.gui.render.Renderer;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.gui.render.URLBuilder;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.StringHelper;
/**
*
* Initial date: 13.06.2014<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class MultipleSelectionRenderer extends DefaultComponentRenderer {
@Override
public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu,
Translator translator, RenderResult renderResult, String[] args) {
MultipleSelectionComponent stC = (MultipleSelectionComponent)source;
MultipleSelectionElementImpl stF = stC.getMultipleSelectionElement();
if(stF.getLayout() == Layout.vertical) {
int columns = stC.getMultipleSelectionElement().getColumns();
if(columns <= 1) {
renderVertical(sb, stC);
} else {
renderMultiColumnsVertical(sb, stC, columns);
}
} else {
renderHorizontal(sb, stC);
}
}
private StringOutput appendIdIfRequired(StringOutput sb, MultipleSelectionComponent stC) {
if(!stC.isDomReplacementWrapperRequired()) {
sb.append(" id='").append(stC.getDispatchID()).append("'");
}
return sb;
}
private void renderVertical(StringOutput sb, MultipleSelectionComponent stC) {
for(CheckboxElement check:stC.getCheckComponents()) {
sb.append("<div ");
appendIdIfRequired(sb, stC).append(" class='checkbox'>");
renderCheckbox(sb, check, stC, false);
sb.append("</div>");
}
}
private void renderMultiColumnsVertical(StringOutput sb, MultipleSelectionComponent stC, int columns) {
String columnCss;
if(columns == 2) {
columnCss = "col-sm-6";
} else if(columns == 3) {
columnCss = "col-sm-4";
} else {
columns = 4;
columnCss = "col-sm-3";
}
sb.append("<div ");
appendIdIfRequired(sb, stC).append(">");
CheckboxElement[] checks = stC.getCheckComponents();
for(int i=0; i<checks.length; ) {
sb.append("<div class='row'>");
for(int j=columns; j-->0; ) {
if(i < checks.length) {
CheckboxElement check = checks[i++];
sb.append("<div class='").append(columnCss).append("'>");
renderCheckbox(sb, check, stC, false);
sb.append("</div>");
}
}
sb.append("</div>");
}
sb.append("</div>");
}
private void renderHorizontal(StringOutput sb, MultipleSelectionComponent stC) {
sb.append("<div ");
appendIdIfRequired(sb, stC).append(" class='form-inline'>");
for(CheckboxElement check:stC.getCheckComponents()) {
renderCheckbox(sb, check, stC, true);
}
sb.append("</div>");
}
private void renderCheckbox(StringOutput sb, CheckboxElement check, MultipleSelectionComponent stC, boolean inline) {
MultipleSelectionElementImpl stF = stC.getMultipleSelectionElement();
String subStrName = "name='" + check.getGroupingName() + "'";
String key = check.getKey();
String value = check.getValue();
if(stF.isEscapeHtml()){
key = StringEscapeUtils.escapeHtml(key);
value = StringEscapeUtils.escapeHtml(value);
}
boolean selected = check.isSelected();
String formDispatchId = check.getFormDispatchId();
//read write view
String cssClass = check.getCssClass(); //optional CSS class
sb.append("<div>", !inline); // normal checkboxes need a wrapper (bootstrap) ...
sb.append("<label class='").append("checkbox-inline ", inline); // ... and inline a class on the label (bootstrap)
sb.append(cssClass, cssClass != null).append("' for=\"").append(formDispatchId).append("\">");
sb.append("<input type='checkbox' id='").append(formDispatchId).append("' ")
.append(subStrName)
.append(" value='").append(key).append("'");
if (selected) {
sb.append(" checked='checked' ");
}
if(!stC.isEnabled() || !check.isEnabled()) {
sb.append(" disabled='disabled' ");
} else if(stF.isAjaxOnly()) {
// The implementation is conservative as it send the state of the check box,
// this is especially useful if an issue of double evaluation appears.
sb.append(" onclick=\"javascript: this.checked ?")
.append(FormJSHelper.getXHRFnCallFor(stF.getRootForm(), stC.getFormDispatchId(), 1, false, false, false,
new NameValuePair("achkbox", key), new NameValuePair("checked", "true")))
.append(" : ")
.append(FormJSHelper.getXHRFnCallFor(stF.getRootForm(), stC.getFormDispatchId(), 1, false, false, false,
new NameValuePair("achkbox", key), new NameValuePair("checked", "false")))
.append(";\"");
} else {
//use the selection form dispatch id and not the one of the element!
sb.append(FormJSHelper.getRawJSFor(check.getRootForm(), check.getSelectionElementFormDispatchId(), check.getAction()));
}
sb.append(" />");
String iconLeftCSS = check.getIconLeftCSS();
if (StringHelper.containsNonWhitespace(iconLeftCSS)) {
sb.append(" <i class='").append(iconLeftCSS).append("'> </i> ");
}
if (StringHelper.containsNonWhitespace(value)) {
sb.append(" ").append(value);
} else if(inline) {
// at least something in label required for properly aligned rendering, nbsp is important for bootstrap
sb.append(" ");
}
sb.append("</label>");
sb.append("</div>", !inline); // normal radios need a wrapper (bootstrap)
if(stC.isEnabled()){
//add set dirty form only if enabled
FormJSHelper.appendFlexiFormDirtyForCheckbox(sb, stF.getRootForm(), formDispatchId);
}
}
}